mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
Improve theme remixing UI (#724)
Co-authored-by: lindsaym-fa <dev@lindsaym.design> Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
|
||||
{# Docs styles #}
|
||||
<link rel="stylesheet" href="/assets/styles/docs.css" />
|
||||
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body class="layout-{{ layout | stripExtension }}{{ ' page-wide' if wide }}">
|
||||
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" %}
|
||||
</div>
|
||||
<span class="page-name">{{ page.data.title }}</span>
|
||||
{% if pageSubtitle -%}
|
||||
<div class="wa-caption-s">{{ pageSubtitle }}</div>
|
||||
{%- endif %}
|
||||
</wa-card>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% set paletteId = page.fileSlug %}
|
||||
{% set paletteId = palette.fileSlug or page.fileSlug %}
|
||||
{% set tints = [80, 60, 40, 20] %}
|
||||
{% set width = 20 %}
|
||||
{% set height = 13 %}
|
||||
|
||||
24
docs/_includes/svgs/theme-color.njk
Normal file
24
docs/_includes/svgs/theme-color.njk
Normal file
@@ -0,0 +1,24 @@
|
||||
{% set themeId = theme.fileSlug %}
|
||||
|
||||
<div>
|
||||
<template shadowrootmode="open">
|
||||
<link rel="stylesheet" href="/dist/styles/utilities.css">
|
||||
<link rel="stylesheet" href="/dist/styles/themes/{{ page.fileSlug or 'default' }}.css">
|
||||
<link rel="stylesheet" href="/dist/styles/themes/{{ themeId }}/color.css">
|
||||
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
|
||||
|
||||
<div class="theme-color-icon wa-theme-{{ themeId }}">
|
||||
<div class="wa-brand wa-accent">A</div>
|
||||
<div class="wa-brand wa-outlined">A</div>
|
||||
<div class="wa-brand wa-filled">A</div>
|
||||
<div class="wa-brand wa-plain">A</div>
|
||||
{# <div class="wa-danger wa-outlined wa-filled"><wa-icon slot="icon" name="circle-exclamation" variant="regular"></wa-icon></div> #}
|
||||
|
||||
<div class="wa-neutral wa-accent">A</div>
|
||||
<div class="wa-neutral wa-outlined">A</div>
|
||||
<div class="wa-neutral wa-filled">A</div>
|
||||
<div class="wa-neutral wa-plain">A</div>
|
||||
{# <div class="wa-warning wa-outlined wa-filled"><wa-icon slot="icon" name="triangle-exclamation" variant="regular"></wa-icon></div> #}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
16
docs/_includes/svgs/theme-typography.njk
Normal file
16
docs/_includes/svgs/theme-typography.njk
Normal file
@@ -0,0 +1,16 @@
|
||||
{% set themeId = theme.fileSlug %}
|
||||
|
||||
<div>
|
||||
<template shadowrootmode="open">
|
||||
<link rel="stylesheet" href="/dist/styles/native/content.css">
|
||||
<link rel="stylesheet" href="/dist/styles/native/blockquote.css">
|
||||
<link rel="stylesheet" href="/dist/styles/themes/{{ page.fileSlug or 'default' }}.css">
|
||||
<link rel="stylesheet" href="/dist/styles/themes/{{ themeId }}/typography.css">
|
||||
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
|
||||
|
||||
<div class="theme-typography-icon wa-theme-{{ themeId }}" data-no-outline data-no-anchor role="presentation">
|
||||
<h3>Title</h3>
|
||||
<p>Body text</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -4,72 +4,131 @@
|
||||
|
||||
{% extends '../_includes/base.njk' %}
|
||||
|
||||
{% block head %}
|
||||
<script>
|
||||
globalThis.wa_data ??= {};
|
||||
wa_data.baseTheme = "{{ page.fileSlug }}";
|
||||
wa_data.themes = {
|
||||
{% for theme in collections.theme -%}
|
||||
"{{ theme.fileSlug }}": {
|
||||
"title": "{{ theme.data.title }}",
|
||||
"palette": "{{ theme.data.palette }}",
|
||||
"brand": "{{ theme.data.brand }}"
|
||||
},
|
||||
{% endfor %}
|
||||
};
|
||||
wa_data.palettes = {
|
||||
{% for palette in collections.palette -%}
|
||||
"{{ palette.fileSlug }}": {
|
||||
"title": "{{ palette.data.title }}",
|
||||
},
|
||||
{% endfor %}
|
||||
};
|
||||
</script>
|
||||
<link href="{{ page.url }}../remix.css" rel="stylesheet">
|
||||
<script src="{{ page.url }}../remix.js" type="module"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
|
||||
<iframe src='{{ page.url }}demo.html' id="demo"></iframe>
|
||||
|
||||
<p id="mix_and_match" class="wa-gap-m">
|
||||
<strong>
|
||||
<wa-icon name="merge" slot="prefix"></wa-icon>
|
||||
<wa-details id="mix_and_match" class="wa-gap-m" >
|
||||
<h4 slot="summary" data-no-anchor data-no-outline>
|
||||
<wa-icon name="arrows-rotate"></wa-icon>
|
||||
Remix
|
||||
<wa-icon-button href="#remixing" name="circle-question" slot="suffix" variant="regular" label="How to use?"></wa-icon-button>
|
||||
</strong>
|
||||
<wa-select name="colors" label="Colors from…" size="small">
|
||||
<wa-icon id="what-is-remixing" href="#remixing" name="circle-question" slot="suffix" variant="regular"></wa-icon>
|
||||
<wa-tooltip for="what-is-remixing">Customize this theme by changing its colors and/or remixing it with design elements from other themes!</wa-tooltip>
|
||||
</h4>
|
||||
|
||||
<wa-select name="colors" label="Colors from…" value="" clearable>
|
||||
<wa-icon name="palette" slot="prefix" variant="regular"></wa-icon>
|
||||
<wa-option value="">(Theme default)</wa-option>
|
||||
<wa-divider></wa-divider>
|
||||
{% for theme in collections.theme | sort %}
|
||||
{% if theme.fileSlug !== page.fileSlug %}
|
||||
<wa-option value="{{ theme.fileSlug }}">{{ theme.data.title }}</wa-option>
|
||||
{% endif %}
|
||||
{% set currentTheme = theme.fileSlug == page.fileSlug %}
|
||||
<wa-option label="{{ theme.data.title }}" value="{{ theme.fileSlug if not currentTheme }}" {{ (theme.fileSlug if currentTheme) | attr('data-id') }}>
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theme-color.njk" %}
|
||||
</div>
|
||||
<span class="page-name">
|
||||
{{ theme.data.title }}
|
||||
{% if theme.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
|
||||
{% if currentTheme %}<wa-badge variant="neutral" appearance="outlined">This theme</wa-badge>{% endif %}
|
||||
</span>
|
||||
</wa-card>
|
||||
</wa-option>
|
||||
{% endfor %}
|
||||
</wa-select>
|
||||
|
||||
<wa-select name="palette" label="Palette" size="small">
|
||||
<wa-select name="palette" label="Palette" clearable>
|
||||
<wa-icon name="swatchbook" slot="prefix" variant="regular"></wa-icon>
|
||||
<wa-option value="">(Theme default)</wa-option>
|
||||
<wa-divider></wa-divider>
|
||||
{% for p in collections.palette | sort %}
|
||||
{% if p.fileSlug !== palette %}
|
||||
<wa-option value="{{ p.fileSlug }}">{{ p.data.title }}</wa-option>
|
||||
{% endif %}
|
||||
{% set defaultPalette = palette %}
|
||||
{% for palette in collections.palette | sort %}
|
||||
{% set currentPalette = palette.fileSlug == defaultPalette %}
|
||||
<wa-option label="{{ palette.data.title }}" value="{{ palette.fileSlug if not currentPalette }}" {{ (palette.fileSlug if currentPalette) | attr('data-id') }}>
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/" + (palette.data.icon or "thumbnail-placeholder") + ".njk" %}
|
||||
</div>
|
||||
<span class="page-name">
|
||||
{{ palette.data.title }}
|
||||
{% if palette.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
|
||||
{% if currentPalette %}<wa-badge variant="neutral" appearance="outlined">Theme default</wa-badge>{% endif %}
|
||||
</span>
|
||||
</wa-card>
|
||||
</wa-option>
|
||||
{% endfor %}
|
||||
{% set palette = defaultPalette %}
|
||||
</wa-select>
|
||||
|
||||
<wa-select name="brand" label="Brand color" value="" clearable>
|
||||
<div class="selected-swatch" slot="prefix"></div>
|
||||
{% for hue in hues %}
|
||||
{% set currentBrand = hue == brand %}
|
||||
<wa-option label="{{ hue | capitalize }}" value="{{ hue if not currentBrand }}" {{ (hue if currentBrand) | attr('data-id') }} style="--color: var(--wa-color-{{ hue }})">
|
||||
{{ hue | capitalize }}
|
||||
{% if currentBrand %}<wa-badge variant="neutral" appearance="outlined">Theme default</wa-badge>{% endif %}
|
||||
</wa-option>
|
||||
{% endfor %}
|
||||
</wa-select>
|
||||
|
||||
<wa-select name="typography" label="Typography from…" size="small">
|
||||
<wa-select name="typography" label="Typography from…" clearable>
|
||||
<wa-icon name="font-case" slot="prefix"></wa-icon>
|
||||
<wa-option value="">(Theme default)</wa-option>
|
||||
<wa-divider></wa-divider>
|
||||
{% for theme in collections.theme | sort %}
|
||||
{% if theme.fileSlug !== page.fileSlug %}
|
||||
<wa-option value="{{ theme.fileSlug }}">{{ theme.data.title }}</wa-option>
|
||||
{% endif %}
|
||||
{% set currentTheme = theme.fileSlug == page.fileSlug %}
|
||||
<wa-option label="{{ theme.data.title }}" value="{{ theme.fileSlug if not currentTheme }}" {{ (theme.fileSlug if currentTheme) | attr('data-id') }}>
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theme-typography.njk" %}
|
||||
</div>
|
||||
<span class="page-name">
|
||||
{{ theme.data.title }}
|
||||
{% if theme.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
|
||||
{% if currentTheme %}<wa-badge variant="neutral" appearance="outlined">This theme</wa-badge>{% endif %}
|
||||
</span>
|
||||
</wa-card>
|
||||
</wa-option>
|
||||
{% endfor %}
|
||||
</wa-select>
|
||||
</wa-details>
|
||||
|
||||
|
||||
</p>
|
||||
<script>
|
||||
document.querySelector('#mix_and_match').addEventListener('change', function(event) {
|
||||
let selects = document.querySelectorAll('#mix_and_match wa-select');
|
||||
let url = new URL(demo.src);
|
||||
|
||||
for (let select of selects) {
|
||||
url.searchParams.set(select.name, select.value);
|
||||
}
|
||||
|
||||
demo.src = url;
|
||||
});
|
||||
</script>
|
||||
|
||||
<h2>Default Color Palette</h2>
|
||||
<h2>Color</h2>
|
||||
{% set paletteURL = '/docs/palettes/' + palette + '/' %}
|
||||
{% set themePage = page %}
|
||||
{% set page = paletteURL | getCollectionItemFromUrl %}
|
||||
<div class="index-grid">
|
||||
{% include 'page-card.njk' %}
|
||||
</div>
|
||||
{% set page = themePage %}
|
||||
|
||||
|
||||
<div class="index-grid">
|
||||
{% set themePage = page %}
|
||||
{% set page = paletteURL | getCollectionItemFromUrl %}
|
||||
{% set pageSubtitle = "Default color palette" %}
|
||||
{% include 'page-card.njk' %}
|
||||
{% set page = themePage %}
|
||||
|
||||
<wa-card style="--header-background: var(--wa-color-{{ brand }})" class="wa-palette-{{ palette }}">
|
||||
<div slot="header"></div>
|
||||
<div class="page-name">{{ brand | capitalize }}</div>
|
||||
<div class="wa-caption-s">Default brand color</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block afterContent %}
|
||||
|
||||
@@ -360,7 +360,7 @@ wa-page > main:has(> .index-grid) {
|
||||
}
|
||||
|
||||
&::part(header) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
background-color: var(--header-background, var(--wa-color-neutral-fill-quiet));
|
||||
border-bottom: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -543,23 +543,4 @@ table.colors {
|
||||
height: 65vh;
|
||||
max-height: 21lh;
|
||||
}
|
||||
|
||||
#mix_and_match {
|
||||
strong {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--wa-space-2xs);
|
||||
margin-top: 1.2em;
|
||||
}
|
||||
|
||||
wa-select::part(label) {
|
||||
margin-block-end: 0;
|
||||
}
|
||||
|
||||
wa-select[value='']::part(display-input),
|
||||
wa-option[value=''] {
|
||||
font-style: italic;
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
docs/assets/styles/theme-icons.css
Normal file
34
docs/assets/styles/theme-icons.css
Normal file
@@ -0,0 +1,34 @@
|
||||
.theme-color-icon {
|
||||
display: grid;
|
||||
gap: var(--wa-space-xs);
|
||||
grid-template-columns: repeat(4, auto);
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background-color: var(--background-color);
|
||||
border: var(--wa-border-width-s) var(--wa-border-style) var(--border-color);
|
||||
padding: var(--wa-space-2xs) var(--wa-space-xs);
|
||||
color: var(--text-color);
|
||||
font-weight: var(--wa-font-weight-semibold);
|
||||
|
||||
&.plain {
|
||||
font-weight: var(--wa-font-weight-bold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-typography-icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--wa-space-xs);
|
||||
|
||||
h3,
|
||||
p {
|
||||
margin-block: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
"tags": ["palettes", "palette"],
|
||||
"eleventyComputed": {
|
||||
"snippet": ".wa-palette-{{ page.fileSlug }}",
|
||||
"icon": "palette"
|
||||
"icon": "palette",
|
||||
"file": "styles/color/{{ page.fileSlug }}.css"
|
||||
}
|
||||
}
|
||||
|
||||
1
docs/docs/themes/active.md
vendored
1
docs/docs/themes/active.md
vendored
@@ -4,4 +4,5 @@ description: Energetic and tactile, always in motion.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: rudimentary
|
||||
brand: green
|
||||
---
|
||||
|
||||
1
docs/docs/themes/awesome.md
vendored
1
docs/docs/themes/awesome.md
vendored
@@ -3,4 +3,5 @@ title: Awesome
|
||||
description: Punchy and vibrant, the rockstar of themes.
|
||||
order: 0.2
|
||||
palette: bright
|
||||
brand: blue
|
||||
---
|
||||
|
||||
1
docs/docs/themes/brutalist.md
vendored
1
docs/docs/themes/brutalist.md
vendored
@@ -4,4 +4,5 @@ description: Sharp, square, and unapologetically bold.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: default
|
||||
brand: blue
|
||||
---
|
||||
|
||||
1
docs/docs/themes/default.md
vendored
1
docs/docs/themes/default.md
vendored
@@ -3,4 +3,5 @@ title: Default
|
||||
description: Your trusty companion, like a perfectly broken-in pair of jeans.
|
||||
order: 0
|
||||
palette: default
|
||||
brand: blue
|
||||
---
|
||||
|
||||
6
docs/docs/themes/demo.njk
vendored
6
docs/docs/themes/demo.njk
vendored
@@ -41,11 +41,13 @@ function updateTheme() {
|
||||
const stylesheetURLs = {
|
||||
colors: id => `/dist/styles/themes/${ id }/color.css`,
|
||||
palette: id => `/dist/styles/color/${ id }.css`,
|
||||
brand: id => `/dist/styles/brand/${ id }.css`,
|
||||
typography: id => `/dist/styles/themes/${ id }/typography.css`
|
||||
};
|
||||
const icons = {
|
||||
colors: 'palette',
|
||||
palette: 'swatchbook',
|
||||
brand: 'droplet',
|
||||
typography: 'font-case'
|
||||
}
|
||||
|
||||
@@ -58,7 +60,7 @@ function updateTheme() {
|
||||
for (let name in stylesheetURLs) {
|
||||
if (params.get(name)) {
|
||||
let url = stylesheetURLs[name](params.get(name));
|
||||
script.insertAdjacentHTML('afterend', `<link rel="stylesheet" href="${ url }" class="mix-and-match" />`);
|
||||
script.insertAdjacentHTML('beforebegin', `<link rel="stylesheet" href="${ url }" class="mix-and-match" />`);
|
||||
let docsURL = (name === 'palette' ? '/docs/palettes/' : '/docs/themes/') + params.get(name) + '/';
|
||||
let title = params.get(name).replace(/^[a-z]/g, c => c.toUpperCase());
|
||||
let icon = icons[name];
|
||||
@@ -70,7 +72,7 @@ function updateTheme() {
|
||||
p.hidden = msgs.length === 0;
|
||||
if (msgs.length) {
|
||||
let icon =
|
||||
p.innerHTML = `<strong><wa-icon name="merge"></wa-icon> Remixed</strong> ` + msgs.map(msg => `<wa-badge appearance=outlined>
|
||||
p.innerHTML = `<strong><wa-icon name="arrows-rotate"></wa-icon> Remixed</strong> ` + msgs.map(msg => `<wa-badge appearance=outlined>
|
||||
${ msg }</wa-badge>`).join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
1
docs/docs/themes/glossy.md
vendored
1
docs/docs/themes/glossy.md
vendored
@@ -4,4 +4,5 @@ description: Bustling with plenty of luster and shine.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: elegant
|
||||
brand: indigo
|
||||
---
|
||||
|
||||
1
docs/docs/themes/matter.md
vendored
1
docs/docs/themes/matter.md
vendored
@@ -4,6 +4,7 @@ description: Digital design inspired by the real world.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: mild
|
||||
brand: indigo
|
||||
---
|
||||
|
||||
Set the page theme to "{{ title }}" from the top right to preview the following examples.
|
||||
|
||||
1
docs/docs/themes/playful.md
vendored
1
docs/docs/themes/playful.md
vendored
@@ -4,4 +4,5 @@ description: Cheerful and engaging, like a playground on screen.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: rudimentary
|
||||
brand: purple
|
||||
---
|
||||
|
||||
1
docs/docs/themes/premium.md
vendored
1
docs/docs/themes/premium.md
vendored
@@ -4,4 +4,5 @@ description: The ultimate in sophistication and style.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: anodized
|
||||
brand: cyan
|
||||
---
|
||||
|
||||
127
docs/docs/themes/remix.css
vendored
Normal file
127
docs/docs/themes/remix.css
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
#mix_and_match {
|
||||
margin-block-end: var(--wa-space-2xl);
|
||||
|
||||
&::part(content) {
|
||||
display: flex;
|
||||
gap: var(--wa-space-xl);
|
||||
padding-block-start: var(--wa-space-m);
|
||||
}
|
||||
|
||||
> [slot='summary'] {
|
||||
margin: 0;
|
||||
|
||||
wa-icon:first-of-type {
|
||||
vertical-align: -0.15em;
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
wa-icon#what-is-remixing {
|
||||
vertical-align: -0.1em;
|
||||
font-size: var(--wa-font-size-s);
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
}
|
||||
|
||||
wa-select {
|
||||
&::part(label) {
|
||||
margin-block-end: 0;
|
||||
}
|
||||
}
|
||||
|
||||
wa-select:has(> wa-option > wa-card) {
|
||||
&::part(listbox) {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
width: min(90vw, 800px);
|
||||
}
|
||||
|
||||
&:state(blank)::part(display-input) {
|
||||
font-style: italic;
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
}
|
||||
|
||||
wa-option:has(> wa-card) {
|
||||
position: relative;
|
||||
padding: var(--wa-space-smaller);
|
||||
|
||||
&::part(checked-icon) {
|
||||
position: absolute;
|
||||
inset-block-start: calc(var(--wa-space-smaller) - 0.5em);
|
||||
inset-inline-end: calc(var(--wa-space-smaller) - 0.5em);
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
padding: 0.4em;
|
||||
border-radius: var(--wa-border-radius-circle);
|
||||
text-align: center;
|
||||
background: var(--wa-color-brand-fill-loud);
|
||||
color: var(--wa-color-brand-on-loud);
|
||||
font-size: var(--wa-font-size-xs);
|
||||
}
|
||||
|
||||
wa-card {
|
||||
--spacing: var(--wa-space-smaller);
|
||||
|
||||
&::part(body) {
|
||||
background: var(--wa-color-neutral-fill-quiet);
|
||||
padding-block: var(--wa-space-s);
|
||||
}
|
||||
}
|
||||
|
||||
&:state(current),
|
||||
&:state(hover),
|
||||
&:state(selected),
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
wa-card {
|
||||
border-color: var(--wa-color-brand-border-loud);
|
||||
box-shadow: 0 0 0 var(--wa-border-width-m) var(--wa-color-brand-border-normal);
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-selected='true'] {
|
||||
wa-card {
|
||||
--border-color: var(--wa-color-brand-border-loud);
|
||||
box-shadow: 0 0 0 var(--wa-border-width-m) var(--wa-color-brand-border-loud);
|
||||
|
||||
&::part(body) {
|
||||
background: var(--wa-color-brand-fill-quiet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selected-swatch,
|
||||
wa-select[name='brand'] wa-option::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 1.2em;
|
||||
aspect-ratio: 1;
|
||||
flex: none;
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background: var(--color);
|
||||
border: 1px solid var(--wa-color-surface-default);
|
||||
}
|
||||
|
||||
wa-select[name='brand'] wa-option {
|
||||
white-space: nowrap;
|
||||
|
||||
&::before {
|
||||
width: 1em;
|
||||
margin-inline: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
&::part(checked-icon) {
|
||||
order: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#test_select wa-option:state(selected) {
|
||||
outline: 2px solid red;
|
||||
background: yellow;
|
||||
}
|
||||
146
docs/docs/themes/remix.js
vendored
Normal file
146
docs/docs/themes/remix.js
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
await Promise.all(['wa-select', 'wa-option', 'wa-details'].map(tag => customElements.whenDefined(tag)));
|
||||
const domChange = document.startViewTransition ? document.startViewTransition.bind(document) : fn => fn();
|
||||
|
||||
let selects, data;
|
||||
|
||||
let computed = {
|
||||
get isRemixed() {
|
||||
return Object.values(data.params).filter(Boolean).length > 0;
|
||||
},
|
||||
get palette() {
|
||||
return data.params.palette || data.defaultParams.palette;
|
||||
},
|
||||
get brand() {
|
||||
return data.params.brand || data.defaultParams.brand;
|
||||
},
|
||||
};
|
||||
|
||||
function selectsChanged(event) {
|
||||
data.params[event.target.name] = event.target.value;
|
||||
render(event.target.name);
|
||||
}
|
||||
|
||||
function init() {
|
||||
selects = Object.fromEntries(
|
||||
[...document.querySelectorAll('#mix_and_match wa-select')].map(select => [select.getAttribute('name'), select]),
|
||||
);
|
||||
|
||||
data = {
|
||||
baseTheme: wa_data.baseTheme,
|
||||
themes: wa_data.themes,
|
||||
palettes: wa_data.palettes,
|
||||
defaultParams: {
|
||||
colors: '',
|
||||
get palette() {
|
||||
let colors = data.params.colors || data.baseTheme;
|
||||
return data.themes[colors].palette;
|
||||
},
|
||||
get brand() {
|
||||
let colors = data.params.colors || data.baseTheme;
|
||||
return data.themes[colors].brand;
|
||||
},
|
||||
typography: '',
|
||||
},
|
||||
params: { colors: '', palette: '', brand: '', typography: '' },
|
||||
urlParams: new URLSearchParams(location.search),
|
||||
};
|
||||
|
||||
// Read URL params and apply them. This facilitates permalinks.
|
||||
if (location.search) {
|
||||
for (let aspect in data.params) {
|
||||
if (data.urlParams.has(aspect)) {
|
||||
data.params[aspect] = data.urlParams.get(aspect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (computed.isRemixed) {
|
||||
// Start with the remixing UI open if the theme has been remixed
|
||||
mix_and_match.setAttribute('open', '');
|
||||
mix_and_match.open = true;
|
||||
}
|
||||
|
||||
for (let name in selects) {
|
||||
selects[name].addEventListener('change', selectsChanged);
|
||||
}
|
||||
|
||||
Promise.all(Object.values(selects).map(select => select.updateComplete)).then(() => render());
|
||||
|
||||
return { selects, data, computed, render };
|
||||
}
|
||||
|
||||
globalThis.remixApp = init();
|
||||
|
||||
// Async load CSS for other themes *before* current theme stylesheet
|
||||
let themeStylesheet = document.querySelector('#theme-stylesheet');
|
||||
|
||||
for (const theme in data.themes) {
|
||||
themeStylesheet.insertAdjacentHTML(
|
||||
'beforebegin',
|
||||
`<link rel="preload" as="style" href="/dist/styles/themes/${theme}/color.css" onload="this.rel = 'stylesheet'" />
|
||||
<link rel="preload" as="style" href="/dist/styles/themes/${theme}/typography.css" onload="this.rel = 'stylesheet'" />`,
|
||||
);
|
||||
}
|
||||
|
||||
for (const palette in data.palettes) {
|
||||
themeStylesheet.insertAdjacentHTML(
|
||||
'beforebegin',
|
||||
`<link rel="preload" as="style" href="/dist/styles/color/${palette}.css" onload="this.rel = 'stylesheet'" />`,
|
||||
);
|
||||
}
|
||||
|
||||
function setDefault(select, value) {
|
||||
let oldDefaultOption = select.querySelector(`wa-option[value=""]:not([data-id="${value}"])`);
|
||||
let newDefaultOption = select.querySelector(`wa-option[value="${value}"]`);
|
||||
|
||||
if (oldDefaultOption) {
|
||||
oldDefaultOption.value = oldDefaultOption.dataset.id;
|
||||
}
|
||||
|
||||
if (newDefaultOption) {
|
||||
newDefaultOption.dataset.id ??= newDefaultOption.value;
|
||||
newDefaultOption.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
function render(changedAspect) {
|
||||
let url = new URL(demo.src);
|
||||
|
||||
if (!changedAspect || changedAspect === 'colors') {
|
||||
// Update the default palette when the theme colors change to the default palette of that theme
|
||||
setDefault(selects.palette, data.defaultParams.palette);
|
||||
setDefault(selects.brand, data.defaultParams.brand);
|
||||
}
|
||||
|
||||
let brand = data.params.brand || data.defaultParams.brand;
|
||||
selects.brand.style.setProperty('--color', `var(--wa-color-${brand})`);
|
||||
selects.brand.className = `wa-palette-${computed.palette}`;
|
||||
|
||||
for (let aspect in data.params) {
|
||||
let value = data.params[aspect];
|
||||
|
||||
if (value) {
|
||||
data.urlParams.set(aspect, value);
|
||||
} else {
|
||||
data.urlParams.delete(aspect);
|
||||
}
|
||||
|
||||
selects[aspect].value = value;
|
||||
}
|
||||
|
||||
// Update demo URL
|
||||
domChange(() => {
|
||||
url.search = data.urlParams;
|
||||
demo.src = url;
|
||||
return new Promise(resolve => (demo.onload = resolve));
|
||||
});
|
||||
|
||||
// Update page URL. If there’s already a search, replace it.
|
||||
// We don’t want to clog the user’s history while they iterate
|
||||
let historyAction = location.search ? 'replaceState' : 'pushState';
|
||||
history[historyAction](null, '', `?${data.urlParams}`);
|
||||
}
|
||||
|
||||
addEventListener('turbo:render', event => {
|
||||
remixApp = init();
|
||||
});
|
||||
13
docs/docs/themes/showcase.css
vendored
13
docs/docs/themes/showcase.css
vendored
@@ -14,7 +14,18 @@ body,
|
||||
color: var(--wa-color-text-quiet);
|
||||
|
||||
wa-icon {
|
||||
vertical-align: middle;
|
||||
vertical-align: -0.15em;
|
||||
}
|
||||
|
||||
> strong {
|
||||
margin-inline-end: var(--wa-space-2xs);
|
||||
}
|
||||
|
||||
wa-badge {
|
||||
> a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
docs/docs/themes/tailspin.md
vendored
1
docs/docs/themes/tailspin.md
vendored
@@ -4,4 +4,5 @@ description: Like a bird in flight, guiding you from there to here.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: vogue
|
||||
brand: indigo
|
||||
---
|
||||
|
||||
6
docs/docs/themes/themes.json
vendored
6
docs/docs/themes/themes.json
vendored
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"layout": "theme.njk",
|
||||
"wide": true,
|
||||
"tags": ["themes", "theme"]
|
||||
"tags": ["themes", "theme"],
|
||||
"brand": "blue",
|
||||
"eleventyComputed": {
|
||||
"file": "styles/themes/{{ page.fileSlug }}.css"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,8 @@ export default class WaOption extends WebAwesomeElement {
|
||||
console.error(`Option values cannot include a space. All spaces have been replaced with underscores.`, this);
|
||||
this.value = this.value.replace(/ /g, '_');
|
||||
}
|
||||
|
||||
this.handleDefaultSlotChange();
|
||||
}
|
||||
|
||||
if (changedProperties.has('current')) {
|
||||
|
||||
Reference in New Issue
Block a user