feat: Proper theme support
This commit is contained in:
@@ -147,39 +147,51 @@
|
|||||||
<div class="flex flex-wrap gap-2 m-2">
|
<div class="flex flex-wrap gap-2 m-2">
|
||||||
{#if isClipboardAvailable()}
|
{#if isClipboardAvailable()}
|
||||||
<button class="action-btn w-full" on:click={onCopyClipboard}
|
<button class="action-btn w-full" on:click={onCopyClipboard}
|
||||||
><i class="far fa-copy" /> Copy Image to clipboard
|
><i class="far fa-copy mr-2" /> Copy Image to clipboard
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
<button class="action-btn flex-auto" on:click={onDownloadPNG}>
|
<button class="action-btn flex-auto" on:click={onDownloadPNG}>
|
||||||
<i class="fas fa-download" /> PNG
|
<i class="fas fa-download mr-2" /> PNG
|
||||||
</button>
|
</button>
|
||||||
<button class="action-btn flex-auto" on:click={onDownloadSVG}>
|
<button class="action-btn flex-auto" on:click={onDownloadSVG}>
|
||||||
<i class="fas fa-download" /> SVG
|
<i class="fas fa-download mr-2" /> SVG
|
||||||
</button>
|
</button>
|
||||||
<button class="action-btn flex-auto">
|
<button class="action-btn flex-auto">
|
||||||
<a target="_blank" href={iUrl}><i class="fas fa-external-link-alt" /> PNG</a>
|
<a target="_blank" href={iUrl}><i class="fas fa-external-link-alt mr-2" /> PNG</a>
|
||||||
</button>
|
</button>
|
||||||
<button class="action-btn flex-auto">
|
<button class="action-btn flex-auto">
|
||||||
<a target="_blank" href={svgUrl}><i class="fas fa-external-link-alt" /> SVG</a>
|
<a target="_blank" href={svgUrl}><i class="fas fa-external-link-alt mr-2" /> SVG</a>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
PNG size
|
PNG size
|
||||||
<input type="radio" value="auto" id="autosize" bind:group={imagemodeselected} />
|
<label for="autosize">
|
||||||
<label for="autosize">Auto</label>
|
<input type="radio" value="auto" id="autosize" bind:group={imagemodeselected} /> Auto
|
||||||
<input type="radio" value="width" id="width-active" bind:group={imagemodeselected} />
|
</label>
|
||||||
<label for="width">Width</label>
|
|
||||||
<input type="radio" value="height" id="height-active" bind:group={imagemodeselected} />
|
<label for="width">
|
||||||
<label for="height">Height</label>
|
<input type="radio" value="width" id="width" bind:group={imagemodeselected} /> Width
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="height">
|
||||||
|
<input type="radio" value="height" id="height" bind:group={imagemodeselected} /> Height
|
||||||
|
</label>
|
||||||
|
|
||||||
{#if imagemodeselected !== 'auto'}
|
{#if imagemodeselected !== 'auto'}
|
||||||
<input id="height" type="number" min="3" max="10000" bind:value={userimagesize} />
|
<input
|
||||||
|
id="height"
|
||||||
|
class="input"
|
||||||
|
type="number"
|
||||||
|
min="3"
|
||||||
|
max="10000"
|
||||||
|
bind:value={userimagesize} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full flex gap-2 items-center">
|
<div class="w-full flex gap-2 items-center">
|
||||||
<input class="input" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
|
<input class="input" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
|
||||||
<label for="markdown">
|
<label for="markdown">
|
||||||
<button class="btn btn-primary btn-sm flex-auto" on:click={onCopyMarkdown}>
|
<button class="btn btn-primary btn-md flex-auto" on:click={onCopyMarkdown}>
|
||||||
Copy Markdown
|
Copy Markdown
|
||||||
</button>
|
</button>
|
||||||
</label>
|
</label>
|
||||||
@@ -193,7 +205,7 @@
|
|||||||
bind:value={gistURL}
|
bind:value={gistURL}
|
||||||
placeholder="Enter Gist URL" />
|
placeholder="Enter Gist URL" />
|
||||||
<label for="gist">
|
<label for="gist">
|
||||||
<button class="btn btn-primary btn-sm flex-auto" on:click={loadGist}> Load Gist </button>
|
<button class="btn btn-primary btn-md flex-auto" on:click={loadGist}> Load Gist </button>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,21 +7,22 @@
|
|||||||
export let tabs: Tab[] = [];
|
export let tabs: Tab[] = [];
|
||||||
export let title: string;
|
export let title: string;
|
||||||
$: isOpen = isCloseable ? isOpen : true;
|
$: isOpen = isCloseable ? isOpen : true;
|
||||||
|
$: isTabsShown = isOpen && tabs.length > 0;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card rounded overflow-hidden m-2 flex-grow flex flex-col shadow-2xl">
|
<div class="card rounded overflow-hidden m-2 flex-grow flex flex-col shadow-2xl">
|
||||||
<div
|
<div
|
||||||
class="bg-primary p-2 {tabs.length > 0 ? 'pb-0' : ''} flex-none cursor-pointer"
|
class="bg-primary p-2 {isTabsShown ? 'pb-0' : ''} flex-none cursor-pointer"
|
||||||
on:click={() => (isOpen = !isOpen)}>
|
on:click={() => (isOpen = !isOpen)}>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<Tabs on:select {tabs} bind:isOpen {title} {isCloseable} />
|
<Tabs on:select {tabs} bind:isOpen {title} {isCloseable} />
|
||||||
<div class="flex gap-x-4 items-center">
|
<div class="flex gap-x-4 items-center {isTabsShown ? '-mt-2' : ''}">
|
||||||
<slot name="actions" />
|
<slot name="actions" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if isOpen}
|
{#if isOpen}
|
||||||
<div class="card-body p-0 flex-grow overflow-auto" transition:slide>
|
<div class="card-body p-0 flex-grow overflow-auto text-base-content" transition:slide>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<ul class="tabs" transition:fade>
|
<ul class="tabs" transition:fade>
|
||||||
{#each tabs as tab}
|
{#each tabs as tab}
|
||||||
<div
|
<div
|
||||||
class="tab tab-lifted {activeTabID === tab.id ? 'tab-active' : ''}"
|
class="tab tab-lifted text-primary-content {activeTabID === tab.id ? 'tab-active' : ''}"
|
||||||
on:click|stopPropagation={() => toggleTabs(tab)}>
|
on:click|stopPropagation={() => toggleTabs(tab)}>
|
||||||
<i class="mr-1 {tab.icon}" />
|
<i class="mr-1 {tab.icon}" />
|
||||||
{tab.title}
|
{tab.title}
|
||||||
|
|||||||
@@ -90,13 +90,13 @@
|
|||||||
<div slot="actions">
|
<div slot="actions">
|
||||||
<button
|
<button
|
||||||
id="saveHistory"
|
id="saveHistory"
|
||||||
class="btn btn-xs btn-success"
|
class="btn btn-xs btn-success w-12"
|
||||||
on:click|stopPropagation={() => saveHistory()}
|
on:click|stopPropagation={() => saveHistory()}
|
||||||
title="Save current state"><i class="far fa-save" /></button>
|
title="Save current state"><i class="far fa-save" /></button>
|
||||||
{#if $historyModeStore !== 'loader'}
|
{#if $historyModeStore !== 'loader'}
|
||||||
<button
|
<button
|
||||||
id="clearHistory"
|
id="clearHistory"
|
||||||
class="btn btn-xs btn-error"
|
class="btn btn-xs btn-error w-12"
|
||||||
on:click|stopPropagation={() => clearHistory()}
|
on:click|stopPropagation={() => clearHistory()}
|
||||||
title="Delete all saved states"><i class="fas fa-trash-alt" /></button>
|
title="Delete all saved states"><i class="fas fa-trash-alt" /></button>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
<li class="rounded p-2 shadow flex-col">
|
<li class="rounded p-2 shadow flex-col">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col text-base-content">
|
||||||
{#if url}
|
{#if url}
|
||||||
<a
|
<a
|
||||||
href={url}
|
href={url}
|
||||||
|
|||||||
@@ -1,47 +1,59 @@
|
|||||||
<script>
|
<script>
|
||||||
import { toggleDarkTheme } from '$lib/util/state';
|
|
||||||
|
|
||||||
import { setTheme, themeStore } from '$lib/util/theme';
|
import { setTheme, themeStore } from '$lib/util/theme';
|
||||||
import { onMount } from 'svelte';
|
|
||||||
|
|
||||||
const themes = [
|
const themes = [
|
||||||
'light',
|
'🌝 light',
|
||||||
'dark',
|
'🌚 dark',
|
||||||
'cupcake',
|
'🧁 cupcake',
|
||||||
'bumblebee',
|
'🐝 bumblebee',
|
||||||
'emerald',
|
'✳️ emerald',
|
||||||
'corporate',
|
'🏢 corporate',
|
||||||
'synthwave',
|
'🌃 synthwave',
|
||||||
'retro',
|
'👴 retro',
|
||||||
'cyberpunk',
|
'🤖 cyberpunk',
|
||||||
'valentine',
|
'🌸 valentine',
|
||||||
'halloween',
|
'🎃 halloween',
|
||||||
'garden',
|
'🌷 garden',
|
||||||
'forest',
|
'🌲 forest',
|
||||||
'aqua',
|
'🐟 aqua',
|
||||||
'lofi',
|
'👓 lofi',
|
||||||
'pastel',
|
'🖍 pastel',
|
||||||
'fantasy',
|
'🧚♀️ fantasy',
|
||||||
'wireframe',
|
'📝 wireframe',
|
||||||
'black',
|
'🏴 black',
|
||||||
'luxury',
|
'💎 luxury',
|
||||||
'dracula'
|
'🧛♂️ dracula'
|
||||||
];
|
];
|
||||||
|
|
||||||
let selectedTheme = $themeStore.theme;
|
|
||||||
onMount(() => {
|
|
||||||
themeStore.subscribe(({ theme, isDark }) => {
|
|
||||||
document.getElementsByTagName('html')[0].setAttribute('data-theme', theme);
|
|
||||||
toggleDarkTheme(isDark);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<select
|
<div class="hidden lg:block dropdown">
|
||||||
class="select select-bordered"
|
<div tabindex="0" class="btn btn-ghost ">
|
||||||
bind:value={selectedTheme}
|
<svg
|
||||||
on:change={() => setTheme(selectedTheme)}>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
{#each themes as theme}
|
fill="none"
|
||||||
<option value={theme}>{theme}</option>
|
viewBox="0 0 24 24"
|
||||||
{/each}
|
class="inline-block w-6 h-6 stroke-current md:mr-2"
|
||||||
</select>
|
><path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" /></svg>
|
||||||
|
<span class="hidden md:inline"> Change Theme </span>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 1792 1792"
|
||||||
|
class="inline-block w-4 h-4 ml-1 fill-current"
|
||||||
|
><path
|
||||||
|
d="M1395 736q0 13-10 23l-466 466q-10 10-23 10t-23-10l-466-466q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l393 393 393-393q10-10 23-10t23 10l50 50q10 10 10 23z" /></svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-14 overflow-y-auto shadow-2xl top-px dropdown-content h-96 w-52 bg-base-200 text-base-content">
|
||||||
|
<ul tabindex="0" class="p-4 menu compact">
|
||||||
|
{#each themes as theme}
|
||||||
|
<li class={theme.includes($themeStore.theme) ? 'bordered' : ''}>
|
||||||
|
<a on:click={() => setTheme(theme)}>{theme}</a>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export const toggleDarkTheme = (dark: boolean): void => {
|
|||||||
config.theme = dark ? 'dark' : 'default';
|
config.theme = dark ? 'dark' : 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...state, mermaid: JSON.stringify(config), updateEditor: true };
|
return { ...state, mermaid: JSON.stringify(config, null, 2), updateEditor: true };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import { persist, localStorage } from '@macfja/svelte-persistent-store';
|
import { persist, localStorage } from '@macfja/svelte-persistent-store';
|
||||||
import { toggleDarkTheme } from './state';
|
|
||||||
|
|
||||||
export const themeStore = persist(
|
export const themeStore = persist(
|
||||||
writable({
|
writable({
|
||||||
isDark: false,
|
isDark: false,
|
||||||
theme: 'light'
|
theme: ''
|
||||||
}),
|
}),
|
||||||
localStorage(),
|
localStorage(),
|
||||||
'themeStore'
|
'themeStore'
|
||||||
@@ -14,6 +13,9 @@ export const themeStore = persist(
|
|||||||
const darkThemes = ['dark', 'synthwave', 'halloween', 'forest', 'luxury', 'black', 'dracula'];
|
const darkThemes = ['dark', 'synthwave', 'halloween', 'forest', 'luxury', 'black', 'dracula'];
|
||||||
|
|
||||||
export const setTheme = (theme: string): void => {
|
export const setTheme = (theme: string): void => {
|
||||||
|
if (theme.includes(' ')) {
|
||||||
|
theme = theme.split(' ')[1].trim();
|
||||||
|
}
|
||||||
const isDark = darkThemes.includes(theme);
|
const isDark = darkThemes.includes(theme);
|
||||||
console.log('Setting theme', theme);
|
console.log('Setting theme', theme);
|
||||||
themeStore.set({ theme, isDark });
|
themeStore.set({ theme, isDark });
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
import { base } from '$app/paths';
|
import { base } from '$app/paths';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { loadingStateStore } from '$lib/util/loading';
|
import { loadingStateStore } from '$lib/util/loading';
|
||||||
import { themeStore } from '$lib/util/theme';
|
import { setTheme, themeStore } from '$lib/util/theme';
|
||||||
|
import { toggleDarkTheme } from '$lib/util/state';
|
||||||
|
|
||||||
// This can be removed once https://github.com/sveltejs/kit/issues/1612 is fixed.
|
// This can be removed once https://github.com/sveltejs/kit/issues/1612 is fixed.
|
||||||
// Then move it into src and vite will bundle it automatically.
|
// Then move it into src and vite will bundle it automatically.
|
||||||
@@ -20,10 +21,23 @@
|
|||||||
console.log('Service worker registration failed, error:', error);
|
console.log('Service worker registration failed, error:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
||||||
|
if (isDarkMode && $themeStore.theme === '') {
|
||||||
|
setTheme('dark');
|
||||||
|
}
|
||||||
|
|
||||||
|
themeStore.subscribe(({ theme, isDark }) => {
|
||||||
|
if (theme) {
|
||||||
|
document.getElementsByTagName('html')[0].setAttribute('data-theme', theme);
|
||||||
|
toggleDarkTheme(isDark);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="h-screen text-primary-content" data-theme={$themeStore}>
|
<main class="h-screen text-primary-content">
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
+20
-17
@@ -126,22 +126,25 @@
|
|||||||
<div class="hidden md:flex flex-col" id="editorPane" style="width: 40%">
|
<div class="hidden md:flex flex-col" id="editorPane" style="width: 40%">
|
||||||
<Card on:select={tabSelectHandler} {tabs} isCloseable={false} title="Mermaid">
|
<Card on:select={tabSelectHandler} {tabs} isCloseable={false} title="Mermaid">
|
||||||
<div slot="actions">
|
<div slot="actions">
|
||||||
{#if !$codeStore.autoSync}
|
<div class="flex flex-row items-center">
|
||||||
<button
|
{#if !$codeStore.autoSync}
|
||||||
class="btn btn-primary btn-xs"
|
<button
|
||||||
title="Sync Diagram"
|
class="btn btn-secondary btn-xs"
|
||||||
data-cy="sync"
|
title="Sync Diagram"
|
||||||
on:click={syncDiagram}><i class="fas fa-sync" /></button>
|
data-cy="sync"
|
||||||
{/if}
|
on:click={syncDiagram}><i class="fas fa-sync" /></button>
|
||||||
<div class="form-control">
|
{/if}
|
||||||
<label class="cursor-pointer label" for="autoSync">
|
|
||||||
<input
|
<div class="form-control">
|
||||||
type="checkbox"
|
<label class="cursor-pointer label" for="autoSync">
|
||||||
class="toggle toggle-primary toggle-sm"
|
<input
|
||||||
id="autoSync"
|
type="checkbox"
|
||||||
bind:checked={$codeStore.autoSync} />
|
class="toggle toggle-primary"
|
||||||
<span> Auto sync</span>
|
id="autoSync"
|
||||||
</label>
|
bind:checked={$codeStore.autoSync} />
|
||||||
|
<span> Auto sync</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -161,7 +164,7 @@
|
|||||||
slot="actions"
|
slot="actions"
|
||||||
class="btn btn-primary btn-xs shadow-lg"
|
class="btn btn-primary btn-xs shadow-lg"
|
||||||
title="View diagram in new page"
|
title="View diagram in new page"
|
||||||
on:click|stopPropagation={() => viewDiagram()}><i class="far fa-eye" /> View</button>
|
on:click|stopPropagation={() => viewDiagram()}><i class="far fa-eye mr-2" /> View</button>
|
||||||
|
|
||||||
<div class="flex-1 overflow-auto">
|
<div class="flex-1 overflow-auto">
|
||||||
<View />
|
<View />
|
||||||
|
|||||||
Reference in New Issue
Block a user