Skip to content

Commit

Permalink
Skeleton themes (#184)
Browse files Browse the repository at this point in the history
* 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)
  • Loading branch information
techniq authored Jan 6, 2024
1 parent 9350414 commit f3762c8
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/rare-flowers-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-ux": patch
---

Map Skeleton themes to Svelte UX themes
1 change: 1 addition & 0 deletions packages/svelte-ux/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"prepare": "svelte-kit sync"
},
"devDependencies": {
"@skeletonlabs/tw-plugin": "^0.3.1",
"@sveltejs/adapter-auto": "^2.1.1",
"@sveltejs/kit": "^1.30.3",
"@sveltejs/package": "^2.2.5",
Expand Down
46 changes: 30 additions & 16 deletions packages/svelte-ux/src/lib/plugins/tailwind/theme.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,55 +34,69 @@ function injectThemes(colorSpace, addBase, config) {
function processThemeColors(themeColors) {
const colors = { ...themeColors };

// Generate optional semanatic colors
if (!('neutral' in colors) && !('neutral-500' in colors)) {
colors['neutral'] = 'oklch(.355192 .032071 262.988584)';
}

// Generate optional state colors
if (!('info' in themeColors)) {
if (!('info' in colors) && !('info-500' in colors)) {
colors['info'] = 'oklch(0.7206 0.191 231.6)';
}
if (!('success' in themeColors)) {
if (!('success' in colors) && !('success-500' in colors)) {
colors['success'] = 'oklch(64.8% 0.150 160)';
}
if (!('warning' in themeColors)) {
if (!('warning' in colors) && !('warning-500' in colors)) {
colors['warning'] = 'oklch(0.8471 0.199 83.87)';
}
if (!('danger' in themeColors)) {
if (!('danger' in colors) && !('danger-500' in colors)) {
colors['danger'] = 'oklch(0.7176 0.221 22.18)';
}

// Generate optional content colors
for (const color of [...semanticColors, ...stateColors]) {
if (!(`${color}-content` in themeColors)) {
// Add `primary` from `primary-500` if not defined in theme (ex. Skeleton)
if (!(color in colors) && `${color}-500` in themeColors) {
colors[color] = themeColors[`${color}-500`];
}

if (!(`${color}-content` in colors)) {
colors[`${color}-content`] = foregroundColor(colors[color]);
}

// Generate color shades (ex. `primary-500`) if not defined. Useful for Daisy but not Skeleton themes, for example
for (const shade of shades) {
const newColor =
shade < 500
? lightenColor(colors[color], (500 - shade) / 1000) // 100 == 0.1
: shade > 500
? darkenColor(colors[color], (shade - 500) / 1000) // 100 == 0.1
: colors[color];
colors[`${color}-${shade}`] = newColor;
const shadeColorName = `${color}-${shade}`;
if (!(shadeColorName in colors)) {
const newColor =
shade < 500
? lightenColor(colors[color], (500 - shade) / 1000) // 100 == 0.1
: shade > 500
? darkenColor(colors[color], (shade - 500) / 1000) // 100 == 0.1
: colors[color];
colors[shadeColorName] = newColor;
}
}
}

// Generate optional surface colors
if (!('surface-100' in themeColors)) {
if (!('surface-100' in colors)) {
colors['surface-100'] = 'oklch(100 0 0)';
}

if (!('surface-200' in themeColors)) {
if (!('surface-200' in colors)) {
colors['surface-200'] = darkenColor(colors['surface-100'], 0.07);
}

if (!('surface-300' in themeColors)) {
if (!('surface-300' in colors)) {
if ('surface-200' in themeColors) {
colors['surface-300'] = darkenColor(colors['surface-200'], 0.07);
} else {
colors['surface-300'] = darkenColor(colors['surface-100'], 0.14);
}
}

if (!('surface-content' in themeColors)) {
if (!('surface-content' in colors)) {
colors['surface-content'] = foregroundColor(colors['surface-100']);
}

Expand Down
100 changes: 100 additions & 0 deletions packages/svelte-ux/src/lib/styles/skeleton.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
const { getThemeProperties } = require('@skeletonlabs/tw-plugin');

const themeNames = [
'skeleton',
'wintry',
'modern',
'rocket',
'seafoam',
'vintage',
'sahara',
'hamlindigo',
'gold-nouveau',
];

// Map Skeleton to Svelte UX theme colors
const skeletonColorMap = {
// Semantic
primary: 'primary',
secondary: 'secondary',
tertiary: 'accent',
// '': 'neutral',
// State
success: 'success',
warning: 'warning',
error: 'danger',
// Surface
surface: 'surface',
};

function processTheme(themeName, scheme) {
const properties = getThemeProperties(themeName);

let mappedThemeProperties = Object.entries(properties)
.map(([key, value]) => {
if (key.startsWith('--color')) {
// `--color-primary-500` => `primary-500`
// `--color-primary-500` => `primary`
const matches = key.match(/--color-(\w*)-([0-9]{3})/);
const skeletonColorName = matches?.[1];
const skeletonColorShade = matches?.[2];
const themeColorName = skeletonColorMap[skeletonColorName];
if (themeColorName) {
return [`${themeColorName}-${skeletonColorShade}`, `rgb(${value})`];
}
} else if (key.startsWith('--on-')) {
// `--on-primary` => `primary-content`
const matches = key.match(/--on-(\w*)/);
const skeletonColorName = matches?.[1];
const themeColorName = skeletonColorMap[skeletonColorName];
if (themeColorName) {
return [`${themeColorName}-content`, `rgb(${value})`];
}
} else {
// consider mapping additional properties
// '--theme-font-family-base': 'system-ui',
// '--theme-font-family-heading': 'system-ui',
// '--theme-font-color-base': '0 0 0',
// '--theme-font-color-dark': '255 255 255',
// '--theme-rounded-base': '9999px',
// '--theme-rounded-container': '8px',
// '--theme-border-base': '1px',
}
})
.filter((d) => d);

mappedThemeProperties =
scheme === 'light'
? [
...mappedThemeProperties,
['color-scheme', 'light'],
['surface-100', `rgb(${properties['--color-surface-50']})`],
['surface-200', `rgb(${properties['--color-surface-100']})`],
['surface-300', `rgb(${properties['--color-surface-200']})`],
['surface-content', `rgb(0 0 0)`],
]
: [
...mappedThemeProperties,
['color-scheme', 'dark'],
['surface-100', `rgb(${properties['--color-surface-700']})`],
['surface-200', `rgb(${properties['--color-surface-800']})`],
['surface-300', `rgb(${properties['--color-surface-900']})`],
['surface-content', `rgb(255 255 255)`],
];

return [
themeName === 'skeleton' ? scheme : scheme === 'dark' ? themeName + '-dark' : themeName,
Object.fromEntries(mappedThemeProperties),
];
}

const themes = Object.fromEntries(
themeNames.flatMap((themeName) => {
return [processTheme(themeName, 'light'), processTheme(themeName, 'dark')];
})
);

const lightThemes = Object.keys(themes).filter((themeName) => !themeName.endsWith('dark'));
const darkThemes = Object.keys(themes).filter((themeName) => themeName.endsWith('dark'));

module.exports = { themes, lightThemes, darkThemes };
18 changes: 18 additions & 0 deletions packages/svelte-ux/src/lib/styles/skeleton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const themeNames = [
'skeleton',
'wintry',
'modern',
'rocket',
'seafoam',
'vintage',
'sahara',
'hamlindigo',
'gold-nouveau',
];

const lightThemes = themeNames.map((themeName) => (themeName === 'skeleton' ? 'light' : themeName));
const darkThemes = themeNames.map((themeName) =>
themeName === 'skeleton' ? 'dark' : themeName + '-dark'
);

export { lightThemes, darkThemes };
2 changes: 2 additions & 0 deletions packages/svelte-ux/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import { settings } from '$lib/components/settings';
import type { PageData } from './$types';
import { DateToken } from '$lib/utils/date';
import { lightThemes, darkThemes } from '$lib/styles/daisy';
// import { lightThemes, darkThemes } from '$lib/styles/skeleton';
export let data: PageData;
Expand Down
7 changes: 5 additions & 2 deletions packages/svelte-ux/tailwind.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ const plugin = require('tailwindcss/plugin');
const colors = require('tailwindcss/colors');

const svelteUx = require('./src/lib/plugins/tailwind.cjs');
const { themes } = require('./src/lib/styles/daisy.cjs');

const { themes: daisyThemes } = require('./src/lib/styles/daisy.cjs');
// const { themes: skeletonThemes } = require('./src/lib/styles/skeleton.cjs');

module.exports = {
content: ['./src/**/*.{html,svelte,md,ts,js}'],
ux: {
themes,
themes: daisyThemes,
// themes: skeletonThemes,
// themes: {
// light: {
// primary: colors['blue']['500'],
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f3762c8

Please sign in to comment.