feat: add extensionsInstallDir var to +layout.ts, exposed to all pages

All pages won't need to get the path asynchronously, it's kind of like a global constant
This commit is contained in:
Huakun Shen 2024-11-04 17:59:32 -05:00
parent 54b7cc58c4
commit f64e562034
No known key found for this signature in database
GPG Key ID: 967DBC3ECBD63A70
9 changed files with 38 additions and 19 deletions

View File

@ -5,6 +5,7 @@ passing everything through props will be very complicated and hard to maintain.
<script lang="ts"> <script lang="ts">
import { systemCommands } from "@/cmds/system" import { systemCommands } from "@/cmds/system"
import { devStoreExts, installedStoreExts } from "@/stores" import { devStoreExts, installedStoreExts } from "@/stores"
import { getActiveElementNodeName } from "@/utils/dom"
import type { ExtPackageJsonExtra } from "@kksh/api/models" import type { ExtPackageJsonExtra } from "@kksh/api/models"
import { isExtPathInDev } from "@kksh/extension/utils" import { isExtPathInDev } from "@kksh/extension/utils"
import { Command } from "@kksh/svelte5" import { Command } from "@kksh/svelte5"
@ -35,8 +36,20 @@ passing everything through props will be very complicated and hard to maintain.
appState: Writable<AppState> appState: Writable<AppState>
builtinCmds: BuiltinCmd[] builtinCmds: BuiltinCmd[]
} = $props() } = $props()
function onKeyDown(event: KeyboardEvent) {
if (event.key === "Escape") {
if (getActiveElementNodeName() === "INPUT") {
;(event.target as HTMLInputElement).value = ""
if ((event.target as HTMLInputElement | undefined)?.id === "main-command-input") {
$appState.searchTerm = ""
}
}
}
}
</script> </script>
<svelte:window on:keydown={onKeyDown} />
<Command.Root <Command.Root
class={cn("rounded-lg border shadow-md", className)} class={cn("rounded-lg border shadow-md", className)}
bind:value={$appState.highlightedCmd} bind:value={$appState.highlightedCmd}
@ -44,6 +57,7 @@ passing everything through props will be very complicated and hard to maintain.
> >
<CustomCommandInput <CustomCommandInput
autofocus autofocus
id="main-command-input"
placeholder="Type a command or search..." placeholder="Type a command or search..."
bind:value={$appState.searchTerm} bind:value={$appState.searchTerm}
/> />
@ -51,7 +65,7 @@ passing everything through props will be very complicated and hard to maintain.
<Command.Empty data-tauri-drag-region>No results found.</Command.Empty> <Command.Empty data-tauri-drag-region>No results found.</Command.Empty>
<BuiltinCmds {builtinCmds} /> <BuiltinCmds {builtinCmds} />
<SystemCmds {systemCommands} /> <SystemCmds {systemCommands} />
{#if $appConfig.extensionPath && $devStoreExts.length > 0} {#if $appConfig.extensionsInstallDir && $devStoreExts.length > 0}
<ExtCmdsGroup <ExtCmdsGroup
extensions={$devStoreExts} extensions={$devStoreExts}
heading="Dev Extensions" heading="Dev Extensions"
@ -60,7 +74,7 @@ passing everything through props will be very complicated and hard to maintain.
hmr={$appConfig.hmr} hmr={$appConfig.hmr}
/> />
{/if} {/if}
{#if $appConfig.extensionPath && $installedStoreExts.length > 0} {#if $appConfig.extensionsInstallDir && $installedStoreExts.length > 0}
<ExtCmdsGroup <ExtCmdsGroup
extensions={$installedStoreExts} extensions={$installedStoreExts}
heading="Extensions" heading="Extensions"

View File

@ -21,7 +21,7 @@ export const defaultAppConfig: AppConfig = {
launchAtLogin: true, launchAtLogin: true,
showInTray: true, showInTray: true,
devExtensionPath: null, devExtensionPath: null,
extensionPath: undefined, extensionsInstallDir: undefined,
hmr: false, hmr: false,
hideOnBlur: true, hideOnBlur: true,
extensionAutoUpgrade: true, extensionAutoUpgrade: true,
@ -40,20 +40,17 @@ function createAppConfig(): Writable<AppConfig> & AppConfigAPI {
async function init() { async function init() {
debug("Initializing app config") debug("Initializing app config")
const appDataDir = await path.appDataDir()
// const appConfigPath = await path.join(appDataDir, "appConfig.json")
// debug(`appConfigPath: ${appConfigPath}`)
const persistStore = await load("kk-config.json", { autoSave: true }) const persistStore = await load("kk-config.json", { autoSave: true })
const loadedConfig = await persistStore.get("config") const loadedConfig = await persistStore.get("config")
const parseRes = v.safeParse(PersistedAppConfig, loadedConfig) const parseRes = v.safeParse(PersistedAppConfig, loadedConfig)
if (parseRes.success) { if (parseRes.success) {
console.log("Parse Persisted App Config Success", parseRes.output) console.log("Parse Persisted App Config Success", parseRes.output)
const extensionPath = await path.join(appDataDir, "extensions") const extensionsInstallDir = await getExtensionsFolder()
update((config) => ({ update((config) => ({
...config, ...config,
...parseRes.output, ...parseRes.output,
isInitialized: true, isInitialized: true,
extensionPath, extensionsInstallDir,
platform: os.platform() platform: os.platform()
})) }))
} else { } else {

View File

@ -25,7 +25,7 @@ function createExtensionsStore(): Writable<ExtPackageJsonExtra[]> & {
} }
function getExtensionsFromStore() { function getExtensionsFromStore() {
const extContainerPath = get(appConfig).extensionPath const extContainerPath = get(appConfig).extensionsInstallDir
if (!extContainerPath) return [] if (!extContainerPath) return []
return get(extensions).filter((ext) => !extAPI.isExtPathInDev(extContainerPath, ext.extPath)) return get(extensions).filter((ext) => !extAPI.isExtPathInDev(extContainerPath, ext.extPath))
} }
@ -83,7 +83,7 @@ function createExtensionsStore(): Writable<ExtPackageJsonExtra[]> & {
identifier: string, identifier: string,
tarballUrl: string tarballUrl: string
): Promise<ExtPackageJsonExtra> { ): Promise<ExtPackageJsonExtra> {
const extsDir = get(appConfig).extensionPath const extsDir = get(appConfig).extensionsInstallDir
if (!extsDir) throw new Error("Extension path not set") if (!extsDir) throw new Error("Extension path not set")
return uninstallStoreExtensionByIdentifier(identifier).then(() => return uninstallStoreExtensionByIdentifier(identifier).then(() =>
installFromTarballUrl(tarballUrl, extsDir) installFromTarballUrl(tarballUrl, extsDir)
@ -109,7 +109,7 @@ export const extensions = createExtensionsStore()
export const installedStoreExts: Readable<ExtPackageJsonExtra[]> = derived( export const installedStoreExts: Readable<ExtPackageJsonExtra[]> = derived(
extensions, extensions,
($extensionsStore) => { ($extensionsStore) => {
const extContainerPath = get(appConfig).extensionPath const extContainerPath = get(appConfig).extensionsInstallDir
if (!extContainerPath) return [] if (!extContainerPath) return []
return $extensionsStore.filter((ext) => !extAPI.isExtPathInDev(extContainerPath, ext.extPath)) return $extensionsStore.filter((ext) => !extAPI.isExtPathInDev(extContainerPath, ext.extPath))
} }
@ -117,7 +117,7 @@ export const installedStoreExts: Readable<ExtPackageJsonExtra[]> = derived(
export const devStoreExts: Readable<ExtPackageJsonExtra[]> = derived( export const devStoreExts: Readable<ExtPackageJsonExtra[]> = derived(
extensions, extensions,
($extensionsStore) => { ($extensionsStore) => {
const extContainerPath = get(appConfig).extensionPath const extContainerPath = get(appConfig).extensionsInstallDir
if (!extContainerPath) return [] if (!extContainerPath) return []
return $extensionsStore.filter((ext) => extAPI.isExtPathInDev(extContainerPath, ext.extPath)) return $extensionsStore.filter((ext) => extAPI.isExtPathInDev(extContainerPath, ext.extPath))
} }

View File

@ -0,0 +1,3 @@
export function getActiveElementNodeName(): string | undefined {
return document.activeElement?.nodeName
}

View File

@ -1,5 +1,12 @@
import { getExtensionsFolder } from "@/constants"
import type { LayoutLoad } from "./$types"
// Tauri doesn't have a Node.js server to do proper SSR // Tauri doesn't have a Node.js server to do proper SSR
// so we will use adapter-static to prerender the app (SSG) // so we will use adapter-static to prerender the app (SSG)
// See: https://v2.tauri.app/start/frontend/sveltekit/ for more info // See: https://v2.tauri.app/start/frontend/sveltekit/ for more info
export const prerender = true export const prerender = true
export const ssr = false export const ssr = false
export const load: LayoutLoad = async () => {
return { extsInstallDir: await getExtensionsFolder() }
}

View File

@ -65,7 +65,6 @@
</script> </script>
<svelte:window on:keydown={goBackOnEscapeClearSearchTerm} /> <svelte:window on:keydown={goBackOnEscapeClearSearchTerm} />
{#snippet leftSlot()} {#snippet leftSlot()}
<Button <Button
variant="outline" variant="outline"

View File

@ -36,9 +36,9 @@
onMount(() => { onMount(() => {
showBtn = { showBtn = {
install: !installedExt, install: !$installedExt,
upgrade: isUpgradable, upgrade: isUpgradable,
uninstall: !!installedExt uninstall: !!$installedExt
} }
}) })
@ -140,7 +140,6 @@
</script> </script>
<svelte:window on:keydown={handleKeydown} /> <svelte:window on:keydown={handleKeydown} />
<Button <Button
variant="outline" variant="outline"
size="icon" size="icon"

View File

@ -23,6 +23,6 @@ export type PersistedAppConfig = v.InferOutput<typeof PersistedAppConfig>
export type AppConfig = PersistedAppConfig & { export type AppConfig = PersistedAppConfig & {
isInitialized: boolean isInitialized: boolean
extensionPath?: string extensionsInstallDir?: string
platform: Platform platform: Platform
} }

View File

@ -125,8 +125,8 @@
data-flip-id={`${Constants.CLASSNAMES.EXT_LOGO}-${ext.identifier}`} data-flip-id={`${Constants.CLASSNAMES.EXT_LOGO}-${ext.identifier}`}
/> />
</span> </span>
<div> <div class="w-full">
<span class="flex items-center"> <span class="flex items-center w-full" use:autoAnimate>
<strong class="ext-name text-xl">{manifest?.name}</strong> <strong class="ext-name text-xl">{manifest?.name}</strong>
{#if isInstalled} {#if isInstalled}
<CircleCheckBigIcon class="ml-2 inline text-green-400" /> <CircleCheckBigIcon class="ml-2 inline text-green-400" />