PWA improvements

This commit is contained in:
Chris Kruining 2024-10-31 14:33:42 +01:00
parent dd11708d15
commit 6ed9c74862
No known key found for this signature in database
GPG key ID: EB894A3560CCCAD2
4 changed files with 70 additions and 31 deletions

View file

@ -1,6 +1,6 @@
{ {
"short_name": "Calque", "short_name": "Calque",
"name": "Calque", "name": "Calque - manage your i18n files",
"description": "Simple tool for maitaining i18n files", "description": "Simple tool for maitaining i18n files",
"icons": [ "icons": [
{ {
@ -13,8 +13,6 @@
"display_override": [ "display_override": [
"window-controls-overlay" "window-controls-overlay"
], ],
"theme_color": "#222",
"background_color": "#222",
"screenshots": [ "screenshots": [
{ {
"src": "/images/screenshots/narrow.png", "src": "/images/screenshots/narrow.png",

View file

@ -1,47 +1,66 @@
import { Accessor, Component, createEffect, createSignal, For, Setter } from "solid-js"; import { Component, createEffect, createMemo, createResource, For, Setter } from "solid-js";
import css from './colorschemepicker.module.css'; import css from './colorschemepicker.module.css';
import { CgDarkMode } from "solid-icons/cg"; import { CgDarkMode } from "solid-icons/cg";
import { action, cache, useAction } from "@solidjs/router";
import { useSession } from "vinxi/http";
export enum ColorScheme { export enum ColorScheme {
Auto = 'light dark', Auto = 'light dark',
Light = 'light', Light = 'light',
Dark = 'dark', Dark = 'dark',
} }
type ColorSchemeKey = keyof typeof ColorScheme;
const colorSchemeEntries = [ const colorSchemeKeys: readonly ColorSchemeKey[] = ['Auto', 'Light', 'Dark'] as const;
[ColorScheme.Auto, 'Auto'],
[ColorScheme.Light, 'Light'],
[ColorScheme.Dark, 'Dark'],
] as const;
interface ColorSchemePickerProps { interface ColorSchemePickerProps {
value?: Setter<ColorScheme> | [Accessor<ColorScheme>, Setter<ColorScheme>]; value?: Setter<ColorScheme>;
} }
const getSession = async () => {
'use server';
return useSession<{ colorScheme: ColorSchemeKey }>({
password: process.env.SESSION_SECRET!,
});
};
export const getColorScheme = cache(async () => {
'use server';
const session = await getSession();
return session.data.colorScheme;
}, 'color-scheme');
const setColorScheme = action(async (colorScheme: ColorSchemeKey) => {
'use server';
const session = await getSession();
await session.update({ colorScheme });
}, 'color-scheme');
export const ColorSchemePicker: Component<ColorSchemePickerProps> = (props) => { export const ColorSchemePicker: Component<ColorSchemePickerProps> = (props) => {
const [value, setValue] = createSignal<ColorScheme>(ColorScheme.Auto); const [value, { mutate }] = createResource<ColorSchemeKey>(() => getColorScheme(), { initialValue: 'Auto' });
const updateStore = useAction(setColorScheme);
createEffect(() => { createEffect(() => {
const currentValue = value(); props.value?.(ColorScheme[value()]);
const setter = props.value instanceof Array ? props.value[1] : props.value;
if (!setter) {
return;
}
setter(currentValue);
}); });
return <label class={css.picker}> return <label class={css.picker}>
<CgDarkMode /> <CgDarkMode />
<select name="color-scheme-picker" value={value()} onInput={(e) => { <select name="color-scheme-picker" onInput={(e) => {
if (e.target.value !== value()) { if (e.target.value !== value()) {
setValue(e.target.value as any); const nextValue = (e.target.value ?? 'Auto') as ColorSchemeKey;
mutate(nextValue);
updateStore(nextValue);
} }
}}> }}>
<For each={colorSchemeEntries}>{ <For each={colorSchemeKeys}>{
([value, label]) => <option value={value}>{label}</option> (v) => <option value={v} selected={v === value()}>{v}</option>
}</For> }</For>
</select> </select>
</label>; </label>;

View file

@ -1,17 +1,24 @@
import { Link, Meta, Title } from "@solidjs/meta"; import { Link, Title } from "@solidjs/meta";
import { createSignal, For, ParentProps, Show } from "solid-js"; import { createEffect, createMemo, createSignal, ParentProps, Show } from "solid-js";
import { BsTranslate } from "solid-icons/bs"; import { BsTranslate } from "solid-icons/bs";
import { FilesProvider } from "~/features/file"; import { FilesProvider } from "~/features/file";
import { CommandPalette, CommandPaletteApi, Menu, MenuProvider } from "~/features/menu"; import { CommandPalette, CommandPaletteApi, Menu, MenuProvider } from "~/features/menu";
import { isServer } from "solid-js/web"; import { isServer } from "solid-js/web";
import { A } from "@solidjs/router"; import { A, createAsync } from "@solidjs/router";
import { createCommand, Modifier } from "~/features/command"; import { createCommand, Modifier } from "~/features/command";
import { ColorScheme, ColorSchemePicker } from "~/components/colorschemepicker"; import { ColorScheme, ColorSchemePicker, getColorScheme } from "~/components/colorschemepicker";
import css from "./editor.module.css"; import css from "./editor.module.css";
export default function Editor(props: ParentProps) { export default function Editor(props: ParentProps) {
const storedColorScheme = createAsync<keyof typeof ColorScheme>(() => getColorScheme(), { initialValue: 'Auto' });
const [commandPalette, setCommandPalette] = createSignal<CommandPaletteApi>(); const [commandPalette, setCommandPalette] = createSignal<CommandPaletteApi>();
const [colorScheme, setColorScheme] = createSignal<ColorScheme>(ColorScheme.Auto); const colorScheme = createMemo(() => ColorScheme[storedColorScheme()]);
const color = createMemo(() => ({
[ColorScheme.Auto]: undefined,
[ColorScheme.Light]: '#eee',
[ColorScheme.Dark]: '#333',
}[ColorScheme[storedColorScheme()]]));
const supported = isServer || typeof window.showDirectoryPicker === 'function'; const supported = isServer || typeof window.showDirectoryPicker === 'function';
const commands = [ const commands = [
@ -22,7 +29,15 @@ export default function Editor(props: ParentProps) {
return <MenuProvider commands={commands}> return <MenuProvider commands={commands}>
<Title>Calque</Title> <Title>Calque</Title>
<Meta name="color-scheme" content={colorScheme()} />
<meta id="theme-scheme" name="color-scheme" content={colorScheme()} />
<meta id="theme-color" name="theme-color" content={color()} />
<Show when={color() === undefined}>
<meta id="theme-auto-light" name="theme-color" media="(prefers-color-scheme: light)" content="#eee" />
<meta id="theme-auto-dark" name="theme-color" media="(prefers-color-scheme: dark)" content="#333" />
</Show>
<Link rel="icon" href="/images/favicon.dark.svg" media="screen and (prefers-color-scheme: dark)" /> <Link rel="icon" href="/images/favicon.dark.svg" media="screen and (prefers-color-scheme: dark)" />
<Link rel="icon" href="/images/favicon.light.svg" media="screen and (prefers-color-scheme: light)" /> <Link rel="icon" href="/images/favicon.light.svg" media="screen and (prefers-color-scheme: light)" />
<Link rel="manifest" href="/manifest.json" /> <Link rel="manifest" href="/manifest.json" />
@ -34,7 +49,7 @@ export default function Editor(props: ParentProps) {
<Menu.Mount /> <Menu.Mount />
<section class={css.right}> <section class={css.right}>
<ColorSchemePicker value={[colorScheme, setColorScheme]} /> <ColorSchemePicker />
</section> </section>
</nav> </nav>

View file

@ -11,16 +11,23 @@
grid-template-columns: auto minmax(0, 1fr) auto; grid-template-columns: auto minmax(0, 1fr) auto;
grid-auto-flow: column; grid-auto-flow: column;
justify-content: start; justify-content: start;
justify-items: start;
position: relative; position: relative;
z-index: 10; z-index: 10;
gap: .5em; gap: .5em;
padding-inline: 1em; padding-inline: 1em;
block-size: 2em; block-size: calc(env(titlebar-area-height, 2em) + .5px);
inline-size: env(titlebar-area-width, 100%);
-webkit-app-region: drag;
background-color: var(--surface-3); background-color: var(--surface-3);
color: var(--text-1); color: var(--text-1);
& > * {
-webkit-app-region: no-drag;
}
& > .logo { & > .logo {
inline-size: 3em; inline-size: 3em;
block-size: 3em; block-size: 3em;