mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-20 17:02:53 -04:00
download pane
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button } from "@storyteller/ui-button";
|
||||
import {
|
||||
AppPreferencesPayload,
|
||||
CustomDirectory,
|
||||
DownloadDirectoryReveal,
|
||||
GetAppPreferences,
|
||||
PreferenceName,
|
||||
SystemDirectory,
|
||||
UpdateAppPreferences,
|
||||
} from "@storyteller/tauri-api";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
import { Label } from "@storyteller/ui-label";
|
||||
import { Switch } from "@storyteller/ui-switch";
|
||||
import { FolderIcon, RotateCcwIcon, SearchIcon } from "lucide-react";
|
||||
import {
|
||||
getAskLocationBeforeDownload,
|
||||
setAskLocationBeforeDownload,
|
||||
} from "@storyteller/api";
|
||||
|
||||
export const DownloadsSettingsPane = () => {
|
||||
const [preferences, setPreferences] = useState<
|
||||
AppPreferencesPayload | undefined
|
||||
>(undefined);
|
||||
|
||||
const [askLocationBeforeDownload, setAskLocationBeforeDownloadState] =
|
||||
useState<boolean>(() => getAskLocationBeforeDownload());
|
||||
|
||||
const toggleAskLocationBeforeDownload = (enabled: boolean) => {
|
||||
setAskLocationBeforeDownload(enabled);
|
||||
setAskLocationBeforeDownloadState(enabled);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const prefs = await GetAppPreferences();
|
||||
console.log("prefs", prefs);
|
||||
setPreferences(prefs.preferences);
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
// NB: This might be a complex type.
|
||||
const outerDownloadObject = preferences?.preferred_download_directory || {};
|
||||
const downloadDirectory =
|
||||
"custom" in outerDownloadObject
|
||||
? (outerDownloadObject.custom as string)
|
||||
: "";
|
||||
const currentDownloadLabel =
|
||||
"system" in outerDownloadObject
|
||||
? "System Download Directory"
|
||||
: downloadDirectory;
|
||||
|
||||
const reloadPreferences = async () => {
|
||||
const prefs = await GetAppPreferences();
|
||||
console.log("prefs", prefs);
|
||||
setPreferences(prefs.preferences);
|
||||
};
|
||||
|
||||
const openDirectoryPicker = async () => {
|
||||
let directory = await open({
|
||||
multiple: false,
|
||||
directory: true,
|
||||
defaultPath: downloadDirectory || undefined,
|
||||
});
|
||||
if (directory === null) {
|
||||
return; // User dismissed the dialog choice
|
||||
}
|
||||
await UpdateAppPreferences({
|
||||
preference: PreferenceName.PreferredDownloadDirectory,
|
||||
value: {
|
||||
custom: directory,
|
||||
} as CustomDirectory,
|
||||
});
|
||||
await reloadPreferences();
|
||||
};
|
||||
|
||||
const clearDirectory = async () => {
|
||||
await UpdateAppPreferences({
|
||||
preference: PreferenceName.PreferredDownloadDirectory,
|
||||
value: {
|
||||
system: "downloads",
|
||||
} as SystemDirectory,
|
||||
});
|
||||
await reloadPreferences();
|
||||
};
|
||||
|
||||
const showDirectory = async () => {
|
||||
await DownloadDirectoryReveal();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4 text-base-fg">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="download-path">Default Download Directory</Label>
|
||||
<p className="opacity-80">
|
||||
This is where downloads are placed after downloading. The current path
|
||||
is:
|
||||
</p>
|
||||
<div className="py-1.5 px-2 rounded-md mt-1 bg-ui-panel border border-ui-panel-border text-base-fg">
|
||||
<pre>{currentDownloadLabel}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="primary" onClick={openDirectoryPicker}>
|
||||
<FolderIcon />
|
||||
Choose Directory
|
||||
</Button>
|
||||
<Button variant="destructive" onClick={clearDirectory}>
|
||||
<RotateCcwIcon />
|
||||
Use Default
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={showDirectory}>
|
||||
<SearchIcon />
|
||||
Show Directory
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 pt-3">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<Label htmlFor="ask-location-before-download">
|
||||
Ask location before download
|
||||
</Label>
|
||||
<p className="text-xs opacity-70">
|
||||
When on, a system file picker appears every time you download from
|
||||
the lightbox or anywhere in the app, letting you choose the save
|
||||
location for that file. When off, downloads go straight to the
|
||||
default download directory above.
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
enabled={askLocationBeforeDownload}
|
||||
setEnabled={toggleAskLocationBeforeDownload}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,150 +1,23 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button } from "@storyteller/ui-button";
|
||||
import {
|
||||
AppPreferencesPayload,
|
||||
CustomDirectory,
|
||||
GetAppPreferences,
|
||||
SystemDirectory,
|
||||
} from "@storyteller/tauri-api";
|
||||
import { PreferenceName, UpdateAppPreferences } from "@storyteller/tauri-api";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
import { Label } from "@storyteller/ui-label";
|
||||
import { Switch } from "@storyteller/ui-switch";
|
||||
import { DownloadDirectoryReveal } from "@storyteller/tauri-api";
|
||||
import { FolderIcon, RotateCcwIcon, SearchIcon } from "lucide-react";
|
||||
import { useEnterToGenerateStore } from "@storyteller/ui-promptbox";
|
||||
import { useModelPickerStyleStore } from "@storyteller/ui-popover";
|
||||
import { useKeybindsStore } from "@storyteller/keybinds";
|
||||
import {
|
||||
getAskLocationBeforeDownload,
|
||||
setAskLocationBeforeDownload,
|
||||
} from "@storyteller/api";
|
||||
|
||||
interface MiscSettingsPaneProps {}
|
||||
|
||||
export const MiscSettingsPane = (args: MiscSettingsPaneProps) => {
|
||||
const [preferences, setPreferences] = useState<
|
||||
AppPreferencesPayload | undefined
|
||||
>(undefined);
|
||||
|
||||
const enterToGenerate = useEnterToGenerateStore((s) => s.enabled);
|
||||
const setEnterToGenerate = useEnterToGenerateStore((s) => s.setEnabled);
|
||||
|
||||
const [askLocationBeforeDownload, setAskLocationBeforeDownloadState] =
|
||||
useState<boolean>(() => getAskLocationBeforeDownload());
|
||||
|
||||
const modelPickerStyle = useModelPickerStyleStore((s) => s.style);
|
||||
const setModelPickerStyle = useModelPickerStyleStore((s) => s.setStyle);
|
||||
|
||||
const cheatsheetSticky = useKeybindsStore((s) => s.cheatsheetSticky);
|
||||
const setCheatsheetSticky = useKeybindsStore((s) => s.setCheatsheetSticky);
|
||||
|
||||
const toggleAskLocationBeforeDownload = (enabled: boolean) => {
|
||||
setAskLocationBeforeDownload(enabled);
|
||||
setAskLocationBeforeDownloadState(enabled);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const prefs = await GetAppPreferences();
|
||||
console.log("prefs", prefs);
|
||||
setPreferences(prefs.preferences);
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
// NB: This might be a complex type.
|
||||
const outerDownloadObject = preferences?.preferred_download_directory || {};
|
||||
const downloadDirectory =
|
||||
"custom" in outerDownloadObject
|
||||
? (outerDownloadObject.custom as string)
|
||||
: "";
|
||||
const currentDownloadLabel =
|
||||
"system" in outerDownloadObject
|
||||
? "System Download Directory"
|
||||
: downloadDirectory;
|
||||
|
||||
const reloadPreferences = async () => {
|
||||
const prefs = await GetAppPreferences();
|
||||
console.log("prefs", prefs);
|
||||
setPreferences(prefs.preferences);
|
||||
};
|
||||
|
||||
const openDirectoryPicker = async () => {
|
||||
let directory = await open({
|
||||
multiple: false,
|
||||
directory: true,
|
||||
defaultPath: downloadDirectory || undefined,
|
||||
});
|
||||
if (directory === null) {
|
||||
return; // User dismissed the dialog choice
|
||||
}
|
||||
await UpdateAppPreferences({
|
||||
preference: PreferenceName.PreferredDownloadDirectory,
|
||||
value: {
|
||||
custom: directory,
|
||||
} as CustomDirectory,
|
||||
});
|
||||
await reloadPreferences();
|
||||
};
|
||||
|
||||
const clearDirectory = async () => {
|
||||
await UpdateAppPreferences({
|
||||
preference: PreferenceName.PreferredDownloadDirectory,
|
||||
value: {
|
||||
system: "downloads",
|
||||
} as SystemDirectory,
|
||||
});
|
||||
await reloadPreferences();
|
||||
};
|
||||
|
||||
const showDirectory = async () => {
|
||||
await DownloadDirectoryReveal();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4 text-base-fg">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="download-path">Default Download Directory</Label>
|
||||
<p className="opacity-80">
|
||||
This is where downloads are placed after downloading. The current path
|
||||
is:
|
||||
</p>
|
||||
<div className="py-1.5 px-2 rounded-md mt-1 bg-ui-panel border border-ui-panel-border text-base-fg">
|
||||
<pre>{currentDownloadLabel}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="primary" onClick={openDirectoryPicker}>
|
||||
<FolderIcon />
|
||||
Choose Directory
|
||||
</Button>
|
||||
<Button variant="destructive" onClick={clearDirectory}>
|
||||
<RotateCcwIcon />
|
||||
Use Default
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={showDirectory}>
|
||||
<SearchIcon />
|
||||
Show Directory
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 pt-3">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<Label htmlFor="ask-location-before-download">
|
||||
Ask location before download
|
||||
</Label>
|
||||
<p className="text-xs opacity-70">
|
||||
When on, a system file picker appears every time you download from
|
||||
the lightbox or anywhere in the app, letting you choose the save
|
||||
location for that file. When off, downloads go straight to the
|
||||
default download directory above.
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
enabled={askLocationBeforeDownload}
|
||||
setEnabled={toggleAskLocationBeforeDownload}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 pt-3">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<Label htmlFor="enter-to-generate">Enter to generate</Label>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Modal } from "@storyteller/ui-modal";
|
||||
import { useEffect, useState } from "react";
|
||||
import { CreditCardIcon, FlaskConicalIcon, InfoIcon, KeyboardIcon, PaletteIcon, SettingsIcon, UserIcon, Volume2Icon } from "lucide-react";
|
||||
import { CreditCardIcon, DownloadIcon, FlaskConicalIcon, InfoIcon, KeyboardIcon, PaletteIcon, SettingsIcon, UserIcon, Volume2Icon } from "lucide-react";
|
||||
import { DynamicIcon } from "@storyteller/icons";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { KeybindsSettings } from "@storyteller/keybinds";
|
||||
import { MiscSettingsPane } from "./panes/MiscSettingsPane";
|
||||
import { DownloadsSettingsPane } from "./panes/DownloadsSettingsPane";
|
||||
import { AudioSettingsPane } from "./panes/AudioSettingsPane";
|
||||
import { AccountSettingsPane } from "./panes/AccountSettings/AccountSettingsPane";
|
||||
import { AboutSettingsPane } from "./panes/AboutSettingsPane";
|
||||
@@ -27,6 +28,7 @@ interface SettingsModalProps {
|
||||
|
||||
type SettingsSection =
|
||||
| "general"
|
||||
| "downloads"
|
||||
| "appearance"
|
||||
| "keybinds"
|
||||
| "accounts"
|
||||
@@ -66,6 +68,7 @@ export const SettingsModal = ({
|
||||
|
||||
const sections = [
|
||||
{ id: "general" as const, label: "General", icon: SettingsIcon },
|
||||
{ id: "downloads" as const, label: "Downloads", icon: DownloadIcon },
|
||||
|
||||
{ id: "accounts" as const, label: "Accounts", icon: UserIcon },
|
||||
{ id: "billing" as const, label: "Plan & Credits", icon: CreditCardIcon },
|
||||
@@ -96,6 +99,8 @@ export const SettingsModal = ({
|
||||
return <AudioSettingsPane />;
|
||||
case "general":
|
||||
return <MiscSettingsPane />;
|
||||
case "downloads":
|
||||
return <DownloadsSettingsPane />;
|
||||
case "accounts":
|
||||
return (
|
||||
<AccountSettingsPane
|
||||
|
||||
Reference in New Issue
Block a user