Theme
This commit is contained in:
parent
adf31c79d7
commit
7d8a9356e2
7 changed files with 194 additions and 9 deletions
|
|
@ -5,16 +5,16 @@ export default (node, props) => {
|
|||
});
|
||||
|
||||
return {
|
||||
update(new_props) {
|
||||
Object.entries(new_props).forEach(([key, value]) => {
|
||||
update(newProps) {
|
||||
Object.entries(newProps).forEach(([key, value]) => {
|
||||
node.style.setProperty(`--${key}`, value);
|
||||
delete props[key];
|
||||
});
|
||||
|
||||
Object.keys(props).forEach(name =>
|
||||
node.style.removeProperty(`--${name}`),
|
||||
);
|
||||
props = new_props;
|
||||
Object.keys(props).forEach((name) => {
|
||||
node.style.removeProperty(`--${name}`);
|
||||
});
|
||||
props = newProps;
|
||||
},
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,6 @@ You can use `GraphicBlock` with components created by [ai2svelte](https://github
|
|||
notes="Note: A shakemap represents the ground shaking produced by an earthquake."
|
||||
ariaDescription="A map showing shake intensity of the quake."
|
||||
>
|
||||
<MyAiMap basePath={assets} />
|
||||
<MyAiMap assetsPath={assets} />
|
||||
</GraphicBlock>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ The `ariaDescription` string will be processed as markdown, so you can add multi
|
|||
notes="Note: A shakemap represents the ground shaking produced by an earthquake."
|
||||
ariaDescription="A map showing the shake intensity produced by the earthquake."
|
||||
>
|
||||
<MyAiMap basePath={assets} />
|
||||
<MyAiMap assetsPath={assets} />
|
||||
</GraphicBlock>
|
||||
```
|
||||
|
||||
|
|
|
|||
100
src/components/Theme/Theme.stories.svelte
Normal file
100
src/components/Theme/Theme.stories.svelte
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<script>
|
||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||
|
||||
// @ts-ignore
|
||||
import componentDocs from './stories/docs/component.md?raw';
|
||||
|
||||
import Theme, { themes } from './Theme.svelte';
|
||||
|
||||
import {
|
||||
withComponentDocs
|
||||
} from '$lib/docs/utils/withParams.js';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Theme',
|
||||
component: Theme,
|
||||
...withComponentDocs(componentDocs),
|
||||
argTypes: {
|
||||
styles: {
|
||||
options: Object.keys(themes), // An array of serializable values
|
||||
mapping: themes, // Maps serializable option values to complex arg values
|
||||
control: {
|
||||
type: 'select', // Type 'select' is automatically inferred when 'options' is defined
|
||||
labels: {
|
||||
// 'labels' maps option values to string labels
|
||||
main: 'Main',
|
||||
dark: 'Dark',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<Meta {...meta} />
|
||||
|
||||
<Template let:args>
|
||||
<Theme {...args}>
|
||||
<div class="themed">
|
||||
<p>My theme</p>
|
||||
</div>
|
||||
</Theme>
|
||||
</Template>
|
||||
|
||||
<Story
|
||||
name="Default"
|
||||
args={{
|
||||
styles: themes.main,
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="Inheritance"
|
||||
args={{
|
||||
styles: themes.main,
|
||||
}}
|
||||
>
|
||||
<Theme styles={themes.main}>
|
||||
<div class="themed">
|
||||
<p>My theme</p>
|
||||
<Theme styles={themes.dark}>
|
||||
<div class="themed">
|
||||
<p>My sub-theme</p>
|
||||
<Theme styles={themes.main}>
|
||||
<div class="themed">
|
||||
<p>My sub-sub-theme</p>
|
||||
</div>
|
||||
</Theme>
|
||||
<Theme styles={{ colour: { background: 'steelblue', primary: '#fff' } }}>
|
||||
<div class="themed">
|
||||
<p>My other sub-sub-theme</p>
|
||||
</div>
|
||||
</Theme>
|
||||
</div>
|
||||
</Theme>
|
||||
</div>
|
||||
</Theme>
|
||||
</Story>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../scss/mixins/fonts";
|
||||
div.themed {
|
||||
background-color: var(--theme-colour-background);
|
||||
padding: 2rem;
|
||||
width: 80%;
|
||||
margin: 1rem auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-flow: column;
|
||||
border: 1px solid var(--theme-colour-primary);
|
||||
border-radius: 20px;
|
||||
p {
|
||||
@include font-display;
|
||||
color: var(--theme-colour-primary);
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
42
src/components/Theme/Theme.svelte
Normal file
42
src/components/Theme/Theme.svelte
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<script context="module" lang="ts">
|
||||
const main = {
|
||||
colour: {
|
||||
background: '#ffffff',
|
||||
primary: '#333333',
|
||||
},
|
||||
};
|
||||
const dark = {
|
||||
colour: {
|
||||
background: '#333333',
|
||||
primary: '#ffffff',
|
||||
},
|
||||
};
|
||||
|
||||
export const themes = {
|
||||
main,
|
||||
dark,
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let styles: object = main;
|
||||
export let name: string = 'theme';
|
||||
|
||||
import cssVariables from '../../actions/cssVariables';
|
||||
import flatten from './utils/flatten';
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="theme theme-{name}"
|
||||
style="display: contents;"
|
||||
use:cssVariables={flatten({ [name]: styles })}
|
||||
>
|
||||
<!-- Clients can override the theme above by attaching custom properties to this element. -->
|
||||
<div
|
||||
class="theme-client-override theme-{name}"
|
||||
style="display: contents;"
|
||||
>
|
||||
<!-- Themed content -->
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
3
src/components/Theme/stories/docs/component.md
Normal file
3
src/components/Theme/stories/docs/component.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
> ⏳ Coming soon!
|
||||
|
||||
Set a theme for your page.
|
||||
40
src/components/Theme/utils/flatten.js
Normal file
40
src/components/Theme/utils/flatten.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
function isBuffer(obj) {
|
||||
return obj &&
|
||||
obj.constructor &&
|
||||
(typeof obj.constructor.isBuffer === 'function') &&
|
||||
obj.constructor.isBuffer(obj);
|
||||
}
|
||||
|
||||
const transformKey = (key) => key.replace(/[^a-z0-9-]/gi, '');
|
||||
|
||||
export default function flatten(target) {
|
||||
const delimiter = '-';
|
||||
const output = {};
|
||||
|
||||
function step(object, prev, currentDepth = 1) {
|
||||
Object.keys(object).forEach(function(key) {
|
||||
const value = object[key];
|
||||
const isArray = Array.isArray(value);
|
||||
const type = Object.prototype.toString.call(value);
|
||||
const isbuffer = isBuffer(value);
|
||||
const isObject = (
|
||||
type === '[object Object]' ||
|
||||
type === '[object Array]'
|
||||
);
|
||||
|
||||
const newKey = prev ?
|
||||
prev + delimiter + transformKey(key) :
|
||||
transformKey(key);
|
||||
|
||||
if (!isArray && !isbuffer && isObject && Object.keys(value).length) {
|
||||
return step(value, newKey, currentDepth + 1);
|
||||
}
|
||||
|
||||
output[newKey] = value;
|
||||
});
|
||||
}
|
||||
|
||||
step(target);
|
||||
|
||||
return output;
|
||||
}
|
||||
Loading…
Reference in a new issue