Skip to content

Commit f3762c8

Browse files
authored
Skeleton themes (#184)
* Update tailwind plugin to only generate shade colors if not present in theme (ex. Skeleton provides the shades 100-900). Map `{color}-500` to `{color}` if not defined. Generate neutral color if not defined * Map Skeleton themes to Svelte UX themes * Switch Daisy UI themes back as the default (for now, until a more robust solution is available)
1 parent 9350414 commit f3762c8

File tree

8 files changed

+172
-18
lines changed

8 files changed

+172
-18
lines changed

.changeset/rare-flowers-flash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-ux": patch
3+
---
4+
5+
Map Skeleton themes to Svelte UX themes

packages/svelte-ux/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"prepare": "svelte-kit sync"
2121
},
2222
"devDependencies": {
23+
"@skeletonlabs/tw-plugin": "^0.3.1",
2324
"@sveltejs/adapter-auto": "^2.1.1",
2425
"@sveltejs/kit": "^1.30.3",
2526
"@sveltejs/package": "^2.2.5",

packages/svelte-ux/src/lib/plugins/tailwind/theme.cjs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,55 +34,69 @@ function injectThemes(colorSpace, addBase, config) {
3434
function processThemeColors(themeColors) {
3535
const colors = { ...themeColors };
3636

37+
// Generate optional semanatic colors
38+
if (!('neutral' in colors) && !('neutral-500' in colors)) {
39+
colors['neutral'] = 'oklch(.355192 .032071 262.988584)';
40+
}
41+
3742
// Generate optional state colors
38-
if (!('info' in themeColors)) {
43+
if (!('info' in colors) && !('info-500' in colors)) {
3944
colors['info'] = 'oklch(0.7206 0.191 231.6)';
4045
}
41-
if (!('success' in themeColors)) {
46+
if (!('success' in colors) && !('success-500' in colors)) {
4247
colors['success'] = 'oklch(64.8% 0.150 160)';
4348
}
44-
if (!('warning' in themeColors)) {
49+
if (!('warning' in colors) && !('warning-500' in colors)) {
4550
colors['warning'] = 'oklch(0.8471 0.199 83.87)';
4651
}
47-
if (!('danger' in themeColors)) {
52+
if (!('danger' in colors) && !('danger-500' in colors)) {
4853
colors['danger'] = 'oklch(0.7176 0.221 22.18)';
4954
}
5055

5156
// Generate optional content colors
5257
for (const color of [...semanticColors, ...stateColors]) {
53-
if (!(`${color}-content` in themeColors)) {
58+
// Add `primary` from `primary-500` if not defined in theme (ex. Skeleton)
59+
if (!(color in colors) && `${color}-500` in themeColors) {
60+
colors[color] = themeColors[`${color}-500`];
61+
}
62+
63+
if (!(`${color}-content` in colors)) {
5464
colors[`${color}-content`] = foregroundColor(colors[color]);
5565
}
5666

67+
// Generate color shades (ex. `primary-500`) if not defined. Useful for Daisy but not Skeleton themes, for example
5768
for (const shade of shades) {
58-
const newColor =
59-
shade < 500
60-
? lightenColor(colors[color], (500 - shade) / 1000) // 100 == 0.1
61-
: shade > 500
62-
? darkenColor(colors[color], (shade - 500) / 1000) // 100 == 0.1
63-
: colors[color];
64-
colors[`${color}-${shade}`] = newColor;
69+
const shadeColorName = `${color}-${shade}`;
70+
if (!(shadeColorName in colors)) {
71+
const newColor =
72+
shade < 500
73+
? lightenColor(colors[color], (500 - shade) / 1000) // 100 == 0.1
74+
: shade > 500
75+
? darkenColor(colors[color], (shade - 500) / 1000) // 100 == 0.1
76+
: colors[color];
77+
colors[shadeColorName] = newColor;
78+
}
6579
}
6680
}
6781

6882
// Generate optional surface colors
69-
if (!('surface-100' in themeColors)) {
83+
if (!('surface-100' in colors)) {
7084
colors['surface-100'] = 'oklch(100 0 0)';
7185
}
7286

73-
if (!('surface-200' in themeColors)) {
87+
if (!('surface-200' in colors)) {
7488
colors['surface-200'] = darkenColor(colors['surface-100'], 0.07);
7589
}
7690

77-
if (!('surface-300' in themeColors)) {
91+
if (!('surface-300' in colors)) {
7892
if ('surface-200' in themeColors) {
7993
colors['surface-300'] = darkenColor(colors['surface-200'], 0.07);
8094
} else {
8195
colors['surface-300'] = darkenColor(colors['surface-100'], 0.14);
8296
}
8397
}
8498

85-
if (!('surface-content' in themeColors)) {
99+
if (!('surface-content' in colors)) {
86100
colors['surface-content'] = foregroundColor(colors['surface-100']);
87101
}
88102

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
const { getThemeProperties } = require('@skeletonlabs/tw-plugin');
2+
3+
const themeNames = [
4+
'skeleton',
5+
'wintry',
6+
'modern',
7+
'rocket',
8+
'seafoam',
9+
'vintage',
10+
'sahara',
11+
'hamlindigo',
12+
'gold-nouveau',
13+
];
14+
15+
// Map Skeleton to Svelte UX theme colors
16+
const skeletonColorMap = {
17+
// Semantic
18+
primary: 'primary',
19+
secondary: 'secondary',
20+
tertiary: 'accent',
21+
// '': 'neutral',
22+
// State
23+
success: 'success',
24+
warning: 'warning',
25+
error: 'danger',
26+
// Surface
27+
surface: 'surface',
28+
};
29+
30+
function processTheme(themeName, scheme) {
31+
const properties = getThemeProperties(themeName);
32+
33+
let mappedThemeProperties = Object.entries(properties)
34+
.map(([key, value]) => {
35+
if (key.startsWith('--color')) {
36+
// `--color-primary-500` => `primary-500`
37+
// `--color-primary-500` => `primary`
38+
const matches = key.match(/--color-(\w*)-([0-9]{3})/);
39+
const skeletonColorName = matches?.[1];
40+
const skeletonColorShade = matches?.[2];
41+
const themeColorName = skeletonColorMap[skeletonColorName];
42+
if (themeColorName) {
43+
return [`${themeColorName}-${skeletonColorShade}`, `rgb(${value})`];
44+
}
45+
} else if (key.startsWith('--on-')) {
46+
// `--on-primary` => `primary-content`
47+
const matches = key.match(/--on-(\w*)/);
48+
const skeletonColorName = matches?.[1];
49+
const themeColorName = skeletonColorMap[skeletonColorName];
50+
if (themeColorName) {
51+
return [`${themeColorName}-content`, `rgb(${value})`];
52+
}
53+
} else {
54+
// consider mapping additional properties
55+
// '--theme-font-family-base': 'system-ui',
56+
// '--theme-font-family-heading': 'system-ui',
57+
// '--theme-font-color-base': '0 0 0',
58+
// '--theme-font-color-dark': '255 255 255',
59+
// '--theme-rounded-base': '9999px',
60+
// '--theme-rounded-container': '8px',
61+
// '--theme-border-base': '1px',
62+
}
63+
})
64+
.filter((d) => d);
65+
66+
mappedThemeProperties =
67+
scheme === 'light'
68+
? [
69+
...mappedThemeProperties,
70+
['color-scheme', 'light'],
71+
['surface-100', `rgb(${properties['--color-surface-50']})`],
72+
['surface-200', `rgb(${properties['--color-surface-100']})`],
73+
['surface-300', `rgb(${properties['--color-surface-200']})`],
74+
['surface-content', `rgb(0 0 0)`],
75+
]
76+
: [
77+
...mappedThemeProperties,
78+
['color-scheme', 'dark'],
79+
['surface-100', `rgb(${properties['--color-surface-700']})`],
80+
['surface-200', `rgb(${properties['--color-surface-800']})`],
81+
['surface-300', `rgb(${properties['--color-surface-900']})`],
82+
['surface-content', `rgb(255 255 255)`],
83+
];
84+
85+
return [
86+
themeName === 'skeleton' ? scheme : scheme === 'dark' ? themeName + '-dark' : themeName,
87+
Object.fromEntries(mappedThemeProperties),
88+
];
89+
}
90+
91+
const themes = Object.fromEntries(
92+
themeNames.flatMap((themeName) => {
93+
return [processTheme(themeName, 'light'), processTheme(themeName, 'dark')];
94+
})
95+
);
96+
97+
const lightThemes = Object.keys(themes).filter((themeName) => !themeName.endsWith('dark'));
98+
const darkThemes = Object.keys(themes).filter((themeName) => themeName.endsWith('dark'));
99+
100+
module.exports = { themes, lightThemes, darkThemes };
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const themeNames = [
2+
'skeleton',
3+
'wintry',
4+
'modern',
5+
'rocket',
6+
'seafoam',
7+
'vintage',
8+
'sahara',
9+
'hamlindigo',
10+
'gold-nouveau',
11+
];
12+
13+
const lightThemes = themeNames.map((themeName) => (themeName === 'skeleton' ? 'light' : themeName));
14+
const darkThemes = themeNames.map((themeName) =>
15+
themeName === 'skeleton' ? 'dark' : themeName + '-dark'
16+
);
17+
18+
export { lightThemes, darkThemes };

packages/svelte-ux/src/routes/+layout.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import { settings } from '$lib/components/settings';
2121
import type { PageData } from './$types';
2222
import { DateToken } from '$lib/utils/date';
23+
2324
import { lightThemes, darkThemes } from '$lib/styles/daisy';
25+
// import { lightThemes, darkThemes } from '$lib/styles/skeleton';
2426
2527
export let data: PageData;
2628

packages/svelte-ux/tailwind.config.cjs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ const plugin = require('tailwindcss/plugin');
22
const colors = require('tailwindcss/colors');
33

44
const svelteUx = require('./src/lib/plugins/tailwind.cjs');
5-
const { themes } = require('./src/lib/styles/daisy.cjs');
5+
6+
const { themes: daisyThemes } = require('./src/lib/styles/daisy.cjs');
7+
// const { themes: skeletonThemes } = require('./src/lib/styles/skeleton.cjs');
68

79
module.exports = {
810
content: ['./src/**/*.{html,svelte,md,ts,js}'],
911
ux: {
10-
themes,
12+
themes: daisyThemes,
13+
// themes: skeletonThemes,
1114
// themes: {
1215
// light: {
1316
// primary: colors['blue']['500'],

pnpm-lock.yaml

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)