mirror of
https://github.com/kunkunsh/kunkun.git
synced 2025-04-04 14:46:42 +00:00
Feature: on boarding page (#46)
* feat: add deno install page * feat: add deno install onboarding page * feat: add ffmpeg, deno, brew install help page * feat: improve on boarding page with deno install, setting, ffmpeg install * refactor: update app configuration and onboarding flow - Improved the onboarding page layout by adding a draggable region. - Introduced a new writable store `appConfigLoaded` to track the loading status of app configuration. - Updated the main application page to subscribe to `appConfigLoaded` for better handling of onboarding logic. - Minor formatting changes in the ffmpeg installation help page for consistency.
This commit is contained in:
parent
f89cf8fe6a
commit
6ce27244a5
@ -159,6 +159,61 @@ export const rawBuiltinCmds: BuiltinCmd[] = [
|
||||
},
|
||||
keywords: ["extension", "window", "troubleshooter"]
|
||||
},
|
||||
{
|
||||
name: "Help (Install Deno)",
|
||||
icon: {
|
||||
type: IconEnum.Iconify,
|
||||
value: "simple-icons:deno"
|
||||
},
|
||||
description: "",
|
||||
function: async () => {
|
||||
appState.clearSearchTerm()
|
||||
goto("/app/help/deno-install")
|
||||
},
|
||||
keywords: ["help", "deno", "install"]
|
||||
},
|
||||
{
|
||||
name: "Help (Install ffmpeg)",
|
||||
icon: {
|
||||
type: IconEnum.Iconify,
|
||||
value: "logos:ffmpeg-icon"
|
||||
},
|
||||
description: "",
|
||||
function: async () => {
|
||||
appState.clearSearchTerm()
|
||||
goto("/app/help/ffmpeg-install")
|
||||
},
|
||||
keywords: ["help", "ffmpeg", "install"]
|
||||
},
|
||||
{
|
||||
name: "Help (Install homebrew)",
|
||||
icon: {
|
||||
type: IconEnum.Iconify,
|
||||
value: "devicon:homebrew"
|
||||
},
|
||||
description: "",
|
||||
function: async () => {
|
||||
appState.clearSearchTerm()
|
||||
goto("/app/help/brew-install")
|
||||
},
|
||||
keywords: ["help", "brew", "install", "homebrew"]
|
||||
},
|
||||
{
|
||||
name: "On Boarding (Dev Only)",
|
||||
icon: {
|
||||
type: IconEnum.Iconify,
|
||||
value: "fluent-mdl2:onboarding"
|
||||
},
|
||||
description: "",
|
||||
function: async () => {
|
||||
appState.clearSearchTerm()
|
||||
goto("/app/help/onboarding")
|
||||
},
|
||||
flags: {
|
||||
dev: true,
|
||||
developer: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Extension Permission Inspector",
|
||||
icon: {
|
||||
|
@ -0,0 +1,81 @@
|
||||
<script lang="ts">
|
||||
import { cn } from "@/utils"
|
||||
import { Button } from "@kksh/svelte5"
|
||||
import { Shiki } from "@kksh/ui"
|
||||
import { confirm } from "@tauri-apps/plugin-dialog"
|
||||
import { platform } from "@tauri-apps/plugin-os"
|
||||
import { toast } from "svelte-sonner"
|
||||
import { writeText } from "tauri-plugin-clipboard-api"
|
||||
import {
|
||||
executeBashScript,
|
||||
executePowershellScript,
|
||||
fixPathEnv,
|
||||
type ChildProcess
|
||||
} from "tauri-plugin-shellx-api"
|
||||
|
||||
let {
|
||||
code,
|
||||
autoInstallable,
|
||||
alreadyInstalled,
|
||||
lang,
|
||||
class: className,
|
||||
onSuccess
|
||||
}: {
|
||||
code: string
|
||||
autoInstallable?: boolean
|
||||
alreadyInstalled?: boolean
|
||||
lang: "bash" | "powershell"
|
||||
class?: string
|
||||
onSuccess?: () => void
|
||||
} = $props()
|
||||
|
||||
function copy() {
|
||||
return writeText(code).then(() => toast.info("Copied to clipboard", { description: code }))
|
||||
}
|
||||
|
||||
async function autoInstall() {
|
||||
let cmd: ChildProcess<string> | undefined
|
||||
if (alreadyInstalled) {
|
||||
const ans = await confirm("Already installed, do you really want to run this command?")
|
||||
if (!ans) return
|
||||
}
|
||||
try {
|
||||
toast.info("Installing...")
|
||||
if (platform() === "macos") {
|
||||
cmd = await executeBashScript(code)
|
||||
} else if (platform() === "windows") {
|
||||
cmd = await executePowershellScript(code)
|
||||
} else if (platform() === "linux") {
|
||||
cmd = await executeBashScript(code)
|
||||
} else {
|
||||
return toast.error("Unsupported platform")
|
||||
}
|
||||
if (cmd) {
|
||||
if (cmd.code === 0) {
|
||||
console.log(cmd.stdout)
|
||||
toast.success("Installed successfully", { description: `Status Code: ${cmd.code}` })
|
||||
onSuccess?.()
|
||||
} else {
|
||||
console.log(cmd.stdout)
|
||||
console.log(cmd.stderr)
|
||||
toast.error("Failed to install", { description: cmd.stderr })
|
||||
}
|
||||
} else {
|
||||
toast.error("Failed to install, Unknown Error")
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error("Failed to install", {
|
||||
description: error instanceof Error ? error.message : "Unknown Error"
|
||||
})
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={cn("flex items-center gap-2", className)}>
|
||||
<Shiki class={cn("w-full overflow-x-scroll rounded-md p-1 px-2")} {code} {lang} />
|
||||
<Button class="" size="sm" variant="secondary" onclick={copy}>Copy</Button>
|
||||
<Button class="" size="sm" variant="secondary" onclick={autoInstall} disabled={!autoInstallable}>
|
||||
Auto Install
|
||||
</Button>
|
||||
</div>
|
@ -0,0 +1,53 @@
|
||||
<script lang="ts">
|
||||
import HotkeyPick from "@/components/standalone/settings/hotkey-pick.svelte"
|
||||
import { appConfig } from "@/stores"
|
||||
import { Button, Switch } from "@kksh/svelte5"
|
||||
</script>
|
||||
|
||||
<ul class="rounded-lg border">
|
||||
<li>
|
||||
<span>Launch at Login</span>
|
||||
<Switch bind:checked={$appConfig.launchAtLogin} />
|
||||
</li>
|
||||
<li class="">
|
||||
<span>Hotkey</span>
|
||||
<HotkeyPick />
|
||||
</li>
|
||||
<li>
|
||||
<span>Menu Bar Icon</span>
|
||||
<Switch bind:checked={$appConfig.showInTray} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Hide On Blur</span>
|
||||
<Switch bind:checked={$appConfig.hideOnBlur} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Extension Auto Upgrade</span>
|
||||
<Switch bind:checked={$appConfig.extensionAutoUpgrade} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Dev Extension HMR</span>
|
||||
<Switch bind:checked={$appConfig.hmr} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Join Beta Updates</span>
|
||||
<Switch bind:checked={$appConfig.joinBetaProgram} />
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span>Developer Mode</span>
|
||||
<Switch bind:checked={$appConfig.developerMode} />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<style scoped>
|
||||
li {
|
||||
@apply flex items-center justify-between border-b px-3 py-3;
|
||||
}
|
||||
ul li:last-child {
|
||||
@apply border-b-0;
|
||||
}
|
||||
li > span {
|
||||
@apply text-sm;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,59 @@
|
||||
<script lang="ts">
|
||||
import InstallCodeBlock from "@/components/common/install-code-block.svelte"
|
||||
import Icon from "@iconify/svelte"
|
||||
import { IconEnum } from "@kksh/api/models"
|
||||
import { Button, Tabs } from "@kksh/svelte5"
|
||||
import { TauriLink } from "@kksh/ui"
|
||||
import { platform } from "@tauri-apps/plugin-os"
|
||||
import { onMount } from "svelte"
|
||||
import { toast } from "svelte-sonner"
|
||||
import { whereIsCommand } from "tauri-plugin-shellx-api"
|
||||
|
||||
let brewPath = $state("")
|
||||
let _platform = $state(platform())
|
||||
|
||||
onMount(async () => {
|
||||
brewPath = await whereIsCommand("brew")
|
||||
})
|
||||
|
||||
function onInstallSuccess() {}
|
||||
let alreadyInstalled = $derived(brewPath != "")
|
||||
</script>
|
||||
|
||||
<h1 class="font-mono text-2xl font-bold">Install Homebrew</h1>
|
||||
<TauriLink
|
||||
href="/app/help/brew-install"
|
||||
icon={IconEnum.Iconify}
|
||||
iconValue="devicon:homebrew"
|
||||
class="flex items-center"
|
||||
>
|
||||
<span class="text-lg">Homebrew Website</span>
|
||||
<Icon icon="devicon:homebrew" class="h-6 w-6" />
|
||||
</TauriLink>
|
||||
{#if _platform !== "macos"}
|
||||
<p class="font-mono text-sm text-red-500">Homebrew is only available on MacOS.</p>
|
||||
{/if}
|
||||
{#if alreadyInstalled}
|
||||
<div class="flex items-center gap-2 font-mono text-sm">
|
||||
<span>✅</span>
|
||||
<span>Homebrew is already installed at </span>
|
||||
<pre class="text-sm">{brewPath}</pre>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex items-center gap-2 font-mono text-sm">
|
||||
<span>❌</span>
|
||||
<span>Homebrew is not installed</span>
|
||||
</div>
|
||||
{/if}
|
||||
<p class="font-mono text-sm">
|
||||
Some extensions require Homebrew to enable advanced features. Homebrew is optional but
|
||||
recommended.
|
||||
</p>
|
||||
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code={`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`}
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
autoInstallable={!alreadyInstalled}
|
||||
/>
|
@ -0,0 +1,161 @@
|
||||
<script lang="ts">
|
||||
import InstallCodeBlock from "@/components/common/install-code-block.svelte"
|
||||
import { goBackOnEscape } from "@/utils/key"
|
||||
import { goBack } from "@/utils/route"
|
||||
import { Button, Tabs } from "@kksh/svelte5"
|
||||
import { platform } from "@tauri-apps/plugin-os"
|
||||
import { onMount } from "svelte"
|
||||
import ArrowLeft from "svelte-radix/ArrowLeft.svelte"
|
||||
import { toast } from "svelte-sonner"
|
||||
import { whereIsCommand } from "tauri-plugin-shellx-api"
|
||||
|
||||
let brewPath = $state("")
|
||||
let denoPath = $state("")
|
||||
let cargoPath = $state("")
|
||||
let scoopPath = $state("")
|
||||
let chocoPath = $state("")
|
||||
let wingetPath = $state("")
|
||||
let _platform = $state(platform())
|
||||
|
||||
onMount(async () => {
|
||||
;[denoPath, brewPath, cargoPath, scoopPath, chocoPath, wingetPath] = await Promise.all([
|
||||
whereIsCommand("deno"),
|
||||
whereIsCommand("brew"),
|
||||
whereIsCommand("cargo"),
|
||||
whereIsCommand("scoop"),
|
||||
whereIsCommand("choco"),
|
||||
whereIsCommand("winget")
|
||||
])
|
||||
})
|
||||
|
||||
async function onInstallSuccess() {
|
||||
denoPath = await whereIsCommand("deno")
|
||||
console.log("new denoPath", denoPath)
|
||||
if (!denoPath) {
|
||||
toast.warning("Installation succeeds, but deno is not found in your PATH", {
|
||||
description: "Please verify by yourself, and restart this app"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let alreadyInstalled = $derived(denoPath != "")
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={goBackOnEscape} />
|
||||
<Button variant="outline" size="icon" onclick={goBack} class="absolute left-2 top-2">
|
||||
<ArrowLeft class="size-4" />
|
||||
</Button>
|
||||
<h1 class="font-mono text-2xl font-bold">Install Deno</h1>
|
||||
<p class="font-mono text-sm">
|
||||
Some extensions require Deno to enable advanced features. Deno provides a secure, sandboxed
|
||||
runtime environment for executing extension code safely. It is optional but recommended.
|
||||
</p>
|
||||
<p class="font-mono text-sm">Choose any installation method below.</p>
|
||||
<p class="font-mono text-sm">
|
||||
If you are unsure, you can use <strong class="text-lg">Auto Install</strong>.
|
||||
</p>
|
||||
<p class="font-mono text-sm text-red-400">
|
||||
After installation, ensure the `deno` command is accessible from your system's PATH.
|
||||
</p>
|
||||
{#if _platform === "macos" || _platform === "linux"}
|
||||
<p class="font-mono text-sm text-red-400">
|
||||
Installation with <span class="font-bold text-green-500">curl</span> command likely requires manual
|
||||
configuration. So auto install is disabled. Please copy the command and run it in a terminal.
|
||||
</p>
|
||||
{/if}
|
||||
{#if denoPath}
|
||||
<div class="flex items-center gap-2">
|
||||
<span>✅</span>
|
||||
<span>Deno is already installed at </span>
|
||||
<pre class="text-sm">{denoPath}</pre>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex items-center gap-2">
|
||||
<span>❌</span>
|
||||
<span>Deno is not installed</span>
|
||||
</div>
|
||||
{/if}
|
||||
<Tabs.Root value={_platform} class="mt-2 w-full">
|
||||
<div class="flex w-full justify-center">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="windows">Windows</Tabs.Trigger>
|
||||
<Tabs.Trigger value="macos">MacOS</Tabs.Trigger>
|
||||
<Tabs.Trigger value="linux">Linux</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
<Tabs.Content value="macos" class="space-y-2">
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code="curl -fsSL https://deno.land/install.sh | sh"
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
{#if brewPath}
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code="brew install deno"
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
autoInstallable={true}
|
||||
/>
|
||||
{/if}
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="windows" class="space-y-2">
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code="irm https://deno.land/install.ps1 | iex"
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
{#if scoopPath}
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code="scoop install deno"
|
||||
lang="bash"
|
||||
autoInstallable={true}
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
{/if}
|
||||
{#if chocoPath}
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code="choco install deno"
|
||||
lang="bash"
|
||||
autoInstallable={true}
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
{/if}
|
||||
{#if wingetPath}
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code="winget install deno"
|
||||
lang="bash"
|
||||
autoInstallable={true}
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
{/if}
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="linux" class="space-y-2">
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code="curl -fsSL https://deno.land/install.sh | sh"
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
{#if cargoPath}
|
||||
<p class="mt-2 font-mono text-sm">
|
||||
Seeing this message means `cargo` is detected and you are a programmer. `cargo install` allows
|
||||
you to install `deno` from rust source code. But rust compiles super slow (a few minutes), so
|
||||
auto install is disabled. If you really want to use this method, please copy the command and run
|
||||
it in a terminal.
|
||||
</p>
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
class="mt-2"
|
||||
code="cargo install deno --locked"
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
{/if}
|
@ -0,0 +1,121 @@
|
||||
<script lang="ts">
|
||||
import InstallCodeBlock from "@/components/common/install-code-block.svelte"
|
||||
import Icon from "@iconify/svelte"
|
||||
import { IconEnum } from "@kksh/api/models"
|
||||
import { Button, Tabs } from "@kksh/svelte5"
|
||||
import { TauriLink } from "@kksh/ui"
|
||||
import { platform } from "@tauri-apps/plugin-os"
|
||||
import { onMount } from "svelte"
|
||||
import { toast } from "svelte-sonner"
|
||||
import { whereIsCommand } from "tauri-plugin-shellx-api"
|
||||
|
||||
let brewPath = $state("")
|
||||
let chocoPath = $state("")
|
||||
let ffmpegPath = $state("")
|
||||
let aptPath = $state("")
|
||||
let _platform = $state(platform())
|
||||
|
||||
onMount(async () => {
|
||||
;[ffmpegPath, brewPath, chocoPath, aptPath] = await Promise.all([
|
||||
whereIsCommand("ffmpeg"),
|
||||
whereIsCommand("brew"),
|
||||
whereIsCommand("choco"),
|
||||
whereIsCommand("apt")
|
||||
])
|
||||
})
|
||||
|
||||
function onInstallSuccess() {}
|
||||
let alreadyInstalled = $derived(ffmpegPath != "")
|
||||
|
||||
let command = {
|
||||
macos: "brew install ffmpeg",
|
||||
windows: "choco install ffmpeg",
|
||||
linux: `sudo apt update && sudo apt upgrade && sudo apt install ffmpeg`
|
||||
}
|
||||
</script>
|
||||
|
||||
<h1 class="font-mono text-2xl font-bold">Install ffmpeg</h1>
|
||||
<p class="font-mono text-sm">
|
||||
Some extensions require ffmpeg to enable advanced features. ffmpeg is optional but recommended.
|
||||
</p>
|
||||
<p class="font-mono text-sm">
|
||||
For example, the YouTube video downloader extension requires `ffmpeg` to merge audio and video;
|
||||
`ffmpeg` is also used in video processing extensions.
|
||||
</p>
|
||||
{#if alreadyInstalled}
|
||||
<div class="flex items-center gap-2 font-mono text-sm">
|
||||
<span>✅</span>
|
||||
<span>ffmpeg is already installed at </span>
|
||||
<pre class="text-sm">{ffmpegPath}</pre>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex items-center gap-2 font-mono text-sm">
|
||||
<span>❌</span>
|
||||
<span>ffmpeg is not installed</span>
|
||||
</div>
|
||||
{/if}
|
||||
<TauriLink
|
||||
href="/app/help/ffmpeg-install"
|
||||
icon={IconEnum.Iconify}
|
||||
iconValue="logos:ffmpeg-icon"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<span class="font-mono text-lg font-bold">ffmpeg Website</span>
|
||||
<Icon icon="logos:ffmpeg-icon" class="h-6 w-6" />
|
||||
</TauriLink>
|
||||
<p class="font-mono text-sm">
|
||||
You can install ffmpeg from the official website, but it's much easier if you use a package
|
||||
manager of your platform.
|
||||
</p>
|
||||
<Tabs.Root value={_platform} class="mt-2 w-full">
|
||||
<div class="flex w-full justify-center">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="windows">Windows</Tabs.Trigger>
|
||||
<Tabs.Trigger value="macos">MacOS</Tabs.Trigger>
|
||||
<Tabs.Trigger value="linux">Linux</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
<Tabs.Content value="macos" class="space-y-2">
|
||||
{#if !brewPath}
|
||||
<p class="font-mono text-sm text-red-400">
|
||||
Homebrew is not installed. Please install Homebrew first.
|
||||
</p>
|
||||
{/if}
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code={command.macos}
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
autoInstallable={true}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="windows" class="space-y-2">
|
||||
{#if !chocoPath}
|
||||
<p class="font-mono text-sm text-red-400">
|
||||
Chocolatey is not installed. Please install Chocolatey first.
|
||||
</p>
|
||||
{/if}
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code={command.windows}
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="linux" class="space-y-2">
|
||||
{#if !aptPath}
|
||||
<p class="font-mono text-sm text-red-400">
|
||||
`apt` is not installed. Please install `apt` first.
|
||||
</p>
|
||||
<p class="font-mono text-sm text-red-400">
|
||||
If you are on a different distro, I believe you can figure it out as a Linux user.
|
||||
</p>
|
||||
{/if}
|
||||
<InstallCodeBlock
|
||||
onSuccess={onInstallSuccess}
|
||||
code={command.linux}
|
||||
lang="bash"
|
||||
{alreadyInstalled}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
@ -5,7 +5,7 @@ import { PersistedAppConfig, type AppConfig } from "@kksh/types"
|
||||
import { debug, error } from "@tauri-apps/plugin-log"
|
||||
import * as os from "@tauri-apps/plugin-os"
|
||||
import { load } from "@tauri-apps/plugin-store"
|
||||
import { get } from "svelte/store"
|
||||
import { get, writable } from "svelte/store"
|
||||
import * as v from "valibot"
|
||||
|
||||
export const defaultAppConfig: AppConfig = {
|
||||
@ -29,12 +29,15 @@ export const defaultAppConfig: AppConfig = {
|
||||
developerMode: false
|
||||
}
|
||||
|
||||
export const appConfigLoaded = writable(false)
|
||||
|
||||
interface AppConfigAPI {
|
||||
init: () => Promise<void>
|
||||
get: () => AppConfig
|
||||
setTheme: (theme: ThemeConfig) => void
|
||||
setDevExtensionPath: (devExtensionPath: string | null) => void
|
||||
setTriggerHotkey: (triggerHotkey: string[]) => void
|
||||
setOnBoarded: (onBoarded: boolean) => void
|
||||
}
|
||||
|
||||
function createAppConfig(): WithSyncStore<AppConfig> & AppConfigAPI {
|
||||
@ -61,7 +64,7 @@ function createAppConfig(): WithSyncStore<AppConfig> & AppConfigAPI {
|
||||
await persistStore.clear()
|
||||
await persistStore.set("config", v.parse(PersistedAppConfig, defaultAppConfig))
|
||||
}
|
||||
|
||||
appConfigLoaded.set(true)
|
||||
store.subscribe(async (config) => {
|
||||
console.log("Saving app config", config)
|
||||
await persistStore.set("config", config)
|
||||
@ -80,6 +83,9 @@ function createAppConfig(): WithSyncStore<AppConfig> & AppConfigAPI {
|
||||
setTriggerHotkey: (triggerHotkey: string[]) => {
|
||||
store.update((config) => ({ ...config, triggerHotkey }))
|
||||
},
|
||||
setOnBoarded: (onBoarded: boolean) => {
|
||||
store.update((config) => ({ ...config, onBoarded }))
|
||||
},
|
||||
init
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@
|
||||
|
||||
<svelte:window on:keydown={globalKeyDownHandler} />
|
||||
<ViewTransition />
|
||||
<Toaster richColors />
|
||||
<Toaster richColors closeButton />
|
||||
<AppContext {appConfig} {appState}>
|
||||
{@render children()}
|
||||
</AppContext>
|
||||
|
@ -3,7 +3,14 @@
|
||||
import { commandLaunchers } from "@/cmds"
|
||||
import { builtinCmds } from "@/cmds/builtin"
|
||||
import { systemCommands } from "@/cmds/system"
|
||||
import { appConfig, appState, devStoreExts, installedStoreExts, quickLinks } from "@/stores"
|
||||
import {
|
||||
appConfig,
|
||||
appConfigLoaded,
|
||||
appState,
|
||||
devStoreExts,
|
||||
installedStoreExts,
|
||||
quickLinks
|
||||
} from "@/stores"
|
||||
import { cmdQueries } from "@/stores/cmdQuery"
|
||||
import { isKeyboardEventFromInputElement } from "@/utils/dom"
|
||||
import Icon from "@iconify/svelte"
|
||||
@ -22,6 +29,7 @@
|
||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"
|
||||
import { getCurrentWindow, Window } from "@tauri-apps/api/window"
|
||||
import { exit } from "@tauri-apps/plugin-process"
|
||||
import { goto } from "$app/navigation"
|
||||
import { ArrowBigUpIcon, CircleXIcon, EllipsisVerticalIcon, RefreshCcwIcon } from "lucide-svelte"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
@ -36,12 +44,23 @@
|
||||
onMount(() => {
|
||||
Promise.all([Window.getByLabel("splashscreen"), getCurrentWindow()]).then(
|
||||
([splashscreenWin, mainWin]) => {
|
||||
mainWin.show()
|
||||
if (splashscreenWin) {
|
||||
splashscreenWin.close()
|
||||
}
|
||||
|
||||
mainWin.show()
|
||||
}
|
||||
)
|
||||
|
||||
appConfigLoaded.subscribe((loaded) => {
|
||||
// wait for appConfig store to be loaded, it's async and saved to disk when changed, so we use another store appConfigLoaded
|
||||
// to keep track of the loading status
|
||||
if (loaded) {
|
||||
if (!appConfig.get().onBoarded) {
|
||||
goto("/app/help/onboarding")
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
16
apps/desktop/src/routes/app/help/brew-install/+page.svelte
Normal file
16
apps/desktop/src/routes/app/help/brew-install/+page.svelte
Normal file
@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import BrewInstall from "@/components/standalone/help/brew-install.svelte"
|
||||
import { goBackOnEscape } from "@/utils/key"
|
||||
import { goBack } from "@/utils/route"
|
||||
import { Button } from "@kksh/svelte5"
|
||||
import ArrowLeft from "svelte-radix/ArrowLeft.svelte"
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={goBackOnEscape} />
|
||||
<Button variant="outline" size="icon" onclick={goBack} class="absolute left-2 top-2">
|
||||
<ArrowLeft class="size-4" />
|
||||
</Button>
|
||||
|
||||
<main class="container pt-12">
|
||||
<BrewInstall />
|
||||
</main>
|
15
apps/desktop/src/routes/app/help/deno-install/+page.svelte
Normal file
15
apps/desktop/src/routes/app/help/deno-install/+page.svelte
Normal file
@ -0,0 +1,15 @@
|
||||
<script lang="ts">
|
||||
import DenoInstall from "@/components/standalone/help/deno-install.svelte"
|
||||
import { goBackOnEscape } from "@/utils/key"
|
||||
import { goBack } from "@/utils/route"
|
||||
import { Button } from "@kksh/svelte5"
|
||||
import ArrowLeft from "svelte-radix/ArrowLeft.svelte"
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={goBackOnEscape} />
|
||||
<Button variant="outline" size="icon" onclick={goBack} class="absolute left-2 top-2">
|
||||
<ArrowLeft class="size-4" />
|
||||
</Button>
|
||||
<main class="container pt-12">
|
||||
<DenoInstall />
|
||||
</main>
|
15
apps/desktop/src/routes/app/help/ffmpeg-install/+page.svelte
Normal file
15
apps/desktop/src/routes/app/help/ffmpeg-install/+page.svelte
Normal file
@ -0,0 +1,15 @@
|
||||
<script lang="ts">
|
||||
import FFmpegInstall from "@/components/standalone/help/ffmpeg-install.svelte"
|
||||
import { goBackOnEscape } from "@/utils/key"
|
||||
import { goBack } from "@/utils/route"
|
||||
import { Button } from "@kksh/svelte5"
|
||||
import ArrowLeft from "svelte-radix/ArrowLeft.svelte"
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={goBackOnEscape} />
|
||||
<Button variant="outline" size="icon" onclick={goBack} class="absolute left-2 top-2">
|
||||
<ArrowLeft class="size-4" />
|
||||
</Button>
|
||||
<main class="container pt-12">
|
||||
<FFmpegInstall />
|
||||
</main>
|
64
apps/desktop/src/routes/app/help/onboarding/+page.svelte
Normal file
64
apps/desktop/src/routes/app/help/onboarding/+page.svelte
Normal file
@ -0,0 +1,64 @@
|
||||
<script lang="ts">
|
||||
import GeneralSettings from "@/components/standalone/general-settings.svelte"
|
||||
import DenoInstall from "@/components/standalone/help/deno-install.svelte"
|
||||
import FFmpegInstall from "@/components/standalone/help/ffmpeg-install.svelte"
|
||||
import { appConfig } from "@/stores/appConfig"
|
||||
import { Button } from "@kksh/svelte5"
|
||||
import { goto } from "$app/navigation"
|
||||
import { ArrowRightIcon } from "lucide-svelte"
|
||||
import { onMount } from "svelte"
|
||||
import { fade } from "svelte/transition"
|
||||
import { whereIsCommand } from "tauri-plugin-shellx-api"
|
||||
import { Step } from "./steps"
|
||||
|
||||
let step = $state(0)
|
||||
let denoPath = $state("")
|
||||
let ffmpegPath = $state("")
|
||||
|
||||
onMount(async () => {
|
||||
denoPath = await whereIsCommand("deno")
|
||||
ffmpegPath = await whereIsCommand("ffmpeg")
|
||||
})
|
||||
|
||||
function nextStep() {
|
||||
step++
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (step === Step.DenoInstall) {
|
||||
if (denoPath) {
|
||||
step++
|
||||
}
|
||||
} else if (step === Step.FFmpegInstall) {
|
||||
if (ffmpegPath) {
|
||||
step++
|
||||
}
|
||||
} else if (step > Step.FFmpegInstall) {
|
||||
appConfig.setOnBoarded(true)
|
||||
goto("/app")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<main class="container">
|
||||
<div class="left-0 top-0 h-10 w-full" data-tauri-drag-region></div>
|
||||
{#if step === Step.Welcome}
|
||||
<h1 class="text-3xl font-bold">Welcome to Kunkun</h1>
|
||||
<p>
|
||||
This is a on boarding page to help you set up Kunkun with some basic settings and optional
|
||||
dependencies.
|
||||
</p>
|
||||
<div>Click <strong>Next</strong> to continue</div>
|
||||
{:else if step === Step.GeneralSettings}
|
||||
<h1 class="text-2xl font-bold">General Settings</h1>
|
||||
<small> You can change these settings later in the settings page. </small>
|
||||
<GeneralSettings />
|
||||
{:else if step === Step.DenoInstall}
|
||||
<DenoInstall />
|
||||
{:else if step === Step.FFmpegInstall}
|
||||
<FFmpegInstall />
|
||||
{/if}
|
||||
</main>
|
||||
<Button class="fixed bottom-4 right-4" variant="outline" size="icon" onclick={nextStep}>
|
||||
<ArrowRightIcon />
|
||||
</Button>
|
6
apps/desktop/src/routes/app/help/onboarding/steps.ts
Normal file
6
apps/desktop/src/routes/app/help/onboarding/steps.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum Step {
|
||||
Welcome = 0,
|
||||
GeneralSettings = 1,
|
||||
DenoInstall = 2,
|
||||
FFmpegInstall = 3
|
||||
}
|
@ -1,70 +1,7 @@
|
||||
<script lang="ts">
|
||||
import HotkeyInputPopover from "@/components/common/HotkeyInputPopover.svelte"
|
||||
import HotkeyPick from "@/components/standalone/settings/hotkey-pick.svelte"
|
||||
import { appConfig } from "@/stores"
|
||||
import { Button, Switch } from "@kksh/svelte5"
|
||||
import { Shiki } from "@kksh/ui"
|
||||
import { dev } from "$app/environment"
|
||||
import { onMount, type Snippet } from "svelte"
|
||||
import GeneralSettings from "@/components/standalone/general-settings.svelte"
|
||||
</script>
|
||||
|
||||
<main class="container flex flex-col space-y-2">
|
||||
<!-- <h3 class="text-mg mb-2 ml-3 font-bold">App Updates</h3> -->
|
||||
<ul class="rounded-lg border">
|
||||
<li>
|
||||
<span>Launch at Login</span>
|
||||
<Switch bind:checked={$appConfig.launchAtLogin} />
|
||||
</li>
|
||||
<li class="">
|
||||
<span>Hotkey</span>
|
||||
<!-- <HotkeyInput bind:keys={$appConfig.triggerHotkey} /> -->
|
||||
<!-- <HotkeyInputPopover class="" /> -->
|
||||
<HotkeyPick />
|
||||
</li>
|
||||
<li>
|
||||
<span>Menu Bar Icon</span>
|
||||
<Switch bind:checked={$appConfig.showInTray} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Hide On Blur</span>
|
||||
<Switch bind:checked={$appConfig.hideOnBlur} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Extension Auto Upgrade</span>
|
||||
<Switch bind:checked={$appConfig.extensionAutoUpgrade} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Dev Extension HMR</span>
|
||||
<Switch bind:checked={$appConfig.hmr} />
|
||||
</li>
|
||||
<li>
|
||||
<span>Join Beta Updates</span>
|
||||
<Switch bind:checked={$appConfig.joinBetaProgram} />
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span>Developer Mode</span>
|
||||
<Switch bind:checked={$appConfig.developerMode} />
|
||||
</li>
|
||||
|
||||
<!-- <li>
|
||||
<span>Language</span>
|
||||
<Switch bind:checked={$appConfig} />
|
||||
</li> -->
|
||||
</ul>
|
||||
<!-- {#if dev}
|
||||
<Shiki class="w-full overflow-x-auto" lang="json" code={JSON.stringify($appConfig, null, 2)} />
|
||||
{/if} -->
|
||||
<GeneralSettings />
|
||||
</main>
|
||||
|
||||
<style scoped>
|
||||
li {
|
||||
@apply flex items-center justify-between border-b px-3 py-3;
|
||||
}
|
||||
ul li:last-child {
|
||||
@apply border-b-0;
|
||||
}
|
||||
li > span {
|
||||
@apply text-sm;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
## Permission Table
|
||||
|
||||
<table>
|
||||
@ -6,6 +7,7 @@
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
|
@ -60,6 +60,7 @@
|
||||
"@internationalized/date": "^3.6.0",
|
||||
"@std/semver": "npm:@jsr/std__semver@^1.0.3",
|
||||
"gsap": "^3.12.5",
|
||||
"shiki-magic-move": "^0.5.2",
|
||||
"svelte-markdown": "^0.4.1"
|
||||
}
|
||||
}
|
||||
|
@ -2,49 +2,39 @@
|
||||
<!-- https://shiki.style/guide/bundles#fine-grained-bundle -->
|
||||
<script lang="ts">
|
||||
import { cn } from "@kksh/ui/utils"
|
||||
import { mode } from "mode-watcher"
|
||||
import { createHighlighterCore, type HighlighterCore } from "shiki/core"
|
||||
import { createOnigurumaEngine } from "shiki/engine/oniguruma"
|
||||
import { onMount } from "svelte"
|
||||
import { getSingletonHighlighter } from "shiki"
|
||||
import { ShikiMagicMove } from "shiki-magic-move/svelte"
|
||||
import "shiki-magic-move/dist/style.css"
|
||||
|
||||
const {
|
||||
code,
|
||||
lang,
|
||||
theme,
|
||||
lineNumbers,
|
||||
class: className
|
||||
}: {
|
||||
code: string
|
||||
lang: "json" | "typescript"
|
||||
lang: "json" | "typescript" | "bash" | "powershell"
|
||||
theme?: "vitesse-dark" | "vitesse-light"
|
||||
lineNumbers?: boolean
|
||||
class?: string
|
||||
} = $props()
|
||||
let html = $state("")
|
||||
let highlighter: HighlighterCore
|
||||
|
||||
function refresh() {
|
||||
html = highlighter.codeToHtml(code, {
|
||||
lang,
|
||||
theme: theme ?? ($mode === "dark" ? "vitesse-dark" : "vitesse-light")
|
||||
})
|
||||
}
|
||||
onMount(async () => {
|
||||
highlighter = await createHighlighterCore({
|
||||
themes: [import("shiki/themes/vitesse-dark.mjs"), import("shiki/themes/vitesse-light.mjs")],
|
||||
langs: [import("shiki/langs/json.mjs"), import("shiki/langs/typescript.mjs")],
|
||||
engine: createOnigurumaEngine(import("shiki/wasm"))
|
||||
})
|
||||
refresh()
|
||||
const highlighter2 = getSingletonHighlighter({
|
||||
themes: ["vitesse-dark", "vitesse-light"],
|
||||
langs: ["typescript", "bash", "powershell", "json"]
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
code // keep this here to watch for code changes
|
||||
highlighter
|
||||
if (highlighter) {
|
||||
refresh()
|
||||
}
|
||||
})
|
||||
let code2 = $state(`const hello = 'world'`)
|
||||
</script>
|
||||
|
||||
<div class={cn("", className)}>
|
||||
{@html html}
|
||||
</div>
|
||||
{#await highlighter2 then highlighter}
|
||||
<ShikiMagicMove
|
||||
class={cn("", className)}
|
||||
{lang}
|
||||
theme={theme ?? "vitesse-dark"}
|
||||
{highlighter}
|
||||
{code}
|
||||
options={{ duration: 800, stagger: 0.3, lineNumbers: lineNumbers ?? false }}
|
||||
/>
|
||||
{/await}
|
||||
|
74
pnpm-lock.yaml
generated
74
pnpm-lock.yaml
generated
@ -1091,6 +1091,9 @@ importers:
|
||||
gsap:
|
||||
specifier: ^3.12.5
|
||||
version: 3.12.5
|
||||
shiki-magic-move:
|
||||
specifier: ^0.5.2
|
||||
version: 0.5.2(react@18.3.1)(shiki@1.24.2)(svelte@5.16.2)(vue@3.5.13(typescript@5.7.2))
|
||||
svelte-markdown:
|
||||
specifier: ^0.4.1
|
||||
version: 0.4.1(svelte@5.16.2)
|
||||
@ -6059,6 +6062,9 @@ packages:
|
||||
didyoumean@1.2.2:
|
||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||
|
||||
diff-match-patch-es@0.1.1:
|
||||
resolution: {integrity: sha512-+wE0HYKRuRdfsnpEFh41kTd0GlYFSDQacz2bQ4dwMDvYGtofqtYdJ6Gl4ZOgUPqPi7v8LSqMY0+/OedmIPHBZw==}
|
||||
|
||||
diff@7.0.0:
|
||||
resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
@ -9175,6 +9181,26 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
shiki-magic-move@0.5.2:
|
||||
resolution: {integrity: sha512-Y5EHPD+IPiUUFFMEKu6RE8wELsKp8CYgf420Z+EXVljOvyBakiR9rjt/1Cm0VcSr9rkyQANw6fTE1PqcNOnAGA==}
|
||||
peerDependencies:
|
||||
react: ^18.2.0 || ^19.0.0
|
||||
shiki: ^1.1.6
|
||||
solid-js: ^1.9.1
|
||||
svelte: ^5.0.0-0
|
||||
vue: ^3.4.0
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
shiki:
|
||||
optional: true
|
||||
solid-js:
|
||||
optional: true
|
||||
svelte:
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
|
||||
shiki@1.24.2:
|
||||
resolution: {integrity: sha512-TR1fi6mkRrzW+SKT5G6uKuc32Dj2EEa7Kj0k8kGqiBINb+C1TiflVOiT9ta6GqOJtC4fraxO5SLUaKBcSY38Fg==}
|
||||
|
||||
@ -15653,6 +15679,13 @@ snapshots:
|
||||
'@vue/shared': 3.5.13
|
||||
vue: 3.5.13(typescript@5.6.3)
|
||||
|
||||
'@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.2))':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
vue: 3.5.13(typescript@5.7.2)
|
||||
optional: true
|
||||
|
||||
'@vue/shared@3.5.13': {}
|
||||
|
||||
'@vueuse/core@10.11.1(vue@3.5.13(typescript@5.6.3))':
|
||||
@ -16830,6 +16863,8 @@ snapshots:
|
||||
|
||||
didyoumean@1.2.2: {}
|
||||
|
||||
diff-match-patch-es@0.1.1: {}
|
||||
|
||||
diff@7.0.0: {}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
@ -17157,8 +17192,8 @@ snapshots:
|
||||
'@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
|
||||
eslint-plugin-react: 7.37.2(eslint@8.57.1)
|
||||
eslint-plugin-react-hooks: 5.0.0(eslint@8.57.1)
|
||||
@ -17186,37 +17221,37 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.3.7
|
||||
enhanced-resolve: 5.17.1
|
||||
eslint: 8.57.1
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.8.1
|
||||
is-bun-module: 1.2.1
|
||||
is-glob: 4.0.3
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- '@typescript-eslint/parser'
|
||||
- eslint-import-resolver-node
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.8
|
||||
@ -17227,7 +17262,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
@ -20464,6 +20499,16 @@ snapshots:
|
||||
interpret: 1.4.0
|
||||
rechoir: 0.6.2
|
||||
|
||||
shiki-magic-move@0.5.2(react@18.3.1)(shiki@1.24.2)(svelte@5.16.2)(vue@3.5.13(typescript@5.7.2)):
|
||||
dependencies:
|
||||
diff-match-patch-es: 0.1.1
|
||||
ohash: 1.1.4
|
||||
optionalDependencies:
|
||||
react: 18.3.1
|
||||
shiki: 1.24.2
|
||||
svelte: 5.16.2
|
||||
vue: 3.5.13(typescript@5.7.2)
|
||||
|
||||
shiki@1.24.2:
|
||||
dependencies:
|
||||
'@shikijs/core': 1.24.2
|
||||
@ -22130,6 +22175,17 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.6.3
|
||||
|
||||
vue@3.5.13(typescript@5.7.2):
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.13
|
||||
'@vue/compiler-sfc': 3.5.13
|
||||
'@vue/runtime-dom': 3.5.13
|
||||
'@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.2))
|
||||
'@vue/shared': 3.5.13
|
||||
optionalDependencies:
|
||||
typescript: 5.7.2
|
||||
optional: true
|
||||
|
||||
walkdir@0.4.1: {}
|
||||
|
||||
wcwidth@1.0.1:
|
||||
|
Loading…
x
Reference in New Issue
Block a user