@joyautomation/salt 0.0.21 → 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -674
- package/dist/actions.js +2 -2
- package/dist/client.js +6 -6
- package/dist/components/ThemeSwitch.svelte +83 -0
- package/dist/components/ThemeSwitch.svelte.d.ts +18 -0
- package/dist/components/Toggle.svelte +0 -2
- package/dist/components/forms/types.d.ts +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.js +10 -8
- package/dist/state/notifications.svelte.js +3 -3
- package/dist/stores/notifications.js +4 -4
- package/dist/styles/buttons.scss +1 -1
- package/dist/styles/themes.scss +26 -12
- package/dist/theme.svelte.d.ts +7 -0
- package/dist/theme.svelte.js +49 -0
- package/package.json +20 -13
package/dist/actions.js
CHANGED
|
@@ -3,13 +3,13 @@ export const setTheme = async ({ request, cookies }) => {
|
|
|
3
3
|
const theme = data.get('theme');
|
|
4
4
|
cookies.set(`theme`, theme, {
|
|
5
5
|
path: '/',
|
|
6
|
-
secure: false
|
|
6
|
+
secure: false
|
|
7
7
|
});
|
|
8
8
|
const themeName = theme === 'themeDark' ? 'dark mode' : 'light mode';
|
|
9
9
|
return {
|
|
10
10
|
context: 'setTheme',
|
|
11
11
|
type: 'success',
|
|
12
12
|
message: `You are now in ${themeName}.`,
|
|
13
|
-
theme
|
|
13
|
+
theme
|
|
14
14
|
};
|
|
15
15
|
};
|
package/dist/client.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export function setTheme(form) {
|
|
2
|
-
if (form?.context ===
|
|
3
|
-
if (form?.theme ===
|
|
4
|
-
document.body.classList.add(
|
|
5
|
-
document.body.classList.remove(
|
|
2
|
+
if (form?.context === 'setTheme') {
|
|
3
|
+
if (form?.theme === 'themeDark') {
|
|
4
|
+
document.body.classList.add('themeDark');
|
|
5
|
+
document.body.classList.remove('themeLight');
|
|
6
6
|
}
|
|
7
7
|
else {
|
|
8
|
-
document.body.classList.remove(
|
|
9
|
-
document.body.classList.add(
|
|
8
|
+
document.body.classList.remove('themeDark');
|
|
9
|
+
document.body.classList.add('themeLight');
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { themeState, type Theme } from '../theme.svelte';
|
|
3
|
+
|
|
4
|
+
const options: { value: Theme; label: string; icon: string }[] = [
|
|
5
|
+
{ value: 'themeSystem', label: 'System', icon: 'computer' },
|
|
6
|
+
{ value: 'themeLight', label: 'Light', icon: 'sun' },
|
|
7
|
+
{ value: 'themeDark', label: 'Dark', icon: 'moon' }
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
function handleChange(newTheme: Theme) {
|
|
11
|
+
themeState.set(newTheme);
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<div class="theme-switch">
|
|
16
|
+
{#each options as option}
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
class="theme-option"
|
|
20
|
+
class:active={themeState.value === option.value}
|
|
21
|
+
onclick={() => handleChange(option.value)}
|
|
22
|
+
title={option.label}
|
|
23
|
+
>
|
|
24
|
+
{#if option.icon === 'computer'}
|
|
25
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
26
|
+
<rect x="2" y="3" width="20" height="14" rx="2" />
|
|
27
|
+
<line x1="8" y1="21" x2="16" y2="21" />
|
|
28
|
+
<line x1="12" y1="17" x2="12" y2="21" />
|
|
29
|
+
</svg>
|
|
30
|
+
{:else if option.icon === 'sun'}
|
|
31
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
32
|
+
<circle cx="12" cy="12" r="4" />
|
|
33
|
+
<path d="M12 2v2" />
|
|
34
|
+
<path d="M12 20v2" />
|
|
35
|
+
<path d="m4.93 4.93 1.41 1.41" />
|
|
36
|
+
<path d="m17.66 17.66 1.41 1.41" />
|
|
37
|
+
<path d="M2 12h2" />
|
|
38
|
+
<path d="M20 12h2" />
|
|
39
|
+
<path d="m6.34 17.66-1.41 1.41" />
|
|
40
|
+
<path d="m19.07 4.93-1.41 1.41" />
|
|
41
|
+
</svg>
|
|
42
|
+
{:else if option.icon === 'moon'}
|
|
43
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
44
|
+
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
|
|
45
|
+
</svg>
|
|
46
|
+
{/if}
|
|
47
|
+
</button>
|
|
48
|
+
{/each}
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<style>.theme-switch {
|
|
52
|
+
display: flex;
|
|
53
|
+
gap: 1px;
|
|
54
|
+
background: var(--theme-neutral-200);
|
|
55
|
+
border-radius: 6px;
|
|
56
|
+
padding: 3px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.theme-option {
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
width: 44px;
|
|
64
|
+
height: 44px;
|
|
65
|
+
border: none;
|
|
66
|
+
border-radius: 4px;
|
|
67
|
+
background: transparent;
|
|
68
|
+
color: var(--theme-neutral-500);
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
transition: all 0.15s ease;
|
|
71
|
+
}
|
|
72
|
+
.theme-option:hover {
|
|
73
|
+
color: var(--theme-neutral-700);
|
|
74
|
+
background: var(--theme-neutral-300);
|
|
75
|
+
}
|
|
76
|
+
.theme-option.active {
|
|
77
|
+
background: var(--theme-neutral-100);
|
|
78
|
+
color: var(--theme-primary);
|
|
79
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
80
|
+
}
|
|
81
|
+
.theme-option svg {
|
|
82
|
+
flex-shrink: 0;
|
|
83
|
+
}</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const ThemeSwitch: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type ThemeSwitch = InstanceType<typeof ThemeSwitch>;
|
|
18
|
+
export default ThemeSwitch;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
export * as actions from
|
|
2
|
-
export * as client from
|
|
3
|
-
export { default as Toggle } from
|
|
4
|
-
export { default as ThemeButton } from
|
|
5
|
-
export { default as Toast } from
|
|
6
|
-
export { default as Icon } from
|
|
7
|
-
export * as icons from
|
|
8
|
-
export * as state from
|
|
1
|
+
export * as actions from './actions.js';
|
|
2
|
+
export * as client from './client.js';
|
|
3
|
+
export { default as Toggle } from './components/Toggle.svelte';
|
|
4
|
+
export { default as ThemeButton } from './components/ThemeButton.svelte';
|
|
5
|
+
export { default as Toast } from './components/Toast.svelte';
|
|
6
|
+
export { default as Icon } from './components/Icon.svelte';
|
|
7
|
+
export * as icons from './components/icons/index.js';
|
|
8
|
+
export * as state from './state/notifications.svelte';
|
|
9
|
+
export { default as ThemeSwitch } from './components/ThemeSwitch.svelte';
|
|
10
|
+
export { themeState, getEffectiveTheme, type Theme } from './theme.svelte';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
export * as actions from
|
|
2
|
-
export * as client from
|
|
3
|
-
export { default as Toggle } from
|
|
4
|
-
export { default as ThemeButton } from
|
|
5
|
-
export { default as Toast } from
|
|
6
|
-
export { default as Icon } from
|
|
7
|
-
export * as icons from
|
|
8
|
-
export * as state from
|
|
1
|
+
export * as actions from './actions.js';
|
|
2
|
+
export * as client from './client.js';
|
|
3
|
+
export { default as Toggle } from './components/Toggle.svelte';
|
|
4
|
+
export { default as ThemeButton } from './components/ThemeButton.svelte';
|
|
5
|
+
export { default as Toast } from './components/Toast.svelte';
|
|
6
|
+
export { default as Icon } from './components/Icon.svelte';
|
|
7
|
+
export * as icons from './components/icons/index.js';
|
|
8
|
+
export * as state from './state/notifications.svelte';
|
|
9
|
+
export { default as ThemeSwitch } from './components/ThemeSwitch.svelte';
|
|
10
|
+
export { themeState, getEffectiveTheme } from './theme.svelte';
|
|
@@ -2,7 +2,7 @@ import { writable } from 'svelte/store';
|
|
|
2
2
|
import { nanoid } from 'nanoid';
|
|
3
3
|
const initializer = [];
|
|
4
4
|
export const notifications = $state({
|
|
5
|
-
current: initializer
|
|
5
|
+
current: initializer
|
|
6
6
|
});
|
|
7
7
|
export function addNotification(notification) {
|
|
8
8
|
const id = nanoid();
|
|
@@ -10,8 +10,8 @@ export function addNotification(notification) {
|
|
|
10
10
|
...notifications.current,
|
|
11
11
|
{
|
|
12
12
|
id,
|
|
13
|
-
...notification
|
|
14
|
-
}
|
|
13
|
+
...notification
|
|
14
|
+
}
|
|
15
15
|
];
|
|
16
16
|
setTimeout(() => {
|
|
17
17
|
notifications.current = notifications.current.filter((n) => n.id !== id);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { writable } from
|
|
2
|
-
import { nanoid } from
|
|
1
|
+
import { writable } from 'svelte/store';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
3
|
const initializer = [];
|
|
4
4
|
export const notifications = writable(initializer);
|
|
5
5
|
export function addNotification(notification) {
|
|
@@ -8,8 +8,8 @@ export function addNotification(notification) {
|
|
|
8
8
|
...notifications,
|
|
9
9
|
{
|
|
10
10
|
id,
|
|
11
|
-
...notification
|
|
12
|
-
}
|
|
11
|
+
...notification
|
|
12
|
+
}
|
|
13
13
|
]);
|
|
14
14
|
setTimeout(() => {
|
|
15
15
|
notifications.update((notifications) => notifications.filter((n) => n.id !== id));
|
package/dist/styles/buttons.scss
CHANGED
package/dist/styles/themes.scss
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@use "sass:meta";
|
|
2
|
+
@use "sass:map";
|
|
2
3
|
|
|
3
4
|
$themes: (
|
|
4
5
|
"themeLight": (
|
|
@@ -127,19 +128,32 @@ $themes: (
|
|
|
127
128
|
),
|
|
128
129
|
);
|
|
129
130
|
|
|
130
|
-
@
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// Check if the value is a nested map (like for 'neutral')
|
|
136
|
-
@if (meta.type-of($value) == "map") {
|
|
137
|
-
@each $nested-key, $nested-value in $value {
|
|
138
|
-
--#{$property}-#{$nested-key}: #{$nested-value};
|
|
139
|
-
}
|
|
140
|
-
} @else {
|
|
141
|
-
--#{$property}: #{$value};
|
|
131
|
+
@mixin apply-theme($theme-map) {
|
|
132
|
+
@each $property, $value in $theme-map {
|
|
133
|
+
@if (meta.type-of($value) == "map") {
|
|
134
|
+
@each $nested-key, $nested-value in $value {
|
|
135
|
+
--#{$property}-#{$nested-key}: #{$nested-value};
|
|
142
136
|
}
|
|
137
|
+
} @else {
|
|
138
|
+
--#{$property}: #{$value};
|
|
143
139
|
}
|
|
144
140
|
}
|
|
145
141
|
}
|
|
142
|
+
|
|
143
|
+
@each $theme-name, $theme-map in $themes {
|
|
144
|
+
.#{$theme-name} {
|
|
145
|
+
@include apply-theme($theme-map);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@media (prefers-color-scheme: light) {
|
|
150
|
+
.themeSystem {
|
|
151
|
+
@include apply-theme(map.get($themes, "themeLight"));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@media (prefers-color-scheme: dark) {
|
|
156
|
+
.themeSystem {
|
|
157
|
+
@include apply-theme(map.get($themes, "themeDark"));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type Theme = 'themeSystem' | 'themeLight' | 'themeDark';
|
|
2
|
+
export declare const themeState: {
|
|
3
|
+
readonly value: Theme;
|
|
4
|
+
initialize: (serverTheme?: Theme | null) => void;
|
|
5
|
+
set: (newTheme: Theme) => void;
|
|
6
|
+
};
|
|
7
|
+
export declare function getEffectiveTheme(): 'themeLight' | 'themeDark';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const isTheme = (value) => value === 'themeSystem' || value === 'themeLight' || value === 'themeDark';
|
|
2
|
+
function readThemeCookie() {
|
|
3
|
+
if (typeof document === 'undefined')
|
|
4
|
+
return null;
|
|
5
|
+
const match = document.cookie?.match(/(?:^|; )theme=([^;]+)/);
|
|
6
|
+
if (!match)
|
|
7
|
+
return null;
|
|
8
|
+
try {
|
|
9
|
+
const value = decodeURIComponent(match[1]);
|
|
10
|
+
return isTheme(value) ? value : null;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function createThemeState() {
|
|
17
|
+
let current = $state('themeSystem');
|
|
18
|
+
function initialize(serverTheme) {
|
|
19
|
+
if (serverTheme && isTheme(serverTheme)) {
|
|
20
|
+
current = serverTheme;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const cookieTheme = readThemeCookie();
|
|
24
|
+
current = cookieTheme ?? 'themeSystem';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function set(newTheme) {
|
|
28
|
+
current = newTheme;
|
|
29
|
+
if (typeof document !== 'undefined') {
|
|
30
|
+
document.cookie = `theme=${newTheme}; path=/; max-age=31536000`;
|
|
31
|
+
document.body.className = newTheme;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
get value() {
|
|
36
|
+
return current;
|
|
37
|
+
},
|
|
38
|
+
initialize,
|
|
39
|
+
set
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export const themeState = createThemeState();
|
|
43
|
+
export function getEffectiveTheme() {
|
|
44
|
+
if (themeState.value === 'themeSystem') {
|
|
45
|
+
const prefersDark = globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
|
|
46
|
+
return prefersDark ? 'themeDark' : 'themeLight';
|
|
47
|
+
}
|
|
48
|
+
return themeState.value;
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joyautomation/salt",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.29",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"dev": "vite dev",
|
|
6
|
+
"build": "vite build && npm run package",
|
|
7
|
+
"preview": "vite preview",
|
|
8
|
+
"package": "svelte-kit sync && svelte-package && publint",
|
|
9
|
+
"prepublishOnly": "npm run package",
|
|
10
|
+
"test": "npm run test:integration && npm run test:unit",
|
|
11
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
12
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
13
|
+
"test:integration": "playwright test",
|
|
14
|
+
"test:unit": "vitest"
|
|
15
|
+
},
|
|
4
16
|
"exports": {
|
|
5
17
|
".": [
|
|
6
18
|
"./dist/index.js",
|
|
@@ -22,6 +34,7 @@
|
|
|
22
34
|
"svelte": "5.0.0-next.244"
|
|
23
35
|
},
|
|
24
36
|
"devDependencies": {
|
|
37
|
+
"@eslint/js": "^9.25.1",
|
|
25
38
|
"@playwright/test": "^1.52.0",
|
|
26
39
|
"@sveltejs/adapter-auto": "^6.0.0",
|
|
27
40
|
"@sveltejs/kit": "^2.20.7",
|
|
@@ -49,20 +62,14 @@
|
|
|
49
62
|
"svelte": "./dist/index.js",
|
|
50
63
|
"types": "./dist/index.d.ts",
|
|
51
64
|
"type": "module",
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "https://github.com/joyautomation/salt"
|
|
68
|
+
},
|
|
69
|
+
"packageManager": "pnpm@10.13.1",
|
|
52
70
|
"dependencies": {
|
|
53
71
|
"@sveltejs/adapter-node": "^5.2.12",
|
|
54
72
|
"nanoid": "^5.1.5",
|
|
55
73
|
"sass": "^1.87.0"
|
|
56
|
-
},
|
|
57
|
-
"scripts": {
|
|
58
|
-
"dev": "vite dev",
|
|
59
|
-
"build": "vite build && npm run package",
|
|
60
|
-
"preview": "vite preview",
|
|
61
|
-
"package": "svelte-kit sync && svelte-package && publint",
|
|
62
|
-
"test": "npm run test:integration && npm run test:unit",
|
|
63
|
-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
64
|
-
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
65
|
-
"test:integration": "playwright test",
|
|
66
|
-
"test:unit": "vitest"
|
|
67
74
|
}
|
|
68
|
-
}
|
|
75
|
+
}
|