Files
BetterSEQTA-Plus/src/interface/pages/settings/shortcuts.svelte
T
StroepWafel fa41542ec6 Update shortcuts.svelte - use "DisplayName" for displayname
made code use "DisplayName" in object for display name instead of object name, includes fallback in case the object is missing displayname
2025-05-08 21:32:59 +09:30

162 lines
5.5 KiB
Svelte

<script lang="ts">
import MotionDiv from '@/interface/components/MotionDiv.svelte';
import { settingsState } from "@/seqta/utils/listeners/SettingsState.ts"
import Switch from "@/interface/components/Switch.svelte"
import { onMount } from 'svelte';
import Shortcuts from "@/seqta/content/links.json"
let isLoaded = $state(false);
onMount(async () => {
// Wait for settingsState to be initialized
await new Promise<void>((resolve) => {
const checkState = () => {
if ($settingsState?.shortcuts) {
isLoaded = true;
resolve();
} else {
setTimeout(checkState, 100);
}
};
checkState();
});
});
const switchChange = (shortcut: any) => {
const value = $settingsState.shortcuts.find(s => s.name === shortcut);
if (value) {
value.enabled = !value.enabled;
settingsState.shortcuts = settingsState.shortcuts;
} else {
settingsState.shortcuts = [...settingsState.shortcuts, { name: shortcut, enabled: true }];
}
}
let isFormVisible = $state(false);
let newTitle = $state("");
let newURL = $state("");
const toggleForm = () => {
isFormVisible = !isFormVisible;
};
const formatUrl = (inputUrl: string) => {
const protocolRegex = /^(http:\/\/|https:\/\/|ftp:\/\/)/;
return protocolRegex.test(inputUrl) ? inputUrl : `https://${inputUrl}`;
};
const isValidTitle = (title: string) => title.trim() !== "";
const isValidURL = (url: string) => {
const pattern = new RegExp("^(https?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\-]+)*(?::\\d+)?(/[\\w\\-./]*)*$", "i");
return pattern.test(url);
};
const addNewCustomShortcut = () => {
if (isValidTitle(newTitle) && isValidURL(newURL)) {
const newShortcut = { name: newTitle.trim(), url: formatUrl(newURL).trim(), icon: newTitle[0] };
settingsState.customshortcuts = [...settingsState.customshortcuts, newShortcut];
newTitle = "";
newURL = "";
isFormVisible = false;
} else {
alert("Please enter a valid title and URL.");
}
};
const deleteCustomShortcut = (index: number) => {
settingsState.customshortcuts = settingsState.customshortcuts.filter((_, i) => i !== index);
};
</script>
<div class="flex flex-col pt-4 divide-y divide-zinc-100 dark:divide-zinc-700">
{#if isLoaded}
<div>
<MotionDiv
initial={{ opacity: 0, height: 0 }}
animate={isFormVisible ? { opacity: 1, height: 'auto' } : { opacity: 0, height: 0 }}
exit={{ opacity: 0, height: 0 }}
transition={{
type: 'spring',
config: { stiffness: 400, damping: 25 }
}}
>
{#if isFormVisible}
<div class="flex flex-col items-center">
<MotionDiv
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0, duration: 0.2 }}
class="w-full"
>
<input
class="p-2 w-full rounded-lg border-0 transition placeholder-zinc-300 bg-zinc-100 dark:bg-zinc-700 focus:bg-zinc-200/50 dark:focus:bg-zinc-600"
type="text"
placeholder="Shortcut Name"
bind:value={newTitle}
/>
</MotionDiv>
<MotionDiv
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.05, duration: 0.2 }}
class="w-full"
>
<input
class="p-2 my-2 w-full rounded-lg border-0 transition placeholder-zinc-300 bg-zinc-100 dark:bg-zinc-700 focus:bg-zinc-200/50 dark:focus:bg-zinc-600"
type="text"
placeholder="URL eg. https://google.com"
bind:value={newURL}
/>
</MotionDiv>
</div>
{/if}
</MotionDiv>
<MotionDiv
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<button
class="w-full px-4 py-2 mb-4 text-[13px] dark:text-white transition rounded-xl bg-zinc-200 dark:bg-zinc-700/50"
onclick={isFormVisible ? addNewCustomShortcut : toggleForm}
>
{#if isFormVisible}
Add
{:else}
Add Custom Shortcut
{/if}
</button>
</MotionDiv>
</div>
{#each Object.entries(Shortcuts) as shortcut}
<div class="flex justify-between items-center px-4 py-3">
<div class="pr-4">
<!-- Use DisplayName if it exists, otherwise use the key (shortcut[0]) as a fallback -->
<h2 class="text-sm">{shortcut[1].DisplayName || shortcut[0]}</h2>
</div>
<Switch state={$settingsState.shortcuts.find(s => s.name === shortcut[0])?.enabled ?? false} onChange={() => switchChange(shortcut[0])} />
</div>
{/each}
<!-- Custom Shortcuts Section -->
{#each $settingsState.customshortcuts as shortcut, index}
<div class="flex justify-between items-center px-4 py-3">
{shortcut.name}
<button aria-label="Delete Shortcut" onclick={() => deleteCustomShortcut(index)}>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width={1.5} stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/each}
{:else}
<div class="p-4 text-center">
Loading shortcuts...
</div>
{/if}
</div>