Compare commits
38 Commits
demo-patte
...
konnorroge
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80a13cc754 | ||
|
|
c70dc7f92f | ||
|
|
59660d6458 | ||
|
|
d47bf56493 | ||
|
|
6acb817688 | ||
|
|
772be3f2ec | ||
|
|
32e6664055 | ||
|
|
029624b869 | ||
|
|
c4ccfafccc | ||
|
|
d34352c5a9 | ||
|
|
8e5e039af8 | ||
|
|
d5a6390fcd | ||
|
|
2e725a2d93 | ||
|
|
c139865635 | ||
|
|
f59c544fbe | ||
|
|
28bdcae2c6 | ||
|
|
b1530d0773 | ||
|
|
5feee64425 | ||
|
|
9647259b5f | ||
|
|
84e276ae10 | ||
|
|
4718c3d815 | ||
|
|
aa1bfb0885 | ||
|
|
acf2055768 | ||
|
|
ef4d2fac40 | ||
|
|
b53c1d940a | ||
|
|
edd62490f8 | ||
|
|
96a381d3a3 | ||
|
|
a2a72de2cf | ||
|
|
9a51e69320 | ||
|
|
07be57847d | ||
|
|
0095ca5fe7 | ||
|
|
a1b1d594aa | ||
|
|
531a2f1634 | ||
|
|
cb1c423aea | ||
|
|
93306c99ce | ||
|
|
5f8c69064c | ||
|
|
f51a09ddf0 | ||
|
|
92533c0297 |
2
.github/CODE_OF_CONDUCT.md
vendored
@@ -35,7 +35,7 @@ This Code of Conduct applies within all project spaces, and it also applies when
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at cory@abeautifulsite.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at support@fontawesome.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
|
||||
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
||||
github: [claviska]
|
||||
2
.github/SECURITY.md
vendored
@@ -2,6 +2,6 @@
|
||||
|
||||
We take security issues in Web Awesome very seriously and appreciate your efforts to disclose your findings responsibly.
|
||||
|
||||
To report a security issue, email [cory@fontawesome.com](mailto:cory@abeautifulsite.net) and include "WEB AWESOME SECURITY" in the subject line.
|
||||
To report a security issue, email [support@fontawesome.com](mailto:support@fontawesome.com) and include "WEB AWESOME SECURITY" in the subject line.
|
||||
|
||||
We'll respond as soon as possible and keep you updated throughout the process.
|
||||
|
||||
2
.gitignore
vendored
@@ -5,6 +5,8 @@ package.json
|
||||
package-lock.json
|
||||
dist
|
||||
docs/assets/images/sprite.svg
|
||||
docs/public/pagefind
|
||||
node_modules
|
||||
src/react
|
||||
cdn
|
||||
.astro
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
*.hbs
|
||||
*.mdx
|
||||
.cache
|
||||
.github
|
||||
cspell.json
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Web Awesome
|
||||
|
||||
A forward-thinking library of web components.
|
||||
|
||||
- Works with all frameworks 🧩
|
||||
- Works with CDNs 🚛
|
||||
- Fully customizable with CSS 🎨
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
"cdndir",
|
||||
"chatbubble",
|
||||
"checkmark",
|
||||
"claviska",
|
||||
"Clippy",
|
||||
"codebases",
|
||||
"codepen",
|
||||
@@ -86,7 +85,6 @@
|
||||
"Kool",
|
||||
"labelledby",
|
||||
"Laravel",
|
||||
"LaViska",
|
||||
"linkify",
|
||||
"listbox",
|
||||
"listitem",
|
||||
@@ -173,6 +171,7 @@
|
||||
"valpha",
|
||||
"valuenow",
|
||||
"valuetext",
|
||||
"viewports",
|
||||
"Vuejs",
|
||||
"WCAG",
|
||||
"webawesome",
|
||||
|
||||
4
docs/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"recommendations": ["astro-build.astro-vscode"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
11
docs/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
{% extends "default.njk" %}
|
||||
|
||||
{# Find the component based on the `tag` front matter #}
|
||||
{% set component = getComponent('wa-' + page.fileSlug) %}
|
||||
|
||||
{% block content %}
|
||||
{# Determine the badge variant #}
|
||||
{% if component.status == 'stable' %}
|
||||
{% set badgeVariant = 'brand' %}
|
||||
{% elseif component.status == 'experimental' %}
|
||||
{% set badgeVariant = 'warning' %}
|
||||
{% elseif component.status == 'planned' %}
|
||||
{% set badgeVariant = 'neutral' %}
|
||||
{% elseif component.status == 'deprecated' %}
|
||||
{% set badgeVariant = 'danger' %}
|
||||
{% else %}
|
||||
{% set badgeVariant = 'neutral' %}
|
||||
{% endif %}
|
||||
|
||||
{# Header #}
|
||||
<header class="component-header">
|
||||
<h1>{{ component.name | classNameToComponentName }}</h1>
|
||||
|
||||
<div class="component-header__tag">
|
||||
<code><{{ component.tagName }}> | {{ component.name }}</code>
|
||||
</div>
|
||||
|
||||
<div class="component-header__info">
|
||||
<wa-badge variant="neutral" pill>
|
||||
Since {{component.since or '?' }}
|
||||
</wa-badge>
|
||||
<wa-badge variant="{{ badgeVariant }}" pill style="text-transform: capitalize;">
|
||||
{{ component.status }}
|
||||
</wa-badge>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<p class="component-summary">
|
||||
{% if component.summary %}
|
||||
{{ component.summary | markdownInline | safe }}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{# Markdown content #}
|
||||
{{ content | safe }}
|
||||
|
||||
{# Importing #}
|
||||
<h2>Importing</h2>
|
||||
<p>
|
||||
If you're using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use
|
||||
any of the following snippets to <a href="/getting-started/installation#cherry-picking">cherry pick</a> this component.
|
||||
</p>
|
||||
|
||||
<wa-tab-group>
|
||||
<wa-tab slot="nav" panel="script">Script</wa-tab>
|
||||
<wa-tab slot="nav" panel="import">Import</wa-tab>
|
||||
<wa-tab slot="nav" panel="bundler">Bundler</wa-tab>
|
||||
<wa-tab slot="nav" panel="react">React</wa-tab>
|
||||
|
||||
<wa-tab-panel name="script">
|
||||
<p>
|
||||
To import this component from <a href="https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace">the CDN</a>
|
||||
using a script tag:
|
||||
</p>
|
||||
<pre><code class="language-html"><script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@{{ meta.version }}/{{ meta.cdndir }}/{{ component.path }}"></script></code></pre>
|
||||
</wa-tab-panel>
|
||||
|
||||
<wa-tab-panel name="import">
|
||||
<p>
|
||||
To import this component from <a href="https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace">the CDN</a>
|
||||
using a JavaScript import:
|
||||
</p>
|
||||
<pre><code class="language-js">import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@{{ meta.version }}/{{ meta.cdndir }}/{{ component.path }}';</code></pre>
|
||||
</wa-tab-panel>
|
||||
|
||||
<wa-tab-panel name="bundler">
|
||||
<p>
|
||||
To import this component using <a href="{{ rootUrl('/getting-started/installation#bundling') }}">a bundler</a>:
|
||||
</p>
|
||||
<pre><code class="language-js">import '@shoelace-style/shoelace/{{ meta.npmdir }}/{{ component.path }}';</code></pre>
|
||||
</wa-tab-panel>
|
||||
|
||||
<wa-tab-panel name="react">
|
||||
<p>
|
||||
To import this component as a <a href="/frameworks/react">React component</a>:
|
||||
</p>
|
||||
<pre><code class="language-js">import {{ component.name }} from '@shoelace-style/shoelace/{{ meta.npmdir }}/react/{{ component.tagNameWithoutPrefix }}';</code></pre>
|
||||
</wa-tab-panel>
|
||||
</wa-tab-group>
|
||||
|
||||
{# Slots #}
|
||||
{% if component.slots.length %}
|
||||
<h2>Slots</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for slot in component.slots %}
|
||||
<tr>
|
||||
<td class="nowrap">
|
||||
{% if slot.name %}
|
||||
<code>{{ slot.name }}</code>
|
||||
{% else %}
|
||||
(default)
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ slot.description | markdownInline | safe }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#slots') }}">using slots</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Properties #}
|
||||
{% if component.properties.length %}
|
||||
<h2>Properties</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-reflects">Reflects</th>
|
||||
<th class="table-type">Type</th>
|
||||
<th class="table-default">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for prop in component.properties %}
|
||||
<tr>
|
||||
<td>
|
||||
<code class="nowrap">{{ prop.name }}</code>
|
||||
{% if prop.attribute | length > 0 %}
|
||||
{% if prop.attribute != prop.name %}
|
||||
<br>
|
||||
<wa-tooltip content="This attribute is different from its property">
|
||||
<small>
|
||||
<code class="nowrap">
|
||||
{{ prop.attribute }}
|
||||
</code>
|
||||
</small>
|
||||
</wa-tooltip>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ prop.description | markdownInline | safe }}
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
{% if prop.reflects %}
|
||||
<wa-icon label="yes" name="check" variant="solid"></wa-icon>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if prop.type.text %}
|
||||
<code>{{ prop.type.text | trimPipes | markdownInline | safe }}</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if prop.default %}
|
||||
<code>{{ prop.default | markdownInline | safe }}</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>updateComplete</code></td>
|
||||
<td>
|
||||
A read-only promise that resolves when the component has
|
||||
<a href="/getting-started/usage?#component-rendering-and-updating">finished updating</a>.
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#attributes-and-properties') }}">attributes and properties</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Events #}
|
||||
{% if component.events.length %}
|
||||
<h2>Events</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name" data-flavor="html">Name</th>
|
||||
<th class="table-name" data-flavor="react">React Event</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-event-detail">Event Detail</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in component.events %}
|
||||
<tr>
|
||||
<td data-flavor="html"><code class="nowrap">{{ event.name }}</code></td>
|
||||
<td data-flavor="react"><code class="nowrap">{{ event.reactName }}</code></td>
|
||||
<td>{{ event.description | markdownInline | safe }}</td>
|
||||
<td>
|
||||
{% if event.type.text %}
|
||||
<code>{{ event.type.text | trimPipes }}</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#events') }}">events</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Methods #}
|
||||
{% if component.methods.length %}
|
||||
<h2>Methods</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-arguments">Arguments</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for method in component.methods %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ method.name }}()</code></td>
|
||||
<td>{{ method.description | markdownInline | safe }}</td>
|
||||
<td>
|
||||
{% if method.parameters.length %}
|
||||
<code>
|
||||
{% for param in method.parameters %}
|
||||
{{ param.name }}: {{ param.type.text | trimPipes }}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</code>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#methods') }}">methods</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Custom Properties #}
|
||||
{% if component.cssProperties.length %}
|
||||
<h2>Custom Properties</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
<th class="table-default">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cssProperty in component.cssProperties %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ cssProperty.name }}</code></td>
|
||||
<td>{{ cssProperty.description | markdownInline | safe }}</td>
|
||||
<td>{{ cssProperty.default }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/usage#custom-properties') }}">customizing CSS custom properties</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# CSS Parts #}
|
||||
{% if component.cssParts.length %}
|
||||
<h2>Parts</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cssPart in component.cssParts %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ cssPart.name }}</code></td>
|
||||
<td>{{ cssPart.description | markdownInline | safe }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/customizing/#css-parts') }}">customizing CSS parts</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Animations #}
|
||||
{% if component.animations.length %}
|
||||
<h2>Animations</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-name">Name</th>
|
||||
<th class="table-description">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for animation in component.animations %}
|
||||
<tr>
|
||||
<td class="nowrap"><code>{{ animation.name }}</code></td>
|
||||
<td>{{ animation.description | markdownInline | safe }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><em>Learn more about <a href="{{ rootUrl('/getting-started/customizing#animations') }}">customizing animations</a>.</em></p>
|
||||
{% endif %}
|
||||
|
||||
{# Dependencies #}
|
||||
{% if component.dependencies.length %}
|
||||
<h2>Dependencies</h2>
|
||||
|
||||
<p>This component automatically imports the following dependencies.</p>
|
||||
|
||||
<ul>
|
||||
{% for dependency in component.dependencies %}
|
||||
<li><code><{{ dependency }}></code></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -1,132 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html
|
||||
lang="en"
|
||||
data-layout="{{ layout }}"
|
||||
data-wa-version="{{ meta.version }}"
|
||||
>
|
||||
<head>
|
||||
{# Metadata #}
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="{{ meta.description }}" />
|
||||
<title>{{ meta.title }}</title>
|
||||
|
||||
{# Opt out of Turbo caching #}
|
||||
<meta name="turbo-cache-control">
|
||||
|
||||
{# Stylesheets #}
|
||||
<link rel="stylesheet" href="{{ assetUrl('styles/docs.css') }}" />
|
||||
<link rel="stylesheet" href="{{ assetUrl('styles/code-previews.css') }}" />
|
||||
<link rel="stylesheet" href="{{ assetUrl('styles/search.css') }}" />
|
||||
|
||||
{# Favicons #}
|
||||
<link rel="icon" href="{{ assetUrl('images/favicon.svg') }}" type="image/x-icon" />
|
||||
|
||||
{# Twitter Cards #}
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:creator" content="shoelace_style" />
|
||||
<meta name="twitter:image" content="{{ assetUrl(meta.image, true) }}" />
|
||||
|
||||
{# OpenGraph #}
|
||||
<meta property="og:url" content="{{ rootUrl(page.url, true) }}" />
|
||||
<meta property="og:title" content="{{ meta.title }}" />
|
||||
<meta property="og:description" content="{{ meta.description }}" />
|
||||
<meta property="og:image" content="{{ assetUrl(meta.image, true) }}" />
|
||||
|
||||
{# Web Awesome #}
|
||||
<link rel="stylesheet" href="/dist/themes/applied.css" />
|
||||
<link rel="stylesheet" href="/dist/themes/forms.css" />
|
||||
<link id="theme-stylesheet" rel="stylesheet" href="/dist/themes/default.css" />
|
||||
<link id="color-stylesheet" rel="stylesheet" href="/dist/themes/color_standard.css" />
|
||||
<link id="theme-stylesheet" rel="stylesheet" href="/dist/themes/demo_patterns.css" />
|
||||
<link id="theme-stylesheet" rel="stylesheet" href="/dist/themes/demo_sublayout.css" />
|
||||
<script type="module" src="/dist/autoloader.js"></script>
|
||||
|
||||
{# Set the initial theme and menu states here to prevent flashing #}
|
||||
<script>
|
||||
(() => {
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const theme = localStorage.getItem('theme') || 'auto';
|
||||
document.documentElement.classList.toggle('wa-theme-default-dark', theme === 'dark' || (theme === 'auto' && prefersDark));
|
||||
})();
|
||||
</script>
|
||||
|
||||
{# Web Fonts #}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Assistant:wght@200..800&family=Inter:wght@100..900&family=Lora:wght@400..700&family=Mulish:wght@200..1000&family=Noto+Sans+Display:wght@100..900&family=Noto+Sans+Mono:wght@100..900&family=Noto+Sans:wght@100..900&family=Noto+Serif:wght@100..900&family=Open+Sans:wght@300..800&family=Playfair+Display:wght@400..900&family=Playfair:opsz,wght@5..1200,300;5..1200,400;5..1200,500;5..1200,600&family=Quicksand:wght@300..700&family=Roboto+Flex:opsz,wght@8..144,300;8..144,400;8..144,500;8..144,600&family=Roboto+Mono:wght@300..700&family=Roboto+Serif:opsz,wght@8..144,300;8..144,400;8..144,500;8..144,600&family=Roboto+Slab:wght@300..700&family=Inconsolata:wght@200..900&display=swap" rel="stylesheet">
|
||||
|
||||
{# Turbo + Scroll positioning #}
|
||||
<script src="{{ assetUrl('scripts/turbo.js') }}" type="module"></script>
|
||||
<script src="{{ assetUrl('scripts/docs.js') }}" defer></script>
|
||||
<script src="{{ assetUrl('scripts/code-previews.js') }}" defer></script>
|
||||
<script src="{{ assetUrl('scripts/lunr.js') }}" defer></script>
|
||||
<script src="{{ assetUrl('scripts/search.js') }}" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<a id="skip-to-main" class="wa-visually-hidden" href="#main-content" data-smooth-link="false">
|
||||
Skip to main content
|
||||
</a>
|
||||
|
||||
{# Menu toggle #}
|
||||
<button id="menu-toggle" type="button" aria-label="Menu">
|
||||
<svg width="148" height="148" viewBox="0 0 148 148" xmlns="http://www.w3.org/2000/svg">
|
||||
<g stroke="currentColor" stroke-width="18" fill="none" fill-rule="evenodd" stroke-linecap="round">
|
||||
<path d="M9.5 125.5h129M9.5 74.5h129M9.5 23.5h129"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<aside id="sidebar" data-preserve-scroll>
|
||||
<header>
|
||||
<a href="/">
|
||||
{% include 'logo.njk' %}
|
||||
</a>
|
||||
<div class="sidebar-version">
|
||||
{{ meta.version }}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="sidebar-buttons">
|
||||
<wa-button size="small" class="repo-button repo-button--github" href="https://github.com/shoelace-style/shoelace" target="_blank">
|
||||
<wa-icon slot="prefix" name="github" family="brands"></wa-icon> Code
|
||||
</wa-button>
|
||||
<wa-button size="small" class="repo-button repo-button--star" href="https://github.com/shoelace-style/shoelace/stargazers" target="_blank">
|
||||
<wa-icon slot="prefix" name="star" variant="solid"></wa-icon> Star
|
||||
</wa-button>
|
||||
<wa-button size="small" class="repo-button repo-button--twitter" href="https://twitter.com/shoelace_style" target="_blank">
|
||||
<wa-icon slot="prefix" name="twitter" family="brands"></wa-icon> Follow
|
||||
</wa-button>
|
||||
</div>
|
||||
|
||||
<button class="search-box" type="button" title="Press / to search" aria-label="Search" data-plugin="search">
|
||||
<wa-icon name="search"></wa-icon>
|
||||
<span>Search</span>
|
||||
</button>
|
||||
|
||||
<nav>
|
||||
{% include 'sidebar.njk' %}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
{# Content #}
|
||||
<main>
|
||||
<a id="main-content"></a>
|
||||
<article id="content" class="content{% if toc %} content--with-toc{% endif %}">
|
||||
{% if toc %}
|
||||
<div class="content__toc">
|
||||
<ul>
|
||||
<li class="top"><a href="#">{{ meta.title }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="content__body">
|
||||
{% block content %}
|
||||
{{ content | safe }}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,86 +0,0 @@
|
||||
<ul>
|
||||
<li>
|
||||
<h2>Experimental</h2>
|
||||
<ul>
|
||||
<li><a href="/experimental/kitchen-sink">Theme Builder</a></li>
|
||||
<li><a href="/experimental/style-guide">Style Guide</a></li>
|
||||
<li><a href="/experimental/form-validation">Form Validation Styles</a></li>
|
||||
<li style="margin-top: .5rem;"><wa-switch id="theme-toggle">Dark mode</wa-switch></li>
|
||||
<script type="module">
|
||||
// Temporary dark toggle
|
||||
const toggle = document.getElementById('theme-toggle');
|
||||
toggle.checked = document.documentElement.classList.contains('wa-theme-default-dark');
|
||||
|
||||
toggle.addEventListener('wa-change', () => {
|
||||
document.documentElement.classList.toggle('wa-theme-default-dark');
|
||||
localStorage.setItem('theme', toggle.checked ? 'dark' : 'light');
|
||||
});
|
||||
</script>
|
||||
<li><a href="/experimental/sandbox">Sandbox</a></li>
|
||||
<li><a href="/experimental/patterns">Patterns</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Getting Started</h2>
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/getting-started/installation">Installation</a></li>
|
||||
<li><a href="/getting-started/usage">Usage</a></li>
|
||||
<li><a href="/getting-started/themes">Themes</a></li>
|
||||
<li><a href="/getting-started/customizing">Customizing</a></li>
|
||||
<li><a href="/getting-started/form-controls">Form Controls</a></li>
|
||||
<li><a href="/getting-started/localization">Localization</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Frameworks</h2>
|
||||
<ul>
|
||||
<li><a href="/frameworks/react">React</a></li>
|
||||
<li><a href="/frameworks/vue">Vue</a></li>
|
||||
<li><a href="/frameworks/angular">Angular</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Resources</h2>
|
||||
<ul>
|
||||
<li><a href="/resources/community">Community</a></li>
|
||||
<li><a href="https://github.com/shoelace-style/shoelace/discussions">Help & Support</a></li>
|
||||
<li><a href="/resources/accessibility">Accessibility</a></li>
|
||||
<li><a href="/resources/contributing">Contributing</a></li>
|
||||
<li><a href="/resources/changelog">Changelog</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Components</h2>
|
||||
<ul>
|
||||
{% for component in meta.components %}
|
||||
<li>
|
||||
<a href="/components/{{ component.tagName | removeWaPrefix }}">
|
||||
{{ component.name | classNameToComponentName }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Design Tokens</h2>
|
||||
<ul>
|
||||
<li><a href="/tokens/typography">Typography</a></li>
|
||||
<li><a href="/tokens/color">Color</a></li>
|
||||
<li><a href="/tokens/spacing">Spacing</a></li>
|
||||
<li><a href="/tokens/borders">Borders</a></li>
|
||||
<li><a href="/tokens/shadows">Shadows</a></li>
|
||||
<li><a href="/tokens/transition">Transition</a></li>
|
||||
<li><a href="/tokens/z-index">Z-index</a></li>
|
||||
<li><a href="/tokens/more">More Tokens</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h2>Tutorials</h2>
|
||||
<ul>
|
||||
<li><a href="/tutorials/integrating-with-laravel">Integrating with Laravel</a></li>
|
||||
<li><a href="/tutorials/integrating-with-nextjs">Integrating with NextJS</a></li>
|
||||
<li><a href="/tutorials/integrating-with-rails">Integrating with Rails</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1,35 +0,0 @@
|
||||
function normalizePathname(pathname) {
|
||||
// Remove /index.html
|
||||
if (pathname.endsWith('/index.html')) {
|
||||
pathname = pathname.replace(/\/index\.html/, '');
|
||||
}
|
||||
|
||||
// Remove trailing slashes
|
||||
return pathname.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a class name to links that are currently active.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
className: 'active-link', // the class to add to active links
|
||||
pathname: undefined, // the current pathname to compare
|
||||
within: 'body', // element containing the target links
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
|
||||
if (!within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll('a').forEach(link => {
|
||||
if (normalizePathname(options.pathname) === normalizePathname(link.pathname)) {
|
||||
link.classList.add(options.className);
|
||||
}
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
const { createSlug } = require('./strings.cjs');
|
||||
|
||||
/**
|
||||
* Turns headings into clickable, deep linkable anchors. The provided doc should be a document object provided by JSDOM.
|
||||
* The same document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
levels: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], // the headings to convert
|
||||
className: 'anchor-heading', // the class name to add
|
||||
within: 'body', // the element containing the target headings
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
|
||||
if (!within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
|
||||
const hasAnchor = heading.querySelector('a');
|
||||
const anchor = doc.createElement('a');
|
||||
let id = heading.textContent ?? '';
|
||||
let suffix = 0;
|
||||
|
||||
// Skip heading levels we don't care about
|
||||
if (!options.levels?.includes(heading.tagName.toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert dots to underscores
|
||||
id = id.replace(/\./g, '_');
|
||||
|
||||
// Turn it into a slug
|
||||
id = createSlug(id);
|
||||
|
||||
// Make sure it starts with a letter
|
||||
if (!/^[a-z]/i.test(id)) {
|
||||
id = `id_${id}`;
|
||||
}
|
||||
|
||||
// Make sure the id is unique
|
||||
const originalId = id;
|
||||
while (doc.getElementById(id) !== null) {
|
||||
id = `${originalId}-${++suffix}`;
|
||||
}
|
||||
|
||||
if (hasAnchor || !id) return;
|
||||
|
||||
heading.setAttribute('id', id);
|
||||
anchor.setAttribute('href', `#${encodeURIComponent(id)}`);
|
||||
anchor.setAttribute('aria-label', `Direct link to "${heading.textContent}"`);
|
||||
|
||||
if (options.className) {
|
||||
heading.classList.add(options.className);
|
||||
}
|
||||
|
||||
// Append the anchor
|
||||
heading.append(anchor);
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,138 +0,0 @@
|
||||
let count = 1;
|
||||
|
||||
function escapeHtml(str) {
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns code fields with the :preview suffix into interactive code previews.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
within: 'body', // the element containing the code fields to convert
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
if (!within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll('[class*=":preview"]').forEach(code => {
|
||||
const pre = code.closest('pre');
|
||||
if (!pre) {
|
||||
return;
|
||||
}
|
||||
const adjacentPre = pre.nextElementSibling?.tagName.toLowerCase() === 'pre' ? pre.nextElementSibling : null;
|
||||
const reactCode = adjacentPre?.querySelector('code[class$="react"]');
|
||||
const sourceGroupId = `code-preview-source-group-${count}`;
|
||||
const isExpanded = code.getAttribute('class').includes(':expanded');
|
||||
const noCodePen = code.getAttribute('class').includes(':no-codepen');
|
||||
|
||||
count++;
|
||||
|
||||
const htmlButton = `
|
||||
<button type="button"
|
||||
title="Show HTML code"
|
||||
class="code-preview__button code-preview__button--html"
|
||||
>
|
||||
HTML
|
||||
</button>
|
||||
`;
|
||||
|
||||
const reactButton = `
|
||||
<button type="button" title="Show React code" class="code-preview__button code-preview__button--react">
|
||||
React
|
||||
</button>
|
||||
`;
|
||||
|
||||
const codePenButton = `
|
||||
<button type="button" class="code-preview__button code-preview__button--codepen" title="Edit on CodePen">
|
||||
<svg
|
||||
width="138"
|
||||
height="26"
|
||||
viewBox="0 0 138 26"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M80 6h-9v14h9 M114 6h-9 v14h9 M111 13h-6 M77 13h-6 M122 20V6l11 14V6 M22 16.7L33 24l11-7.3V9.3L33 2L22 9.3V16.7z M44 16.7L33 9.3l-11 7.4 M22 9.3l11 7.3 l11-7.3 M33 2v7.3 M33 16.7V24 M88 14h6c2.2 0 4-1.8 4-4s-1.8-4-4-4h-6v14 M15 8c-1.3-1.3-3-2-5-2c-4 0-7 3-7 7s3 7 7 7 c2 0 3.7-0.8 5-2 M64 13c0 4-3 7-7 7h-5V6h5C61 6 64 9 64 13z" />
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
const codePreview = `
|
||||
<div class="code-preview ${isExpanded ? 'code-preview--expanded' : ''}">
|
||||
<div class="code-preview__preview">
|
||||
${code.textContent}
|
||||
<div class="code-preview__resizer">
|
||||
<wa-icon name="grip-vertical" variant="solid"></wa-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="code-preview__source-group" id="${sourceGroupId}">
|
||||
<div class="code-preview__source code-preview__source--html" ${reactCode ? 'data-flavor="html"' : ''}>
|
||||
<pre><code class="language-html">${escapeHtml(code.textContent)}</code></pre>
|
||||
</div>
|
||||
|
||||
${
|
||||
reactCode
|
||||
? `
|
||||
<div class="code-preview__source code-preview__source--react" data-flavor="react">
|
||||
<pre><code class="language-jsx">${escapeHtml(reactCode.textContent)}</code></pre>
|
||||
</div>
|
||||
`
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="code-preview__buttons">
|
||||
<button
|
||||
type="button"
|
||||
class="code-preview__button code-preview__toggle"
|
||||
aria-expanded="${isExpanded ? 'true' : 'false'}"
|
||||
aria-controls="${sourceGroupId}"
|
||||
>
|
||||
Source
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
${reactCode ? ` ${htmlButton} ${reactButton} ` : ''}
|
||||
|
||||
${noCodePen ? '' : codePenButton}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
pre.insertAdjacentHTML('afterend', codePreview);
|
||||
pre.remove();
|
||||
|
||||
if (adjacentPre) {
|
||||
adjacentPre.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Wrap code preview scripts in anonymous functions so they don't run in the global scope
|
||||
doc.querySelectorAll('.code-preview__preview script').forEach(script => {
|
||||
if (script.type === 'module') {
|
||||
// Modules are already scoped
|
||||
script.textContent = script.innerHTML;
|
||||
} else {
|
||||
// Wrap non-modules in an anonymous function so they don't run in the global scope
|
||||
script.textContent = `(() => { ${script.innerHTML} })();`;
|
||||
}
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
let codeBlockId = 0;
|
||||
|
||||
/**
|
||||
* Adds copy code buttons to code fields. The provided doc should be a document object provided by JSDOM. The same
|
||||
* document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc) {
|
||||
doc.querySelectorAll('pre > code').forEach(code => {
|
||||
const pre = code.closest('pre');
|
||||
const button = doc.createElement('wa-copy-button');
|
||||
|
||||
if (!code.id) {
|
||||
code.id = `code-block-${++codeBlockId}`;
|
||||
}
|
||||
|
||||
button.classList.add('copy-code-button');
|
||||
button.setAttribute('from', code.id);
|
||||
|
||||
pre.append(button);
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
const { isExternalLink } = require('./strings.cjs');
|
||||
|
||||
/**
|
||||
* Transforms external links to make them safer and optionally add a target. The provided doc should be a document
|
||||
* object provided by JSDOM. The same document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
className: 'external-link', // the class name to add to links
|
||||
noopener: true, // sets rel="noopener"
|
||||
noreferrer: true, // sets rel="noreferrer"
|
||||
ignore: () => false, // callback function to filter links that should be ignored
|
||||
within: 'body', // element that contains the target links
|
||||
target: '', // sets the target attribute
|
||||
...options
|
||||
};
|
||||
|
||||
const within = doc.querySelector(options.within);
|
||||
|
||||
if (within) {
|
||||
within.querySelectorAll('a').forEach(link => {
|
||||
if (isExternalLink(link) && !options.ignore(link)) {
|
||||
link.classList.add(options.className);
|
||||
|
||||
const rel = [];
|
||||
if (options.noopener) rel.push('noopener');
|
||||
if (options.noreferrer) rel.push('noreferrer');
|
||||
|
||||
if (rel.length) {
|
||||
link.setAttribute('rel', rel.join(' '));
|
||||
}
|
||||
|
||||
if (options.target) {
|
||||
link.setAttribute('target', options.target);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
const Prism = require('prismjs');
|
||||
const PrismLoader = require('prismjs/components/index.js');
|
||||
|
||||
PrismLoader('diff');
|
||||
PrismLoader.silent = true;
|
||||
|
||||
/** Highlights a code string. */
|
||||
function highlight(code, language) {
|
||||
const alias = language.replace(/^diff-/, '');
|
||||
const isDiff = /^diff-/i.test(language);
|
||||
|
||||
// Auto-load the target language
|
||||
if (!Prism.languages[alias]) {
|
||||
PrismLoader(alias);
|
||||
|
||||
if (!Prism.languages[alias]) {
|
||||
throw new Error(`Unsupported language for code highlighting: "${language}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Register diff-* languages to use the diff grammar
|
||||
if (isDiff) {
|
||||
Prism.languages[language] = Prism.languages.diff;
|
||||
}
|
||||
|
||||
return Prism.highlight(code, Prism.languages[language], language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights all code fields that have a language parameter. If the language has a colon in its name, the first chunk
|
||||
* will be the language used and additional chunks will be applied as classes to the `<pre>`. For example, a code field
|
||||
* tagged with "html:preview" will be rendered as `<pre class="language-html preview">`.
|
||||
*
|
||||
* The provided doc should be a document object provided by JSDOM. The same document will be returned with the
|
||||
* appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc) {
|
||||
doc.querySelectorAll('pre > code[class]').forEach(code => {
|
||||
// Look for class="language-*" and split colons into separate classes
|
||||
code.classList.forEach(className => {
|
||||
if (className.startsWith('language-')) {
|
||||
//
|
||||
// We use certain suffixes to indicate code previews, expanded states, etc. The class might look something like
|
||||
// this:
|
||||
//
|
||||
// class="language-html:preview:expanded"
|
||||
//
|
||||
// The language will always come first, so we need to drop the "language-" prefix and everything after the first
|
||||
// color to get the highlighter language.
|
||||
//
|
||||
const language = className.replace(/^language-/, '').split(':')[0];
|
||||
|
||||
try {
|
||||
code.innerHTML = highlight(code.textContent ?? '', language);
|
||||
} catch (err) {
|
||||
// Language not found, skip it
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,75 +0,0 @@
|
||||
const MarkdownIt = require('markdown-it');
|
||||
const markdownItContainer = require('markdown-it-container');
|
||||
const markdownItIns = require('markdown-it-ins');
|
||||
const markdownItKbd = require('markdown-it-kbd');
|
||||
const markdownItMark = require('markdown-it-mark');
|
||||
const markdownItReplaceIt = require('markdown-it-replace-it');
|
||||
|
||||
const markdown = MarkdownIt({
|
||||
html: true,
|
||||
xhtmlOut: false,
|
||||
breaks: false,
|
||||
langPrefix: 'language-',
|
||||
linkify: false,
|
||||
typographer: false
|
||||
});
|
||||
|
||||
// Third-party plugins
|
||||
markdown.use(markdownItContainer);
|
||||
markdown.use(markdownItIns);
|
||||
markdown.use(markdownItKbd);
|
||||
markdown.use(markdownItMark);
|
||||
markdown.use(markdownItReplaceIt);
|
||||
|
||||
// Callouts
|
||||
['tip', 'warning', 'danger'].forEach(type => {
|
||||
const variant = type === 'tip' ? 'brand' : type;
|
||||
let icon = 'circle-info';
|
||||
if (type === 'warning') icon = 'triangle-exclamation';
|
||||
if (type === 'danger') icon = 'circle-exclamation';
|
||||
|
||||
markdown.use(markdownItContainer, type, {
|
||||
render: function (tokens, idx) {
|
||||
if (tokens[idx].nesting === 1) {
|
||||
return `
|
||||
<wa-alert class="callout" variant="${variant}" open>
|
||||
<wa-icon slot="icon" name="${icon}" variant="regular"></wa-icon>
|
||||
`;
|
||||
}
|
||||
return '</wa-alert>\n';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Asides
|
||||
markdown.use(markdownItContainer, 'aside', {
|
||||
render: function (tokens, idx) {
|
||||
if (tokens[idx].nesting === 1) {
|
||||
return `<aside>`;
|
||||
}
|
||||
return '</aside>\n';
|
||||
}
|
||||
});
|
||||
|
||||
// Details
|
||||
markdown.use(markdownItContainer, 'details', {
|
||||
validate: params => params.trim().match(/^details\s+(.*)$/),
|
||||
render: (tokens, idx) => {
|
||||
const m = tokens[idx].info.trim().match(/^details\s+(.*)$/);
|
||||
if (tokens[idx].nesting === 1) {
|
||||
return `<details>\n<summary><span>${markdown.utils.escapeHtml(m[1])}</span></summary>\n`;
|
||||
}
|
||||
return '</details>\n';
|
||||
}
|
||||
});
|
||||
|
||||
// Replace [#1234] with a link to GitHub issues
|
||||
markdownItReplaceIt.replacements.push({
|
||||
name: 'github-issues',
|
||||
re: /\[#([0-9]+)\]/gs,
|
||||
sub: '<a href="https://github.com/shoelace-style/shoelace/issues/$1">#$1</a>',
|
||||
html: true,
|
||||
default: true
|
||||
});
|
||||
|
||||
module.exports = markdown;
|
||||
@@ -1,26 +0,0 @@
|
||||
const { format } = require('prettier');
|
||||
|
||||
/** Formats markup using prettier. */
|
||||
module.exports = function (content, options) {
|
||||
options = {
|
||||
arrowParens: 'avoid',
|
||||
bracketSpacing: true,
|
||||
htmlWhitespaceSensitivity: 'css',
|
||||
insertPragma: false,
|
||||
bracketSameLine: false,
|
||||
jsxSingleQuote: false,
|
||||
parser: 'html',
|
||||
printWidth: 120,
|
||||
proseWrap: 'preserve',
|
||||
quoteProps: 'as-needed',
|
||||
requirePragma: false,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
tabWidth: 2,
|
||||
trailingComma: 'none',
|
||||
useTabs: false,
|
||||
...options
|
||||
};
|
||||
|
||||
return format(content, options);
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* @typedef {object} Replacement
|
||||
* @property {string | RegExp} pattern
|
||||
* @property {string} replacement
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Array<Replacement>} Replacements
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Document} content
|
||||
* @param {Replacements} replacements
|
||||
*/
|
||||
module.exports = function (content, replacements) {
|
||||
/** This seems trivial, but by assigning to a string first, THEN using innerHTML after iterating over every replacement, we reduce the calculations of JSDOM. At the time of writing benchmarks show a reduction from 9seconds to 3 seconds by doing so. */
|
||||
let html = content.body.innerHTML;
|
||||
|
||||
replacements.forEach(replacement => {
|
||||
html = html.replaceAll(replacement.pattern, replacement.replacement);
|
||||
});
|
||||
|
||||
content.body.innerHTML = html;
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Turns headings into clickable, deep linkable anchors. The provided doc should be a document object provided by JSDOM.
|
||||
* The same document will be returned with the appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
const tables = [...doc.querySelectorAll('table')];
|
||||
|
||||
options = {
|
||||
className: 'table-scroll', // the class name to add to the table's container
|
||||
...options
|
||||
};
|
||||
|
||||
tables.forEach(table => {
|
||||
const div = doc.createElement('div');
|
||||
div.classList.add(options.className);
|
||||
table.insertAdjacentElement('beforebegin', div);
|
||||
div.append(table);
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
const slugify = require('slugify');
|
||||
|
||||
/** Creates a slug from an arbitrary string of text. */
|
||||
module.exports.createSlug = function (text) {
|
||||
return slugify(String(text), {
|
||||
remove: /[^\w|\s]/g,
|
||||
lower: true
|
||||
});
|
||||
};
|
||||
|
||||
/** Determines whether or not a link is external. */
|
||||
module.exports.isExternalLink = function (link) {
|
||||
// We use the "internal" hostname when initializing JSDOM so we know that those are local links
|
||||
if (!link.hostname || link.hostname === 'internal') return false;
|
||||
return true;
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Generates an in-page table of contents based on headings.
|
||||
*/
|
||||
module.exports = function (doc, options) {
|
||||
options = {
|
||||
levels: ['h2'], // headings to include (they must have an id)
|
||||
container: 'nav', // the container to append links to
|
||||
listItem: true, // if true, links will be wrapped in <li>
|
||||
within: 'body', // the element containing the headings to summarize
|
||||
...options
|
||||
};
|
||||
|
||||
const container = doc.querySelector(options.container);
|
||||
const within = doc.querySelector(options.within);
|
||||
const headingSelector = options.levels.map(h => `${h}[id]`).join(', ');
|
||||
|
||||
if (!container || !within) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
within.querySelectorAll(headingSelector).forEach(heading => {
|
||||
const listItem = doc.createElement('li');
|
||||
const link = doc.createElement('a');
|
||||
const level = heading.tagName.slice(1);
|
||||
|
||||
link.href = `#${heading.id}`;
|
||||
link.textContent = heading.textContent;
|
||||
|
||||
if (options.listItem) {
|
||||
// List item + link
|
||||
listItem.setAttribute('data-level', level);
|
||||
listItem.append(link);
|
||||
container.append(listItem);
|
||||
} else {
|
||||
// Link only
|
||||
link.setAttribute('data-level', level);
|
||||
container.append(link);
|
||||
}
|
||||
});
|
||||
|
||||
return doc;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
const smartquotes = require('smartquotes');
|
||||
|
||||
smartquotes.replacements.push([/---/g, '\u2014']); // em dash
|
||||
smartquotes.replacements.push([/--/g, '\u2013']); // en dash
|
||||
smartquotes.replacements.push([/\.\.\./g, '\u2026']); // ellipsis
|
||||
smartquotes.replacements.push([/\(c\)/gi, '\u00A9']); // copyright
|
||||
smartquotes.replacements.push([/\(r\)/gi, '\u00AE']); // registered trademark
|
||||
smartquotes.replacements.push([/\?!/g, '\u2048']); // ?!
|
||||
smartquotes.replacements.push([/!!/g, '\u203C']); // !!
|
||||
smartquotes.replacements.push([/\?\?/g, '\u2047']); // ??
|
||||
smartquotes.replacements.push([/([0-9]\s?)-(\s?[0-9])/g, '$1\u2013$2']); // number ranges use en dash
|
||||
|
||||
/**
|
||||
* Improves typography by adding smart quotes and similar corrections within the specified element(s).
|
||||
*
|
||||
* The provided doc should be a document object provided by JSDOM. The same document will be returned with the
|
||||
* appropriate DOM manipulations.
|
||||
*/
|
||||
module.exports = function (doc, selector = 'body') {
|
||||
const elements = [...doc.querySelectorAll(selector)];
|
||||
elements.forEach(el => smartquotes.element(el));
|
||||
return doc;
|
||||
};
|
||||
3
docs/assets/images/web-awesome-mark-black.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.63 3.625C11.63 4.27911 11.2435 4.84296 10.6865 5.10064L14 8L17.2622 7.34755C17.0968 7.10642 17 6.81452 17 6.5C17 5.67157 17.6716 5 18.5 5C19.3284 5 20 5.67157 20 6.5C20 7.31157 19.3555 7.9726 18.5504 7.99917L15.0307 15.8207C14.7077 16.5384 13.9939 17 13.2068 17H6.79317C6.00615 17 5.29229 16.5384 4.96933 15.8207L1.44963 7.99917C0.64452 7.9726 0 7.31157 0 6.5C0 5.67157 0.671573 5 1.5 5C2.32843 5 3 5.67157 3 6.5C3 6.81452 2.9032 7.10642 2.73777 7.34755L6 8L9.31702 5.09761C8.76346 4.83855 8.38 4.27656 8.38 3.625C8.38 2.72754 9.10754 2 10.005 2C10.9025 2 11.63 2.72754 11.63 3.625Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 722 B |
@@ -1,206 +0,0 @@
|
||||
//
|
||||
// Sidebar
|
||||
//
|
||||
// When the sidebar is hidden, we apply the inert attribute to prevent focus from reaching it. Due to the many states
|
||||
// the sidebar can have (e.g. static, hidden, expanded), we test for visibility by checking to see if it's placed
|
||||
// offscreen or not. Then, on resize/transition we make sure to update the attribute accordingly.
|
||||
//
|
||||
(() => {
|
||||
function getSidebar() {
|
||||
return document.getElementById('sidebar');
|
||||
}
|
||||
|
||||
function isSidebarOpen() {
|
||||
return document.documentElement.classList.contains('sidebar-open');
|
||||
}
|
||||
|
||||
function isSidebarVisible() {
|
||||
return getSidebar().getBoundingClientRect().x >= 0;
|
||||
}
|
||||
|
||||
function toggleSidebar(force) {
|
||||
const isOpen = typeof force === 'boolean' ? force : !isSidebarOpen();
|
||||
return document.documentElement.classList.toggle('sidebar-open', isOpen);
|
||||
}
|
||||
|
||||
function updateInert() {
|
||||
getSidebar().inert = !isSidebarVisible();
|
||||
}
|
||||
|
||||
// Toggle the menu
|
||||
document.addEventListener('click', event => {
|
||||
const menuToggle = event.target.closest('#menu-toggle');
|
||||
if (!menuToggle) return;
|
||||
toggleSidebar();
|
||||
});
|
||||
|
||||
// Update the sidebar's inert state when the window resizes and when the sidebar transitions
|
||||
window.addEventListener('resize', () => toggleSidebar(false));
|
||||
|
||||
document.addEventListener('transitionend', event => {
|
||||
const sidebar = event.target.closest('#sidebar');
|
||||
if (!sidebar) return;
|
||||
updateInert();
|
||||
});
|
||||
|
||||
// Close when a menu item is selected on mobile
|
||||
document.addEventListener('click', event => {
|
||||
const sidebar = event.target.closest('#sidebar');
|
||||
const link = event.target.closest('a');
|
||||
if (!sidebar || !link) return;
|
||||
|
||||
if (isSidebarOpen()) {
|
||||
toggleSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
// Close when open and escape is pressed
|
||||
document.addEventListener('keydown', event => {
|
||||
if (event.key === 'Escape' && isSidebarOpen()) {
|
||||
event.stopImmediatePropagation();
|
||||
toggleSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
// Close when clicking outside of the sidebar
|
||||
document.addEventListener('mousedown', event => {
|
||||
if (isSidebarOpen() & !event.target?.closest('#sidebar, #menu-toggle')) {
|
||||
event.stopImmediatePropagation();
|
||||
toggleSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
updateInert();
|
||||
})();
|
||||
|
||||
//
|
||||
// Open details when printing
|
||||
//
|
||||
(() => {
|
||||
const detailsOpenOnPrint = new Set();
|
||||
|
||||
window.addEventListener('beforeprint', () => {
|
||||
detailsOpenOnPrint.clear();
|
||||
document.querySelectorAll('details').forEach(details => {
|
||||
if (details.open) {
|
||||
detailsOpenOnPrint.add(details);
|
||||
}
|
||||
details.open = true;
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('afterprint', () => {
|
||||
document.querySelectorAll('details').forEach(details => {
|
||||
details.open = detailsOpenOnPrint.has(details);
|
||||
});
|
||||
detailsOpenOnPrint.clear();
|
||||
});
|
||||
})();
|
||||
|
||||
//
|
||||
// Smooth links
|
||||
//
|
||||
(() => {
|
||||
document.addEventListener('click', event => {
|
||||
const link = event.target.closest('a');
|
||||
const id = (link?.hash ?? '').substr(1);
|
||||
const isFragment = link?.hasAttribute('href') && link?.getAttribute('href').startsWith('#');
|
||||
|
||||
if (!link || !isFragment || link.getAttribute('data-smooth-link') === 'false') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Scroll to the top
|
||||
if (link.hash === '') {
|
||||
event.preventDefault();
|
||||
window.scroll({ top: 0, behavior: 'smooth' });
|
||||
history.pushState(undefined, undefined, location.pathname);
|
||||
}
|
||||
|
||||
// Scroll to an id
|
||||
if (id) {
|
||||
const target = document.getElementById(id);
|
||||
|
||||
if (target) {
|
||||
event.preventDefault();
|
||||
window.scroll({ top: target.offsetTop, behavior: 'smooth' });
|
||||
history.pushState(undefined, undefined, `#${id}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
//
|
||||
// Table of Contents scrollspy
|
||||
//
|
||||
(() => {
|
||||
// This will be stale if its not a function.
|
||||
const getLinks = () => [...document.querySelectorAll('.content__toc a')];
|
||||
const linkTargets = new WeakMap();
|
||||
const visibleTargets = new WeakSet();
|
||||
const observer = new IntersectionObserver(handleIntersect, { rootMargin: '0px 0px' });
|
||||
let debounce;
|
||||
|
||||
function handleIntersect(entries) {
|
||||
entries.forEach(entry => {
|
||||
// Remember which targets are visible
|
||||
if (entry.isIntersecting) {
|
||||
visibleTargets.add(entry.target);
|
||||
} else {
|
||||
visibleTargets.delete(entry.target);
|
||||
}
|
||||
});
|
||||
|
||||
updateActiveLinks();
|
||||
}
|
||||
|
||||
function updateActiveLinks() {
|
||||
const links = getLinks();
|
||||
// Find the first visible target and activate the respective link
|
||||
links.find(link => {
|
||||
const target = linkTargets.get(link);
|
||||
|
||||
if (target && visibleTargets.has(target)) {
|
||||
links.forEach(el => el.classList.toggle('active', el === link));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Observe link targets
|
||||
function observeLinks() {
|
||||
getLinks().forEach(link => {
|
||||
const hash = link.hash.slice(1);
|
||||
const target = hash ? document.querySelector(`.content__body #${hash}`) : null;
|
||||
|
||||
if (target) {
|
||||
linkTargets.set(link, target);
|
||||
observer.observe(target);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
observeLinks();
|
||||
|
||||
document.addEventListener('turbo:load', updateActiveLinks);
|
||||
document.addEventListener('turbo:load', observeLinks);
|
||||
})();
|
||||
|
||||
//
|
||||
// Show custom versions in the sidebar
|
||||
//
|
||||
(() => {
|
||||
function updateVersion() {
|
||||
const el = document.querySelector('.sidebar-version');
|
||||
if (!el) return;
|
||||
|
||||
if (location.hostname === 'next.shoelace.style') el.textContent = 'Next';
|
||||
if (location.hostname === 'localhost') el.textContent = 'Development';
|
||||
}
|
||||
|
||||
updateVersion();
|
||||
|
||||
document.addEventListener('turbo:load', updateVersion);
|
||||
})();
|
||||
@@ -1,384 +0,0 @@
|
||||
(() => {
|
||||
// Append the search dialog to the body
|
||||
const siteSearch = document.createElement('div');
|
||||
const scrollbarWidth = Math.abs(window.innerWidth - document.documentElement.clientWidth);
|
||||
|
||||
siteSearch.classList.add('search');
|
||||
siteSearch.innerHTML = `
|
||||
<div class="search__overlay"></div>
|
||||
<dialog id="search-dialog" class="search__dialog">
|
||||
<div class="search__content">
|
||||
<div class="search__header">
|
||||
<div id="search-combobox" class="search__input-wrapper">
|
||||
<wa-icon name="search"></wa-icon>
|
||||
<input
|
||||
id="search-input"
|
||||
class="search__input"
|
||||
type="search"
|
||||
placeholder="Search"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
enterkeyhint="go"
|
||||
spellcheck="false"
|
||||
maxlength="100"
|
||||
role="combobox"
|
||||
aria-autocomplete="list"
|
||||
aria-expanded="true"
|
||||
aria-controls="search-listbox"
|
||||
aria-haspopup="listbox"
|
||||
aria-activedescendant
|
||||
>
|
||||
<button type="button" class="search__clear-button" aria-label="Clear entry" tabindex="-1" hidden>
|
||||
<wa-icon name="circle-xmark" variant="regular"></wa-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search__body">
|
||||
<ul
|
||||
id="search-listbox"
|
||||
class="search__results"
|
||||
role="listbox"
|
||||
aria-label="Search results"
|
||||
></ul>
|
||||
<div class="search__empty">No matching pages</div>
|
||||
</div>
|
||||
<footer class="search__footer">
|
||||
<small><kbd><wa-icon label="Up" name="arrow-up"></wa-icon></kbd> <kbd><wa-icon label="Down" name="arrow-down"></wa-icon></kbd> Navigate</small>
|
||||
<small><kbd><wa-icon label="Enter" name="arrow-turn-down-left"></wa-icon></kbd> Select</small>
|
||||
<small><kbd>Esc</kbd> Close</small>
|
||||
</footer>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
const overlay = siteSearch.querySelector('.search__overlay');
|
||||
const dialog = siteSearch.querySelector('.search__dialog');
|
||||
const input = siteSearch.querySelector('.search__input');
|
||||
const clearButton = siteSearch.querySelector('.search__clear-button');
|
||||
const results = siteSearch.querySelector('.search__results');
|
||||
const version = document.documentElement.getAttribute('data-wa-version');
|
||||
const key = `search_${version}`;
|
||||
const searchDebounce = 50;
|
||||
const animationDuration = 150;
|
||||
let isShowing = false;
|
||||
let searchTimeout;
|
||||
let searchIndex;
|
||||
let map;
|
||||
|
||||
const loadSearchIndex = new Promise(resolve => {
|
||||
const cache = localStorage.getItem(key);
|
||||
const wait = 'requestIdleCallback' in window ? requestIdleCallback : requestAnimationFrame;
|
||||
|
||||
// Cleanup older search indices (everything before this version)
|
||||
try {
|
||||
const items = { ...localStorage };
|
||||
|
||||
Object.keys(items).forEach(k => {
|
||||
if (key > k) {
|
||||
localStorage.removeItem(k);
|
||||
}
|
||||
});
|
||||
} catch {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
// Look for a cached index
|
||||
try {
|
||||
if (cache) {
|
||||
const data = JSON.parse(cache);
|
||||
|
||||
searchIndex = window.lunr.Index.load(data.searchIndex);
|
||||
map = data.map;
|
||||
|
||||
return resolve();
|
||||
}
|
||||
} catch {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
// Wait until idle to fetch the index
|
||||
wait(() => {
|
||||
fetch('/assets/search.json')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (!window.lunr) {
|
||||
console.error('The Lunr search client has not yet been loaded.');
|
||||
}
|
||||
|
||||
searchIndex = window.lunr.Index.load(data.searchIndex);
|
||||
map = data.map;
|
||||
|
||||
// Cache the search index for this version
|
||||
if (version) {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(data));
|
||||
} catch (err) {
|
||||
console.warn(`Unable to cache the search index: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function show() {
|
||||
isShowing = true;
|
||||
document.body.append(siteSearch);
|
||||
document.body.classList.add('search-visible');
|
||||
document.body.style.setProperty('--docs-search-scroll-lock-size', `${scrollbarWidth}px`);
|
||||
clearButton.hidden = true;
|
||||
requestAnimationFrame(() => input.focus());
|
||||
updateResults();
|
||||
|
||||
dialog.showModal();
|
||||
|
||||
await Promise.all([
|
||||
dialog.animate(
|
||||
[
|
||||
{ opacity: 0, transform: 'scale(.9)', transformOrigin: 'top' },
|
||||
{ opacity: 1, transform: 'scale(1)', transformOrigin: 'top' }
|
||||
],
|
||||
{ duration: animationDuration }
|
||||
).finished,
|
||||
overlay.animate([{ opacity: 0 }, { opacity: 1 }], { duration: animationDuration }).finished
|
||||
]);
|
||||
|
||||
dialog.addEventListener('mousedown', handleMouseDown);
|
||||
dialog.addEventListener('keydown', handleKeyDown);
|
||||
}
|
||||
|
||||
async function hide() {
|
||||
isShowing = false;
|
||||
|
||||
await Promise.all([
|
||||
dialog.animate(
|
||||
[
|
||||
{ opacity: 1, transform: 'scale(1)', transformOrigin: 'top' },
|
||||
{ opacity: 0, transform: 'scale(.9)', transformOrigin: 'top' }
|
||||
],
|
||||
{ duration: animationDuration }
|
||||
).finished,
|
||||
overlay.animate([{ opacity: 1 }, { opacity: 0 }], { duration: animationDuration }).finished
|
||||
]);
|
||||
|
||||
dialog.close();
|
||||
|
||||
input.blur(); // otherwise Safari will scroll to the bottom of the page on close
|
||||
input.value = '';
|
||||
document.body.classList.remove('search-visible');
|
||||
document.body.style.removeProperty('--docs-search-scroll-lock-size');
|
||||
siteSearch.remove();
|
||||
updateResults();
|
||||
|
||||
dialog.removeEventListener('mousedown', handleMouseDown);
|
||||
dialog.removeEventListener('keydown', handleKeyDown);
|
||||
}
|
||||
|
||||
function handleInput() {
|
||||
clearButton.hidden = input.value === '';
|
||||
|
||||
// Debounce search queries
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => updateResults(input.value), searchDebounce);
|
||||
}
|
||||
|
||||
function handleClear() {
|
||||
clearButton.hidden = true;
|
||||
input.value = '';
|
||||
input.focus();
|
||||
updateResults();
|
||||
}
|
||||
|
||||
function handleMouseDown(event) {
|
||||
if (!event.target.closest('.search__content')) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
// Close when pressing escape
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault(); // prevent <dialog> from closing immediately so it can animate
|
||||
event.stopImmediatePropagation();
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle keyboard selections
|
||||
if (['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter'].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
|
||||
const currentEl = results.querySelector('[data-selected="true"]');
|
||||
const items = [...results.querySelectorAll('li')];
|
||||
const index = items.indexOf(currentEl);
|
||||
let nextEl;
|
||||
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowUp':
|
||||
nextEl = items[Math.max(0, index - 1)];
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
nextEl = items[Math.min(items.length - 1, index + 1)];
|
||||
break;
|
||||
case 'Home':
|
||||
nextEl = items[0];
|
||||
break;
|
||||
case 'End':
|
||||
nextEl = items[items.length - 1];
|
||||
break;
|
||||
case 'Enter':
|
||||
currentEl?.querySelector('a')?.click();
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the selected item
|
||||
items.forEach(item => {
|
||||
if (item === nextEl) {
|
||||
input.setAttribute('aria-activedescendant', item.id);
|
||||
item.setAttribute('data-selected', 'true');
|
||||
nextEl.scrollIntoView({ block: 'nearest' });
|
||||
} else {
|
||||
item.setAttribute('data-selected', 'false');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function updateResults(query = '') {
|
||||
try {
|
||||
await loadSearchIndex;
|
||||
|
||||
const hasQuery = query.length > 0;
|
||||
const searchTerms = query
|
||||
.split(' ')
|
||||
.map((term, index, arr) => {
|
||||
// Search API: https://lunrjs.com/guides/searching.html
|
||||
if (index === arr.length - 1) {
|
||||
// The last term is not mandatory and 1x fuzzy. We also duplicate it with a wildcard to match partial words
|
||||
// as the user types.
|
||||
return `${term}~1 ${term}*`;
|
||||
} else {
|
||||
// All other terms are mandatory and 1x fuzzy
|
||||
return `+${term}~1`;
|
||||
}
|
||||
})
|
||||
.join(' ');
|
||||
const matches = hasQuery ? searchIndex.search(searchTerms) : [];
|
||||
const hasResults = hasQuery && matches.length > 0;
|
||||
|
||||
siteSearch.classList.toggle('search--has-results', hasQuery && hasResults);
|
||||
siteSearch.classList.toggle('search--no-results', hasQuery && !hasResults);
|
||||
|
||||
input.setAttribute('aria-activedescendant', '');
|
||||
results.innerHTML = '';
|
||||
|
||||
matches.forEach((match, index) => {
|
||||
const page = map[match.ref];
|
||||
const li = document.createElement('li');
|
||||
const a = document.createElement('a');
|
||||
const displayTitle = page.title ?? '';
|
||||
const displayDescription = page.description ?? '';
|
||||
const displayUrl = page.url.replace(/^\//, '').replace(/\/$/, '');
|
||||
let icon = 'file-text';
|
||||
|
||||
a.setAttribute('role', 'option');
|
||||
a.setAttribute('id', `search-result-item-${match.ref}`);
|
||||
|
||||
if (page.url.includes('getting-started/')) {
|
||||
icon = 'lightbulb';
|
||||
}
|
||||
if (page.url.includes('resources/')) {
|
||||
icon = 'book';
|
||||
}
|
||||
if (page.url.includes('components/')) {
|
||||
icon = 'puzzle-piece';
|
||||
}
|
||||
if (page.url.includes('tokens/')) {
|
||||
icon = 'swatchbook';
|
||||
}
|
||||
if (page.url.includes('utilities/')) {
|
||||
icon = 'wrench';
|
||||
}
|
||||
if (page.url.includes('tutorials/')) {
|
||||
icon = 'gamepad';
|
||||
}
|
||||
|
||||
li.classList.add('search__result');
|
||||
li.setAttribute('role', 'option');
|
||||
li.setAttribute('id', `search-result-item-${match.ref}`);
|
||||
li.setAttribute('data-selected', index === 0 ? 'true' : 'false');
|
||||
|
||||
a.href = page.url;
|
||||
a.innerHTML = `
|
||||
<div class="search__result-icon" aria-hidden="true">
|
||||
<wa-icon name="${icon}"></wa-icon>
|
||||
</div>
|
||||
<div class="search__result__details">
|
||||
<div class="search__result-title"></div>
|
||||
<div class="search__result-description"></div>
|
||||
<div class="search__result-url"></div>
|
||||
</div>
|
||||
`;
|
||||
a.querySelector('.search__result-title').textContent = displayTitle;
|
||||
a.querySelector('.search__result-description').textContent = displayDescription;
|
||||
a.querySelector('.search__result-url').textContent = displayUrl;
|
||||
|
||||
li.appendChild(a);
|
||||
results.appendChild(li);
|
||||
});
|
||||
} catch {
|
||||
// Ignore query errors as the user types
|
||||
}
|
||||
}
|
||||
|
||||
// Show the search dialog when clicking on data-plugin="search"
|
||||
document.addEventListener('click', event => {
|
||||
const searchButton = event.target.closest('[data-plugin="search"]');
|
||||
if (searchButton) {
|
||||
show();
|
||||
}
|
||||
});
|
||||
|
||||
// Show the search dialog when slash (or CMD+K) is pressed and focus is not inside a form element
|
||||
document.addEventListener('keydown', event => {
|
||||
if (
|
||||
!isShowing &&
|
||||
(event.key === '/' || (event.key === 'k' && (event.metaKey || event.ctrlKey))) &&
|
||||
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
|
||||
) {
|
||||
event.preventDefault();
|
||||
show();
|
||||
}
|
||||
});
|
||||
|
||||
// Purge cache when we press CMD+CTRL+R
|
||||
document.addEventListener('keydown', event => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'r') {
|
||||
localStorage.clear();
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('input', handleInput);
|
||||
clearButton.addEventListener('click', handleClear);
|
||||
|
||||
// Close when a result is selected
|
||||
results.addEventListener('click', event => {
|
||||
if (event.target.closest('a')) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
// We're using Turbo, so when a user searches for something, visits a result, and presses the back button, the search
|
||||
// UI will still be visible but not interactive. This removes the search UI when Turbo renders a page so they don't
|
||||
// get trapped.
|
||||
window.addEventListener('turbo:render', () => {
|
||||
document.body.classList.remove('search-visible');
|
||||
document.querySelectorAll('.search__overlay, .search__dialog').forEach(el => el.remove());
|
||||
});
|
||||
})();
|
||||
@@ -1,29 +0,0 @@
|
||||
import * as Turbo from 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@7.3.0/+esm';
|
||||
|
||||
(() => {
|
||||
if (!window.scrollPositions) {
|
||||
window.scrollPositions = {};
|
||||
}
|
||||
|
||||
function preserveScroll() {
|
||||
document.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
scrollPositions[element.id] = element.scrollTop;
|
||||
});
|
||||
}
|
||||
|
||||
function restoreScroll(event) {
|
||||
document.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
element.scrollTop = scrollPositions[element.id];
|
||||
});
|
||||
|
||||
if (event.detail && event.detail.newBody) {
|
||||
event.detail.newBody.querySelectorAll('[data-preserve-scroll').forEach(element => {
|
||||
element.scrollTop = scrollPositions[element.id];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('turbo:before-cache', preserveScroll);
|
||||
window.addEventListener('turbo:before-render', restoreScroll);
|
||||
window.addEventListener('turbo:render', restoreScroll);
|
||||
})();
|
||||
147
docs/astro.config.mjs
Normal file
@@ -0,0 +1,147 @@
|
||||
import { defineConfig } from 'astro/config';
|
||||
import starlight from '@astrojs/starlight';
|
||||
import * as url from 'node:url';
|
||||
import * as path from 'node:path';
|
||||
// const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
|
||||
import FullReload from 'vite-plugin-full-reload';
|
||||
|
||||
import { customElementsManifest } from './src/js/cem.js';
|
||||
import { RemarkPluginFindAndReplace } from 'remark-plugin-find-and-replace';
|
||||
import rehypeExternalLinks from 'rehype-external-links';
|
||||
import remarkCodeHighlighter from './src/plugins/prism';
|
||||
import GithubAutolink from './src/plugins/github-autolink.ts';
|
||||
|
||||
const version = customElementsManifest().package.version;
|
||||
const cdndir = 'cdn';
|
||||
const npmdir = 'dist';
|
||||
|
||||
function remarkFrontmatterPlugin() {
|
||||
// All remark and rehype plugins return a separate function
|
||||
return function (tree, file) {
|
||||
const frontmatter = file.data.astro.frontmatter;
|
||||
|
||||
frontmatter.npmdir = npmdir;
|
||||
frontmatter.cdndir = cdndir;
|
||||
frontmatter.version = version;
|
||||
};
|
||||
}
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
server: {
|
||||
open: true,
|
||||
port: 4000,
|
||||
host: true
|
||||
},
|
||||
vite: {
|
||||
server: {
|
||||
watch: {
|
||||
ignored: ['./public/pagefind/**/*.*'] // HERE
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
FullReload([
|
||||
path.relative(__dirname, '../dist/custom-elements.json')
|
||||
// path.relative(__dirname, './public/**/*.*')
|
||||
])
|
||||
]
|
||||
},
|
||||
outDir: '../_site',
|
||||
site: 'https://shoelace.style',
|
||||
markdown: {
|
||||
syntaxHighlight: 'prism',
|
||||
remarkPlugins: [
|
||||
remarkFrontmatterPlugin,
|
||||
RemarkPluginFindAndReplace({
|
||||
replacements: [
|
||||
{ pattern: '%VERSION%', replacement: version },
|
||||
{ pattern: '%CDNDIR%', replacement: cdndir },
|
||||
{ pattern: '%NPMDIR%', replacement: npmdir }
|
||||
]
|
||||
}),
|
||||
GithubAutolink,
|
||||
remarkCodeHighlighter
|
||||
],
|
||||
rehypePlugins: [
|
||||
() =>
|
||||
rehypeExternalLinks({
|
||||
rel: ['nofollow', 'noopener', 'noreferrer'],
|
||||
target: ['_blank'],
|
||||
properties: {
|
||||
class: 'external-link'
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
integrations: [
|
||||
starlight({
|
||||
expressiveCode: false,
|
||||
title: 'Web Awesome',
|
||||
social: {
|
||||
github: 'https://github.com/shoelace-style/shoelace',
|
||||
twitter: 'https://twitter.com/shoelace_style'
|
||||
},
|
||||
sidebar: [
|
||||
{
|
||||
label: 'Experimental',
|
||||
autogenerate: { directory: 'experimental' }
|
||||
},
|
||||
{
|
||||
label: 'Getting Started',
|
||||
autogenerate: { directory: 'getting-started' }
|
||||
},
|
||||
{
|
||||
label: 'Frameworks',
|
||||
autogenerate: { directory: 'frameworks' }
|
||||
},
|
||||
{
|
||||
label: 'Resources',
|
||||
autogenerate: { directory: 'resources' },
|
||||
items: [
|
||||
{
|
||||
label: 'Community',
|
||||
link: '/resources/community'
|
||||
},
|
||||
{
|
||||
label: 'Help & Support',
|
||||
link: 'https://github.com/shoelace-style/shoelace/discussions'
|
||||
},
|
||||
{
|
||||
label: 'Accessibility',
|
||||
link: '/resources/accessibility'
|
||||
},
|
||||
{
|
||||
label: 'Contributing',
|
||||
link: '/resources/contributing'
|
||||
},
|
||||
{
|
||||
label: 'Changelog',
|
||||
link: '/resources/changelog'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Components',
|
||||
autogenerate: { directory: 'components' }
|
||||
},
|
||||
{
|
||||
label: 'Design Tokens',
|
||||
autogenerate: { directory: 'tokens' }
|
||||
},
|
||||
{
|
||||
label: 'Tutorials',
|
||||
autogenerate: { directory: 'tutorials' }
|
||||
}
|
||||
],
|
||||
// Component overrides
|
||||
components: {
|
||||
// Override the default `Head` component.
|
||||
Head: './src/components/overrides/Head.astro',
|
||||
TableOfContents: './src/components/overrides/TableOfContents.astro',
|
||||
Search: './src/components/overrides/Search.astro'
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||
@@ -1,246 +0,0 @@
|
||||
/* eslint-disable no-invalid-this */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const lunr = require('lunr');
|
||||
const { capitalCase } = require('change-case');
|
||||
const { JSDOM } = require('jsdom');
|
||||
const { customElementsManifest, getAllComponents } = require('./_utilities/cem.cjs');
|
||||
const webAwesomeFlavoredMarkdown = require('./_utilities/markdown.cjs');
|
||||
const activeLinks = require('./_utilities/active-links.cjs');
|
||||
const anchorHeadings = require('./_utilities/anchor-headings.cjs');
|
||||
const codePreviews = require('./_utilities/code-previews.cjs');
|
||||
const copyCodeButtons = require('./_utilities/copy-code-buttons.cjs');
|
||||
const externalLinks = require('./_utilities/external-links.cjs');
|
||||
const highlightCodeBlocks = require('./_utilities/highlight-code.cjs');
|
||||
const tableOfContents = require('./_utilities/table-of-contents.cjs');
|
||||
const prettier = require('./_utilities/prettier.cjs');
|
||||
const scrollingTables = require('./_utilities/scrolling-tables.cjs');
|
||||
const typography = require('./_utilities/typography.cjs');
|
||||
const replacer = require('./_utilities/replacer.cjs');
|
||||
|
||||
const assetsDir = 'assets';
|
||||
const cdndir = 'cdn';
|
||||
const npmdir = 'dist';
|
||||
const allComponents = getAllComponents();
|
||||
let hasBuiltSearchIndex = false;
|
||||
|
||||
module.exports = function (eleventyConfig) {
|
||||
//
|
||||
// Global data
|
||||
//
|
||||
eleventyConfig.addGlobalData('baseUrl', 'https://shoelace.style/'); // the production URL
|
||||
eleventyConfig.addGlobalData('layout', 'default'); // make 'default' the default layout
|
||||
eleventyConfig.addGlobalData('toc', true); // enable the table of contents
|
||||
eleventyConfig.addGlobalData('meta', {
|
||||
title: 'Web Awesome',
|
||||
description: 'A forward-thinking library of web components.',
|
||||
image: 'images/og-image.png',
|
||||
version: customElementsManifest.package.version,
|
||||
components: allComponents,
|
||||
cdndir,
|
||||
npmdir
|
||||
});
|
||||
|
||||
//
|
||||
// Layout aliases
|
||||
//
|
||||
eleventyConfig.addLayoutAlias('default', 'default.njk');
|
||||
|
||||
//
|
||||
// Copy assets
|
||||
//
|
||||
eleventyConfig.addPassthroughCopy(assetsDir);
|
||||
eleventyConfig.setServerPassthroughCopyBehavior('passthrough'); // emulates passthrough copy during --serve
|
||||
|
||||
//
|
||||
// Functions
|
||||
//
|
||||
|
||||
// Generates a URL relative to the site's root
|
||||
eleventyConfig.addNunjucksGlobal('rootUrl', (value = '', absolute = false) => {
|
||||
value = path.join('/', value);
|
||||
return absolute ? new URL(value, eleventyConfig.globalData.baseUrl).toString() : value;
|
||||
});
|
||||
|
||||
// Generates a URL relative to the site's asset directory
|
||||
eleventyConfig.addNunjucksGlobal('assetUrl', (value = '', absolute = false) => {
|
||||
value = path.join(`/${assetsDir}`, value);
|
||||
return absolute ? new URL(value, eleventyConfig.globalData.baseUrl).toString() : value;
|
||||
});
|
||||
|
||||
// Fetches a specific component's metadata
|
||||
eleventyConfig.addNunjucksGlobal('getComponent', tagName => {
|
||||
const component = allComponents.find(c => c.tagName === tagName);
|
||||
if (!component) {
|
||||
throw new Error(
|
||||
`Unable to find a component called "${tagName}". Make sure the file name is the same as the component's tag ` +
|
||||
`name (minus the wa- prefix).`
|
||||
);
|
||||
}
|
||||
return component;
|
||||
});
|
||||
|
||||
//
|
||||
// Custom markdown syntaxes
|
||||
//
|
||||
eleventyConfig.setLibrary('md', webAwesomeFlavoredMarkdown);
|
||||
|
||||
//
|
||||
// Filters
|
||||
//
|
||||
eleventyConfig.addFilter('markdown', content => {
|
||||
return webAwesomeFlavoredMarkdown.render(content);
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter('markdownInline', content => {
|
||||
return webAwesomeFlavoredMarkdown.renderInline(content);
|
||||
});
|
||||
|
||||
// Trims whitespace and pipes from the start and end of a string. Useful for CEM types, which can be pipe-delimited.
|
||||
// With Prettier 3, this means a leading pipe will exist if the line wraps.
|
||||
eleventyConfig.addFilter('trimPipes', content => {
|
||||
return typeof content === 'string' ? content.replace(/^(\s|\|)/g, '').replace(/(\s|\|)$/g, '') : content;
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter('classNameToComponentName', className => {
|
||||
let name = capitalCase(className.replace(/^Wa/, ''));
|
||||
if (name === 'Qr Code') name = 'QR Code'; // manual override
|
||||
return name;
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter('removeWaPrefix', tagName => {
|
||||
return tagName.replace(/^wa-/, '');
|
||||
});
|
||||
|
||||
//
|
||||
// Transforms
|
||||
//
|
||||
eleventyConfig.addTransform('html-transform', function (content) {
|
||||
// Parse the template and get a Document object
|
||||
const doc = new JSDOM(content, {
|
||||
// We must set a default URL so links are parsed with a hostname. Let's use a bogus TLD so we can easily
|
||||
// identify which ones are internal and which ones are external.
|
||||
url: `https://internal/`
|
||||
}).window.document;
|
||||
|
||||
// DOM transforms
|
||||
activeLinks(doc, { pathname: this.page.url });
|
||||
anchorHeadings(doc, {
|
||||
within: '#content .content__body',
|
||||
levels: ['h2', 'h3', 'h4', 'h5']
|
||||
});
|
||||
tableOfContents(doc, {
|
||||
levels: ['h2', 'h3'],
|
||||
container: '#content .content__toc > ul',
|
||||
within: '#content .content__body'
|
||||
});
|
||||
codePreviews(doc);
|
||||
externalLinks(doc, { target: '_blank' });
|
||||
highlightCodeBlocks(doc);
|
||||
scrollingTables(doc);
|
||||
copyCodeButtons(doc); // must be after codePreviews + highlightCodeBlocks
|
||||
typography(doc, '#content');
|
||||
|
||||
replacer(doc, [
|
||||
{ pattern: '%VERSION%', replacement: customElementsManifest.package.version },
|
||||
{ pattern: '%CDNDIR%', replacement: cdndir },
|
||||
{ pattern: '%NPMDIR%', replacement: npmdir }
|
||||
]);
|
||||
|
||||
// Serialize the Document object to an HTML string and prepend the doctype
|
||||
content = `<!DOCTYPE html>\n${doc.documentElement.outerHTML}`;
|
||||
|
||||
// String transforms
|
||||
content = prettier(content);
|
||||
|
||||
return content;
|
||||
});
|
||||
|
||||
//
|
||||
// Build a search index
|
||||
//
|
||||
eleventyConfig.on('eleventy.after', ({ results }) => {
|
||||
// We only want to build the search index on the first run so all pages get indexed.
|
||||
if (hasBuiltSearchIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
const map = {};
|
||||
const searchIndexFilename = path.join(eleventyConfig.dir.output, assetsDir, 'search.json');
|
||||
const lunrInput = path.resolve('../node_modules/lunr/lunr.min.js');
|
||||
const lunrOutput = path.join(eleventyConfig.dir.output, assetsDir, 'scripts/lunr.js');
|
||||
const searchIndex = lunr(function () {
|
||||
// The search index uses these field names extensively, so shortening them can save some serious bytes. The
|
||||
// initial index file went from 468 KB => 401 KB by using single-character names!
|
||||
this.ref('id'); // id
|
||||
this.field('t', { boost: 50 }); // title
|
||||
this.field('h', { boost: 25 }); // headings
|
||||
this.field('c'); // content
|
||||
|
||||
results.forEach((result, index) => {
|
||||
const url = path
|
||||
.join('/', path.relative(eleventyConfig.dir.output, result.outputPath))
|
||||
.replace(/\\/g, '/') // convert backslashes to forward slashes
|
||||
.replace(/\/index.html$/, '/'); // convert trailing /index.html to /
|
||||
const doc = new JSDOM(result.content, {
|
||||
// We must set a default URL so links are parsed with a hostname. Let's use a bogus TLD so we can easily
|
||||
// identify which ones are internal and which ones are external.
|
||||
url: `https://internal/`
|
||||
}).window.document;
|
||||
const content = doc.querySelector('#content');
|
||||
|
||||
// Get title and headings
|
||||
const title = (doc.querySelector('title')?.textContent || path.basename(result.outputPath)).trim();
|
||||
const headings = [...content.querySelectorAll('h1, h2, h3, h4')]
|
||||
.map(heading => heading.textContent)
|
||||
.join(' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
|
||||
// Remove code blocks and whitespace from content
|
||||
[...content.querySelectorAll('code[class|=language]')].forEach(code => code.remove());
|
||||
const textContent = content.textContent.replace(/\s+/g, ' ').trim();
|
||||
|
||||
// Update the index and map
|
||||
this.add({ id: index, t: title, h: headings, c: textContent });
|
||||
map[index] = { title, url };
|
||||
});
|
||||
});
|
||||
|
||||
// Copy the Lunr search client and write the index
|
||||
fs.mkdirSync(path.dirname(lunrOutput), { recursive: true });
|
||||
fs.copyFileSync(lunrInput, lunrOutput);
|
||||
fs.writeFileSync(searchIndexFilename, JSON.stringify({ searchIndex, map }), 'utf-8');
|
||||
|
||||
hasBuiltSearchIndex = true;
|
||||
});
|
||||
|
||||
//
|
||||
// Send a signal to stdout that let's the build know we've reached this point
|
||||
//
|
||||
eleventyConfig.on('eleventy.after', () => {
|
||||
console.log('[eleventy.after]');
|
||||
});
|
||||
|
||||
//
|
||||
// Dev server options (see https://www.11ty.dev/docs/dev-server/#options)
|
||||
//
|
||||
eleventyConfig.setServerOptions({
|
||||
domDiff: false, // disable dom diffing so custom elements don't break on reload,
|
||||
port: 4000, // if port 4000 is taken, 11ty will use the next one available
|
||||
watch: ['cdn/**/*'] // additional files to watch that will trigger server updates (array of paths or globs)
|
||||
});
|
||||
|
||||
//
|
||||
// 11ty config
|
||||
//
|
||||
return {
|
||||
dir: {
|
||||
input: 'pages',
|
||||
output: '../_site',
|
||||
includes: '../_includes' // resolved relative to the input dir
|
||||
},
|
||||
markdownTemplateEngine: 'njk', // use Nunjucks instead of Liquid for markdown files
|
||||
templateEngineOverride: ['njk'] // just Nunjucks and then markdown
|
||||
};
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
meta:
|
||||
title: Page Not Found
|
||||
description: "The page you were looking for couldn't be found."
|
||||
permalink: 404.html
|
||||
toc: false
|
||||
---
|
||||
|
||||
<div style="text-align: center;">
|
||||
|
||||
# Page Not Found
|
||||
|
||||

|
||||
|
||||
The page you were looking for couldn't be found.
|
||||
|
||||
Press [[/]] to search, or [head back to the homepage](/).
|
||||
|
||||
</div>
|
||||
@@ -1,282 +0,0 @@
|
||||
---
|
||||
meta:
|
||||
title: Blog Listing
|
||||
description: TODO
|
||||
toc: false
|
||||
---
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--docs-content-max-width: 72rem;
|
||||
}
|
||||
#menu-toggle,
|
||||
#sidebar {
|
||||
display: none;
|
||||
}
|
||||
main {
|
||||
padding: var(--docs-content-vertical-spacing) var(--docs-content-padding);
|
||||
margin: 0;
|
||||
}
|
||||
.anchor-heading a {
|
||||
display: none;
|
||||
}
|
||||
.preview-container {
|
||||
container: preview / inline-size;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="preview-container wa:block-flow:3xl">
|
||||
<div class="wa:blog_header wa:background:college_ruled">
|
||||
<h1>Latest from the Blog</h1>
|
||||
<p>Don't miss the hottest takes on art and design from respected industry experts.</p>
|
||||
</div>
|
||||
<div class="wa:arrange:aside-end" style="--wa-grid-size: 45ch;">
|
||||
<div class="wa:block-flow:m">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://bit.ly/3Irq42Q" alt="">
|
||||
</div>
|
||||
<div class="wa:arrange:flex:justify-space_between">
|
||||
<small><wa-format-date month="long" year="numeric"></wa-format-date></small>
|
||||
<wa-tag size="small">Design</wa-tag>
|
||||
</div>
|
||||
<h1>Pantone's Color of the Year 2024</h1>
|
||||
<p>PANTONE 13-1023 Peach Fuzz has our new year starting off with lots of warm and fuzzies.</p>
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<wa-avatar label="User avatar" style="--size: 2rem;"></wa-avatar>
|
||||
<small>Jane Doe</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:arrange" style="align-content: start;">
|
||||
<div class="wa:arrange:side-by-side:gap-s">
|
||||
<div class="wa:block-flow:xs">
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
<h4>Lorem Ipsum Dolor Sit Amet</h4>
|
||||
</div>
|
||||
<div class="wa:frame">
|
||||
<img src="https://images.pexels.com/photos/1181676/pexels-photo-1181676.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:arrange:side-by-side:gap-s">
|
||||
<div class="wa:block-flow:xs">
|
||||
<small><wa-format-date date="2023-11-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
<h4>Consectetur Adipiscing Elit</h4>
|
||||
</div>
|
||||
<div class="wa:frame">
|
||||
<img src="https://images.pexels.com/photos/4219654/pexels-photo-4219654.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:arrange:side-by-side:gap-s">
|
||||
<div class="wa:block-flow:xs">
|
||||
<small><wa-format-date date="2023-11-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
<h4>Nunc Rhoncus Enim Ligula</h4>
|
||||
</div>
|
||||
<div class="wa:frame">
|
||||
<img src="https://images.pexels.com/photos/14822510/pexels-photo-14822510.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:arrange:side-by-side:gap-s">
|
||||
<div class="wa:block-flow:xs">
|
||||
<small><wa-format-date date="2023-10-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
<h4>Donec Quis Tincidunt Massa</h4>
|
||||
</div>
|
||||
<div class="wa:frame">
|
||||
<img src="https://images.pexels.com/photos/7988116/pexels-photo-7988116.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:arrange:gap-m" style="background-color:var(--wa-color-brand-fill-subtle); padding:var(--wa-space-3xl); border-radius:var(--wa-panel-corners); box-shadow:var(--wa-shadow-level-1);">
|
||||
<div class="wa:block-flow:s">
|
||||
<h2 style="color:var(--wa-color-brand-text-on-fill)"><strong>Don't miss a thing.</strong></h2>
|
||||
<p style="color:var(--wa-color-neutral-text-on-fill)">Subscribe to receive the latest posts in your inbox.</p>
|
||||
</div>
|
||||
<div class="wa:arrange:flex:justify-space_between:gap-s">
|
||||
<wa-input class="wa:fill_space" type="email" placeholder="your@email.com">
|
||||
<wa-icon name="envelope" variant="regular" label="email" slot="prefix"></wa-icon>
|
||||
</wa-input>
|
||||
<wa-button variant="brand">Subscribe</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:block-flow:xl">
|
||||
<div class="wa:arrange:flex:justify-space_between">
|
||||
<h2>Arts & Culture</h2>
|
||||
<wa-button outline variant="brand">
|
||||
See more arts & culture posts
|
||||
<wa-icon name="arrow-right" slot="suffix"></wa-icon>
|
||||
</wa-button>
|
||||
</div>
|
||||
<div class="wa:arrange:size-s">
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/14363192/pexels-photo-14363192.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Dolore eu Fugiat Nulla</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/8843689/pexels-photo-8843689.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Sed Tincidunt Nibh Felis</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/1646953/pexels-photo-1646953.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Curabitur Cursus Eleifend</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/3184188/pexels-photo-3184188.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Ante Est Non Ligula</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:block-flow:xl">
|
||||
<div class="wa:arrange:flex:justify-space_between">
|
||||
<h2>Design</h2>
|
||||
<wa-button outline variant="brand">
|
||||
See more design posts
|
||||
<wa-icon name="arrow-right" slot="suffix"></wa-icon>
|
||||
</wa-button>
|
||||
</div>
|
||||
<div class="wa:arrange:size-s">
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/1762851/pexels-photo-1762851.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Maecenas ut Metus</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/196645/pexels-photo-196645.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Morbi Vitae Sapien Non Velit</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/1194420/pexels-photo-1194420.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Vestibulum Ante Ipsum Primis</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/1779487/pexels-photo-1779487.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Viverra Eros Vitae</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:block-flow:xl">
|
||||
<div class="wa:arrange:flex:justify-space_between">
|
||||
<h2>Web Development</h2>
|
||||
<wa-button outline variant="brand">
|
||||
See more web development posts
|
||||
<wa-icon name="arrow-right" slot="suffix"></wa-icon>
|
||||
</wa-button>
|
||||
</div>
|
||||
<div class="wa:arrange:size-s">
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/6321244/pexels-photo-6321244.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Ante Est Non Ligula Imperdiet</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/5473956/pexels-photo-5473956.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Viverra Eros Vitae</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/4709289/pexels-photo-4709289.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Maecenas ut Metus</h4>
|
||||
</div>
|
||||
<div class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://images.pexels.com/photos/3184340/pexels-photo-3184340.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
<h4>Dolore eu Fugiat Nulla</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:arrange:size-s wa:collection">
|
||||
<div>
|
||||
<h2>So Fetch <wa-icon name="arrow-trend-up" style="color: var(--wa-color-brand-spot);"></wa-icon></h2>
|
||||
<p style="margin-block-end:0;">Other readers have been into these trending posts recently.</p>
|
||||
</div>
|
||||
<wa-card class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape" slot="image">
|
||||
<img src="https://images.pexels.com/photos/1194420/pexels-photo-1194420.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
<h4>Vestibulum Ante Ipsum Primis</h4>
|
||||
<wa-tag size="small">Design</wa-tag>
|
||||
</wa-card>
|
||||
<wa-card class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape" slot="image">
|
||||
<img src="https://images.pexels.com/photos/4219654/pexels-photo-4219654.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
<h4>Consectetur Adipiscing Elit</h4>
|
||||
<wa-tag size="small">Arts & Culture</wa-tag>
|
||||
</wa-card>
|
||||
<wa-card class="wa:block-flow:xs">
|
||||
<div class="wa:frame:landscape" slot="image">
|
||||
<img src="https://images.pexels.com/photos/6321244/pexels-photo-6321244.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
<small><wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date></small>
|
||||
<h4>Ante Est Non Ligula Imperdiet</h4>
|
||||
<wa-tag size="small">Web Development</wa-tag>
|
||||
</wa-card>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Browse All Topics</h2>
|
||||
<div class="wa:arrange:gap-m">
|
||||
<wa-button outline>Accessibility <wa-icon name="arrow-right" slot="suffix"></wa-icon></wa-button>
|
||||
<wa-button outline>Arts & Culture <wa-icon name="arrow-right" slot="suffix"></wa-icon></wa-button>
|
||||
<wa-button outline>Design <wa-icon name="arrow-right" slot="suffix"></wa-icon></wa-button>
|
||||
<wa-button outline>News <wa-icon name="arrow-right" slot="suffix"></wa-icon></wa-button>
|
||||
<wa-button outline>Typography <wa-icon name="arrow-right" slot="suffix"></wa-icon></wa-button>
|
||||
<wa-button outline>Web Development <wa-icon name="arrow-right" slot="suffix"></wa-icon></wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,171 +0,0 @@
|
||||
---
|
||||
meta:
|
||||
title: Patterns List
|
||||
description: TBD
|
||||
toc: false
|
||||
---
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--docs-content-max-width: 72rem;
|
||||
}
|
||||
#menu-toggle,
|
||||
#sidebar {
|
||||
display: none;
|
||||
}
|
||||
main {
|
||||
margin: var(--wa-space-xl);
|
||||
}
|
||||
h2:not(.code-preview h2) {
|
||||
font-size: large;
|
||||
}
|
||||
</style>
|
||||
|
||||
# Blog Patterns
|
||||
|
||||
## Overflowing Hero
|
||||
|
||||
```html:preview
|
||||
<section class="wa:blog-hero-overflowing">
|
||||
<div class="wa:hero-backdrop">
|
||||
<div class="wa:hero-content">
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Design</wa-tag>
|
||||
</div>
|
||||
<h1>Pantone's Color of the Year 2024</h1>
|
||||
<p>PANTONE 13-1023 Peach Fuzz has our new year starting off with lots of warm and fuzzies.</p>
|
||||
<div class="wa:post-author">
|
||||
<wa-avatar label="User avatar" style="--size: 2rem;"></wa-avatar>
|
||||
<small>Jane Doe</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:frame:square">
|
||||
<img src="https://bit.ly/3Irq42Q" alt="Vast, peach-colored desert">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
## Post Body with Drop Cap
|
||||
|
||||
```html:preview
|
||||
<section class="wa:blog-post">
|
||||
<div class="wa:post-body">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
|
||||
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
## Footer with Reactions
|
||||
|
||||
```html:preview
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa:post-footer">
|
||||
<wa-radio-group name="reactions" class="wa:post-reactions">
|
||||
<wa-radio-button value="applaud"><wa-icon name="hands-clapping" label="Applaud"></wa-icon><small class="wa:count">74</small></wa-radio-button>
|
||||
<wa-radio-button value="love"><wa-icon name="heart" label="Love"></wa-icon><small class="wa:count">161</small></wa-radio-button>
|
||||
<wa-radio-button value="laugh"><wa-icon name="face-laugh-beam" label="Laugh"></wa-icon><small class="wa:count">9</small></wa-radio-button>
|
||||
<wa-radio-button value="cry"><wa-icon name="face-sad-tear" label="Cry"></wa-icon><small class="wa:count">1</small></wa-radio-button>
|
||||
</wa-radio-group>
|
||||
<div class="wa:post-actions">
|
||||
<wa-tooltip content="Save">
|
||||
<wa-icon-button name="bookmark" label="Save"></wa-icon-button>
|
||||
</wa-tooltip>
|
||||
<wa-tooltip content="Share">
|
||||
<wa-icon-button name="share-from-square" label="Share"></wa-icon-button>
|
||||
</wa-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Comment Field
|
||||
|
||||
```html:preview
|
||||
<article class="wa:comment-composer">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<wa-textarea rows="1" placeholder="Add a comment"></wa-textarea>
|
||||
</article>
|
||||
```
|
||||
|
||||
## Comment
|
||||
|
||||
```html:preview
|
||||
<article class="wa:comment">
|
||||
<wa-avatar image="https://bit.ly/3V9kV7a" label="User avatar"></wa-avatar>
|
||||
<div class="wa:comment-content">
|
||||
<div class="wa:comment-bubble">
|
||||
<div class="wa:comment-details">
|
||||
<strong>Pedro Pascal</strong>
|
||||
<small>1d</small>
|
||||
</div>
|
||||
<span>You expect me to search the galaxy for the home of this creature and deliver it to a race of enemy sorcerers?</span>
|
||||
</div>
|
||||
<div class="wa:comment-actions">
|
||||
<div class="wa:reaction-like">
|
||||
<wa-icon-button name="thumbs-up" label="Like"></wa-icon-button>
|
||||
<small>(3)</small>
|
||||
</div>
|
||||
<wa-button variant="text" size="small">Reply</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
```
|
||||
|
||||
## Call to Action
|
||||
|
||||
```html:preview
|
||||
<section class="wa:blog-subscribe-cta">
|
||||
<div class="wa:cta-description">
|
||||
<h2><strong>Don't miss a thing.</strong></h2>
|
||||
<p>Subscribe to receive the latest posts in your inbox.</p>
|
||||
</div>
|
||||
<form>
|
||||
<wa-input type="email" placeholder="your@email.com">
|
||||
<wa-icon name="envelope" variant="regular" label="email" slot="prefix"></wa-icon>
|
||||
</wa-input>
|
||||
<wa-button type="submit" variant="brand">Subscribe</wa-button>
|
||||
</form>
|
||||
</section>
|
||||
```
|
||||
|
||||
## Recommended Posts
|
||||
|
||||
```html:preview
|
||||
<section class="wa:blog-recommended-posts">
|
||||
<h2>You may also like</h2>
|
||||
<div class="wa:post-list">
|
||||
<article class="wa:post-link">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="http://bit.ly/49ThK7O" alt="">
|
||||
</div>
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date date="2024-02-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Arts & Culture</wa-tag>
|
||||
</div>
|
||||
<h4>Eget Consequat Libero</h4>
|
||||
</article>
|
||||
<article class="wa:post-link">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://bit.ly/3wHdFFp" alt="">
|
||||
</div>
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date date="2024-01-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Design</wa-tag>
|
||||
</div>
|
||||
<h4>Sed a Leo Tempus Aute Irure</h4>
|
||||
</article>
|
||||
<article class="wa:post-link">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://bit.ly/49LxbPx" alt="">
|
||||
</div>
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Arts & Culture</wa-tag>
|
||||
</div>
|
||||
<h4>Ultrices Posuere Cubilia Curae</h4>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
@@ -1,175 +0,0 @@
|
||||
---
|
||||
meta:
|
||||
title: Blog Post
|
||||
description: TODO
|
||||
toc: false
|
||||
---
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--docs-content-max-width: 72rem;
|
||||
}
|
||||
#menu-toggle,
|
||||
#sidebar {
|
||||
display: none;
|
||||
}
|
||||
main {
|
||||
padding: var(--docs-content-vertical-spacing) var(--docs-content-padding);
|
||||
margin: 0;
|
||||
}
|
||||
.anchor-heading a {
|
||||
display: none;
|
||||
}
|
||||
.preview-container {
|
||||
container: preview / inline-size;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- cSpell:dictionaries lorem-ipsum -->
|
||||
|
||||
<div class="preview-container wa:block-flow:3xl">
|
||||
<section class="wa:blog-hero-overflowing">
|
||||
<div class="wa:hero-backdrop">
|
||||
<div class="wa:hero-content">
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Design</wa-tag>
|
||||
</div>
|
||||
<h1>Pantone's Color of the Year 2024</h1>
|
||||
<p>PANTONE 13-1023 Peach Fuzz has our new year starting off with lots of warm and fuzzies.</p>
|
||||
<div class="wa:post-author">
|
||||
<wa-avatar label="User avatar" style="--size: 2rem;"></wa-avatar>
|
||||
<small>Jane Doe</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:frame:square">
|
||||
<img src="https://bit.ly/3Irq42Q" alt="Vast, peach-colored desert">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="wa:blog-post">
|
||||
<div class="wa:post-body">
|
||||
<p>Morbi vitae sapien non velit feugiat consectetur. Nulla lacinia ante a diam gravida cursus. Quisque fermentum ex a nisi cursus porttitor. Praesent id laoreet mauris, id efficitur sapien. Quisque eget metus velit. Nulla sit amet tristique lectus, tincidunt lobortis velit. Proin vitae facilisis lectus. Nunc vel sapien vitae dui commodo suscipit iaculis eget felis.</p>
|
||||
<p>Praesent in erat semper, fringilla tellus non, lacinia felis. Nam eu fringilla nisl. Maecenas id tortor tempus, accumsan nisi eget, bibendum arcu. Pellentesque nec enim non nisl varius iaculis. Phasellus interdum nec ex nec faucibus. Vestibulum et quam auctor massa pellentesque tempor. Sed tincidunt nibh felis, ut euismod ante volutpat aliquam. Etiam varius suscipit ornare.</p>
|
||||
<p>Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed a leo tempus, pretium mi ac, pretium ipsum. Curabitur cursus eleifend enim. Pellentesque feugiat euismod tincidunt. Sed semper velit nunc, nec imperdiet eros varius ac. Aenean aliquam augue at venenatis volutpat. Proin a imperdiet leo. Nullam eget aliquet urna.</p>
|
||||
<p>Mauris faucibus varius massa vel vulputate. Praesent ac ligula pretium, viverra eros vitae, consequat metus. Morbi commodo vehicula sem, eget scelerisque ipsum rutrum ut. Maecenas cursus dolor mattis risus dapibus pulvinar. Suspendisse ut dolor nec arcu lobortis molestie.</p>
|
||||
<p>Donec eros felis, dictum non placerat vitae, sodales in risus. Etiam felis lectus, consectetur quis tempor non, porta a metus. Cras finibus nibh a est semper, eget consequat libero pretium. Pellentesque placerat feugiat enim sit amet sodales. Proin convallis dui eu nibh tincidunt, a posuere dolor sagittis. Ut egestas et eros eu convallis. Integer eros elit, blandit at euismod sit amet, blandit sed velit. Donec dapibus nulla in augue commodo, at efficitur orci dictum. Praesent ultrices accumsan iaculis. Maecenas ut metus a lectus venenatis euismod. Sed auctor, dui efficitur molestie convallis, diam odio faucibus turpis, vitae bibendum ante est non ligula.</p>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa:post-footer">
|
||||
<wa-radio-group name="reactions" class="wa:post-reactions">
|
||||
<wa-radio-button value="applaud"><wa-icon name="hands-clapping" label="Applaud"></wa-icon><small class="wa:count">74</small></wa-radio-button>
|
||||
<wa-radio-button value="love"><wa-icon name="heart" label="Love"></wa-icon><small class="wa:count">161</small></wa-radio-button>
|
||||
<wa-radio-button value="laugh"><wa-icon name="face-laugh-beam" label="Laugh"></wa-icon><small class="wa:count">9</small></wa-radio-button>
|
||||
<wa-radio-button value="cry"><wa-icon name="face-sad-tear" label="Cry"></wa-icon><small class="wa:count">1</small></wa-radio-button>
|
||||
</wa-radio-group>
|
||||
<div class="wa:post-actions">
|
||||
<wa-tooltip content="Save">
|
||||
<wa-icon-button name="bookmark" label="Save"></wa-icon-button>
|
||||
</wa-tooltip>
|
||||
<wa-tooltip content="Share">
|
||||
<wa-icon-button name="share-from-square" label="Share"></wa-icon-button>
|
||||
</wa-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="wa:post-comments wa:block-flow:2xl">
|
||||
<h2>Comments</h2>
|
||||
<article class="wa:comment-composer">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<wa-textarea rows="1" placeholder="Add a comment"></wa-textarea>
|
||||
</article>
|
||||
<article class="wa:comment">
|
||||
<wa-avatar image="https://bit.ly/3V9kV7a" label="User avatar"></wa-avatar>
|
||||
<div class="wa:comment-content">
|
||||
<div class="wa:comment-bubble">
|
||||
<div class="wa:comment-details">
|
||||
<strong>Pedro Pascal</strong>
|
||||
<small>1d</small>
|
||||
</div>
|
||||
<span>You expect me to search the galaxy for the home of this creature and deliver it to a race of enemy sorcerers?</span>
|
||||
</div>
|
||||
<div class="wa:comment-actions">
|
||||
<div class="wa:reaction-like">
|
||||
<wa-icon-button name="thumbs-up" label="Like"></wa-icon-button>
|
||||
<small>(3)</small>
|
||||
</div>
|
||||
<wa-button variant="text" size="small">Reply</wa-button>
|
||||
</div>
|
||||
<article class="wa:comment">
|
||||
<wa-avatar image="https://bit.ly/3Pb2cUC" label="User avatar"></wa-avatar>
|
||||
<div class="wa:comment-content">
|
||||
<div class="wa:comment-bubble">
|
||||
<div class="wa:comment-details">
|
||||
<strong>Emily Swallow</strong>
|
||||
<small>12h</small>
|
||||
</div>
|
||||
<span>This is the Way.</span>
|
||||
</div>
|
||||
<div class="wa:comment-actions">
|
||||
<div class="wa:reaction-like">
|
||||
<wa-icon-button name="thumbs-up" label="Like"></wa-icon-button>
|
||||
<small>(21)</small>
|
||||
</div>
|
||||
<wa-button variant="text" size="small">Reply</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</article>
|
||||
<article class="wa:comment">
|
||||
<wa-avatar image="https://bit.ly/3Tq9GWr" label="User avatar"></wa-avatar>
|
||||
<div class="wa:comment-content">
|
||||
<div class="wa:comment-bubble">
|
||||
<div class="wa:comment-details">
|
||||
<strong>Nick Nolte</strong>
|
||||
<small>2w</small>
|
||||
</div>
|
||||
<span>I have spoken.</span>
|
||||
</div>
|
||||
<div class="wa:comment-actions">
|
||||
<div class="wa:reaction-like">
|
||||
<wa-icon-button name="thumbs-up" label="Like"></wa-icon-button>
|
||||
<small>(1)</small>
|
||||
</div>
|
||||
<wa-button variant="text" size="small">Reply</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</section>
|
||||
<section class="wa:blog-recommended-posts">
|
||||
<h2>You may also like</h2>
|
||||
<div class="wa:post-list">
|
||||
<article class="wa:post-link">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="http://bit.ly/49ThK7O" alt="">
|
||||
</div>
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date date="2024-02-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Arts & Culture</wa-tag>
|
||||
</div>
|
||||
<h4>Eget Consequat Libero</h4>
|
||||
</article>
|
||||
<article class="wa:post-link">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://bit.ly/3wHdFFp" alt="">
|
||||
</div>
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date date="2024-01-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Design</wa-tag>
|
||||
</div>
|
||||
<h4>Sed a Leo Tempus Aute Irure</h4>
|
||||
</article>
|
||||
<article class="wa:post-link">
|
||||
<div class="wa:frame:landscape">
|
||||
<img src="https://bit.ly/49LxbPx" alt="">
|
||||
</div>
|
||||
<div class="wa:post-details">
|
||||
<wa-format-date date="2023-12-16T09:17:00-04:00" month="long" year="numeric"></wa-format-date>
|
||||
<wa-tag size="small">Arts & Culture</wa-tag>
|
||||
</div>
|
||||
<h4>Ultrices Posuere Cubilia Curae</h4>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -1,586 +0,0 @@
|
||||
---
|
||||
meta:
|
||||
title: Dashboard
|
||||
description: TODO
|
||||
toc: false
|
||||
---
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--docs-content-max-width: 80rem;
|
||||
}
|
||||
html {
|
||||
background-color: var(--wa-color-surface-lowered);
|
||||
}
|
||||
|
||||
#menu-toggle,
|
||||
#sidebar {
|
||||
display: none;
|
||||
}
|
||||
main {
|
||||
padding: initial;
|
||||
padding-bottom: var(--wa-space-3xl);
|
||||
margin: var(--wa-space-xl);
|
||||
}
|
||||
.anchor-heading a {
|
||||
display: none;
|
||||
}
|
||||
.preview-container {
|
||||
container: preview / inline-size;
|
||||
}
|
||||
|
||||
/* strata - support table */
|
||||
.support-table {
|
||||
font-size: var(--wa-font-size-s);
|
||||
}
|
||||
|
||||
.support-table th {
|
||||
padding: var(--wa-space-l);
|
||||
}
|
||||
|
||||
.support-table td {
|
||||
padding: var(--wa-space-m) var(--wa-space-l);
|
||||
}
|
||||
|
||||
.support-table .desc {
|
||||
max-width: 30ch;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.support-table .excerpt {
|
||||
color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
.support-table wa-avatar {
|
||||
--size: var(--wa-font-size-2xl);
|
||||
}
|
||||
|
||||
.support-table wa-card > * {
|
||||
border-radius: calc(var(--border-radius) - var(--border-width));
|
||||
}
|
||||
|
||||
.wa\:card-title {
|
||||
font-size: var(--wa-font-size-l);
|
||||
margin-block-end: 0;
|
||||
}
|
||||
|
||||
.wa\:statistic {
|
||||
& .wa\:card-title {
|
||||
color: var(--wa-color-text-quiet);
|
||||
font-size: var(--wa-font-size-s);
|
||||
}
|
||||
|
||||
& .wa\:value {
|
||||
font-size: var(--wa-font-size-2xl);
|
||||
font-weight: var(--wa-font-weight-heavy);
|
||||
line-height: var(--wa-font-line-height-compact);
|
||||
|
||||
& + wa-badge > wa-icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wa-card#glitches::part(body) {
|
||||
padding-block-end: 0;
|
||||
}
|
||||
|
||||
wa-card.wa\:statistic::part(base) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.wa\:box-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--wa-color-brand-spot);
|
||||
color: var(--wa-color-brand-text-on-spot);
|
||||
border-radius: var(--wa-corners-s);
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
font-size: var(--wa-font-size-l);
|
||||
}
|
||||
|
||||
.wa\:contact {
|
||||
font-size: var(--wa-font-size-s);
|
||||
}
|
||||
|
||||
wa-card::part(base) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
wa-checkbox[checked] {
|
||||
--wa-form-controls-value-color: var(--wa-color-text-quiet);
|
||||
}
|
||||
|
||||
caption {
|
||||
color: var(--wa-color-text-normal);
|
||||
text-align: left;
|
||||
margin: var(--wa-space-xl) var(--wa-space-xl) var(--wa-space-l) var(--wa-space-xl);
|
||||
|
||||
& h2 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
margin-inline: calc(var(--padding) * -1);
|
||||
}
|
||||
.sparkline {
|
||||
height: 1em;
|
||||
transition: all .5s ease;
|
||||
}
|
||||
|
||||
.sparkline .index {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 1%;
|
||||
height: 6.25em;
|
||||
}
|
||||
|
||||
.sparkline .index .count {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
background: var(--wa-color-brand-spot);
|
||||
font: 0/0 a;
|
||||
text-shadow: none;
|
||||
color: transparent;
|
||||
}
|
||||
figcaption {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- cSpell:dictionaries lorem-ipsum -->
|
||||
|
||||
<div class="preview-container wa:arrange:flex:align-start:nowrap">
|
||||
<div class="wa:block-flow:l" style="display: flex; flex-direction: column; align-items: center;">
|
||||
<wa-icon-button name="crown" href="/" style="color: var(--wa-color-brand-spot);"></wa-icon-button>
|
||||
<wa-divider style="width: 100%;"></wa-divider>
|
||||
<wa-icon-button name="home"></wa-icon-button>
|
||||
<wa-icon-button name="calendar"></wa-icon-button>
|
||||
<wa-icon-button name="envelope"></wa-icon-button>
|
||||
<wa-icon-button name="chart-simple"></wa-icon-button>
|
||||
<wa-icon-button name="archive"></wa-icon-button>
|
||||
<wa-divider style="width: 100%;"></wa-divider>
|
||||
<wa-icon-button name="gear"></wa-icon-button>
|
||||
<wa-icon-button name="right-from-bracket"></wa-icon-button>
|
||||
</div>
|
||||
<div class="wa:fill_space wa:block-flow:l">
|
||||
<div class="wa:arrange:aside-end:gap-l">
|
||||
<div class="wa:arrange:size-m:gap-l">
|
||||
<wa-card class="wa:block-flow:l wa:statistic">
|
||||
<div class="wa:arrange:flex:align-start:gap-m:nowrap">
|
||||
<span class="wa:box-icon">
|
||||
<wa-icon name="globe"></wa-icon>
|
||||
</span>
|
||||
<div>
|
||||
<h2 class="wa:fill_space wa:card-title">
|
||||
Population (Zion)
|
||||
</h2>
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<span class="wa:value">251,999</span>
|
||||
<wa-badge variant="danger">-3% <wa-icon name="arrow-trend-down"></wa-icon></wa-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
<wa-card class="wa:block-flow:l wa:statistic">
|
||||
<div class="wa:arrange:flex:align-start:gap-m:nowrap">
|
||||
<span class="wa:box-icon">
|
||||
<wa-icon name="brain-circuit"></wa-icon>
|
||||
</span>
|
||||
<div>
|
||||
<h2 class="wa:fill_space wa:card-title">
|
||||
Minds Freed
|
||||
</h2>
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<span class="wa:value">0.36%</span>
|
||||
<wa-badge variant="success">+0.02% <wa-icon name="arrow-trend-up"></wa-icon></wa-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
<wa-card class="wa:block-flow:l wa:statistic">
|
||||
<div class="wa:arrange:flex:align-start:gap-m:nowrap">
|
||||
<span class="wa:box-icon">
|
||||
<wa-icon name="robot"></wa-icon>
|
||||
</span>
|
||||
<div>
|
||||
<h2 class="wa:fill_space wa:card-title">
|
||||
Agents Discovered
|
||||
</h2>
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<span class="wa:value">3</span>
|
||||
<wa-badge variant="neutral">±0% <wa-icon name="wave-triangle"></wa-icon></wa-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
<wa-card class="wa:block-flow:l wa:statistic">
|
||||
<div class="wa:arrange:flex:align-start:gap-m:nowrap">
|
||||
<span class="wa:box-icon">
|
||||
<wa-icon name="spaghetti-monster-flying"></wa-icon>
|
||||
</span>
|
||||
<div>
|
||||
<h2 class="wa:fill_space wa:card-title">
|
||||
Sentinels Controlled
|
||||
</h2>
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<span class="wa:value">208</span>
|
||||
<wa-badge variant="success">+1% <wa-icon name="arrow-trend-up"></wa-icon></wa-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
<wa-card>
|
||||
<div class="wa:block-flow:l">
|
||||
<div class="wa:arrange:flex:gap-xl">
|
||||
<h2 class="wa:card-title">Daily Tasks</h2>
|
||||
<wa-progress-bar value="40" class="wa:fill_space" style="--height: 0.5em;"></wa-progress-bar>
|
||||
</div>
|
||||
<div class="wa:block-flow:s">
|
||||
<wa-checkbox style="display:block;">Let go fear, doubt, and disbelief</wa-checkbox>
|
||||
<wa-checkbox style="display:block;">Walk through the door</wa-checkbox>
|
||||
<wa-checkbox style="display:block;">Train with Morpheus</wa-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<a href="#">View completed tasks</a>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
<section class="strata support-table">
|
||||
<wa-card style="--padding: 0; width: 100%;">
|
||||
<table style="margin-bottom: 0;">
|
||||
<caption>
|
||||
<h2 class="wa:card-title">Conversations</h2>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><wa-checkbox size="large" style="padding-left: var(--wa-space-s)"><wa-visually-hidden>Check all</wa-visually-hidden></wa-checkbox></th>
|
||||
<th>Customer</th>
|
||||
<th>Conversation</th>
|
||||
<th>Assigned To</th>
|
||||
<th style="text-align: center;">Status</th>
|
||||
<th><wa-visually-hidden>Actions</wa-visually-hidden></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><wa-checkbox size="large" style="padding-left: var(--wa-space-s)"><wa-visually-hidden>Completed</wa-visually-hidden></wa-checkbox></td>
|
||||
<td>Keanu Reeves</td>
|
||||
<td class="desc"><span style="font-weight: bold">Am I dead?</span><br><span class="excerpt">Okey dokey... free my mind. Right, no problem, free my mind, free my mind, no problem, right...</span></td>
|
||||
<td><wa-avatar image="/assets/images/kitchen-sink/avatar-chad.jpg" label="Chad" style="margin-right: var(--wa-space-xs)"></wa-avatar> Chad Stahelski</td>
|
||||
<td style="text-align: center;"><wa-tag variant="warning" size="small">Pending</wa-tag></td>
|
||||
<td>
|
||||
<wa-dropdown>
|
||||
<wa-button slot="trigger" caret size="small">Action</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="check" variant="regular"></wa-icon>
|
||||
Resolved
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="clock" variant="regular"></wa-icon>
|
||||
Pending
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="arrow-rotate-left" variant="regular"></wa-icon>
|
||||
Re-open
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="xmark" variant="regular"></wa-icon>
|
||||
Delete
|
||||
</wa-menu-item>
|
||||
</wa-menu>
|
||||
</wa-dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><wa-checkbox size="large" style="padding-left: var(--wa-space-s)"><wa-visually-hidden>Completed</wa-visually-hidden></wa-checkbox></td>
|
||||
<td>Lawrence Fishburne</td>
|
||||
<td class="desc"><span style="font-weight: bold">We have a rule</span><br><span class="excerpt">We never free a mind once it's reached a certain age. It's dangerous, the mind has trouble letting go.</span></td>
|
||||
<td><wa-avatar image="/assets/images/kitchen-sink/avatar-char.jpg" label="Char" style="margin-right: var(--wa-space-xs)"></wa-avatar> Char McCoy</td>
|
||||
<td style="text-align: center;"><wa-tag variant="success" size="small">Resolved</wa-tag></td>
|
||||
<td>
|
||||
<wa-dropdown>
|
||||
<wa-button slot="trigger" caret size="small">Action</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="check" variant="regular"></wa-icon>
|
||||
Resolved
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="clock" variant="regular"></wa-icon>
|
||||
Pending
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="arrow-rotate-left" variant="regular"></wa-icon>
|
||||
Re-open
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="xmark" variant="regular"></wa-icon>
|
||||
Delete
|
||||
</wa-menu-item>
|
||||
</wa-menu>
|
||||
</wa-dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><wa-checkbox size="large" style="padding-left: var(--wa-space-s)" checked><wa-visually-hidden>Completed</wa-visually-hidden></wa-checkbox></td>
|
||||
<td>Carrie-Ann Moss</td>
|
||||
<td class="desc"><span style="font-weight: bold">Was it the same cat?</span><br><span class="excerpt">A déjà vu is usually a glitch in the Matrix. It happens when they change something.</span></td>
|
||||
<td><wa-avatar initials="DE" label="Avatar with initials: DE" style="margin-right: var(--wa-space-xs)"></wa-avatar> Debbie Evans</td>
|
||||
<td style="text-align: center;"><wa-tag variant="warning" size="small">Pending</wa-tag></td>
|
||||
<td>
|
||||
<wa-dropdown>
|
||||
<wa-button slot="trigger" caret size="small">Action</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="check" variant="regular"></wa-icon>
|
||||
Resolved
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="clock" variant="regular"></wa-icon>
|
||||
Pending
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="arrow-rotate-left" variant="regular"></wa-icon>
|
||||
Re-open
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="xmark" variant="regular"></wa-icon>
|
||||
Delete
|
||||
</wa-menu-item>
|
||||
</wa-menu>
|
||||
</wa-dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><wa-checkbox size="large" style="padding-left: var(--wa-space-s)"><wa-visually-hidden>Completed</wa-visually-hidden></wa-checkbox></td>
|
||||
<td>Joe Pantoliano</td>
|
||||
<td class="desc"><span style="font-weight: bold">Ignorance is bliss</span><br><span class="excerpt">Why oh why didn't I take the blue pill?</span></td>
|
||||
<td></td>
|
||||
<td style="text-align: center;"><wa-tag variant="danger" size="small">Bounced</wa-tag></td>
|
||||
<td>
|
||||
<wa-dropdown>
|
||||
<wa-button slot="trigger" caret size="small">Action</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="check" variant="regular"></wa-icon>
|
||||
Resolved
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="clock" variant="regular"></wa-icon>
|
||||
Pending
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="arrow-rotate-left" variant="regular"></wa-icon>
|
||||
Re-open
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="xmark" variant="regular"></wa-icon>
|
||||
Delete
|
||||
</wa-menu-item>
|
||||
</wa-menu>
|
||||
</wa-dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><wa-checkbox size="large" style="padding-left: var(--wa-space-s)"><wa-visually-hidden>Completed</wa-visually-hidden></wa-checkbox></td>
|
||||
<td>Hugo Weaving</td>
|
||||
<td class="desc"><span style="font-weight: bold">I'd like to share a revelation</span><br><span class="excerpt">I need the codes, I have to get inside Zion and you have to tell me how.</span></td>
|
||||
<td><wa-avatar image="/assets/images/kitchen-sink/avatar-dara.jpg" label="Dara" style="margin-right: var(--wa-space-xs)"></wa-avatar> Dara Prescott</td>
|
||||
<td style="text-align: center;"><wa-tag variant="neutral" size="small">Expired</wa-tag></td>
|
||||
<td>
|
||||
<wa-dropdown>
|
||||
<wa-button slot="trigger" caret size="small">Action</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="check" variant="regular"></wa-icon>
|
||||
Resolved
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="clock" variant="regular"></wa-icon>
|
||||
Pending
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="arrow-rotate-left" variant="regular"></wa-icon>
|
||||
Re-open
|
||||
</wa-menu-item>
|
||||
<wa-menu-item>
|
||||
<wa-icon slot="prefix" name="xmark" variant="regular"></wa-icon>
|
||||
Delete
|
||||
</wa-menu-item>
|
||||
</wa-menu>
|
||||
</wa-dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</wa-card>
|
||||
</section>
|
||||
<div class="wa:arrange:gap-l">
|
||||
<wa-card id="glitches">
|
||||
<div class="wa:block-flow:l">
|
||||
<div class="wa:arrange:flex:justify-space_between">
|
||||
<h2 class="wa:card-title">Glitches</h2>
|
||||
<small style="color: var(--wa-color-text-quiet);">March 31, 1999</small>
|
||||
</div>
|
||||
<figure>
|
||||
<span class="sparkline">
|
||||
<span class="index"><span class="count" style="height: 27%;">(60,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 92%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 80%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 71%;">160,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 78%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 21%;">225,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 78%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 12%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 21%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 56%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 80%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 71%;">160,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 69%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 99%;">225,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 80%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 27%;">(60,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 77%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 80%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 71%;">160,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 38%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 85%;">225,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 78%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 80%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 92%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 92%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 46%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 80%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 71%;">160,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 60%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 100%;">225,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 78%;">175,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 49%;">110,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 60%;">180,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 27%;">(60,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 8%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 56%;">125)</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 27%;">(60,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 56%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 62%;">140,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 27%;">(60,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 78%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 40%;">90,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 53%;">120,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 27%;">(60,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 25%;">220,</span> </span>
|
||||
<span class="index"><span class="count" style="height: 35%;">80,</span> </span>
|
||||
</span>
|
||||
</figure>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<a href="#">View all data</a>
|
||||
</div>
|
||||
</wa-card>
|
||||
<wa-card>
|
||||
<div class="wa:block-flow:l">
|
||||
<h2 class="wa:card-title">Recent Contacts</h2>
|
||||
<div class="wa:arrange:gap-l" style="--wa-grid-size: 20ch;">
|
||||
<wa-card style="--padding: var(--wa-space-s);">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<wa-avatar label="User avatar">
|
||||
<wa-icon slot="icon" name="user-secret"></wa-icon>
|
||||
</wa-avatar>
|
||||
<div class="wa:contact">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<strong>Trinity</strong>
|
||||
</div>
|
||||
<small><em>Nebuchadnezzar</em></small>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
<wa-card style="--padding: var(--wa-space-s);">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<wa-avatar label="User avatar">
|
||||
<wa-icon slot="icon" name="user-tie"></wa-icon>
|
||||
</wa-avatar>
|
||||
<div class="wa:contact">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<strong>Mr. Rhineheart</strong>
|
||||
</div>
|
||||
<small><em>MetaCortex</em></small>
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<a href="#">View all contacts</a>
|
||||
</div>
|
||||
</wa-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,223 +0,0 @@
|
||||
---
|
||||
meta:
|
||||
title: Ecommerce Product Page
|
||||
description: TODO
|
||||
toc: false
|
||||
---
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--docs-content-max-width: 72rem;
|
||||
}
|
||||
#menu-toggle,
|
||||
#sidebar {
|
||||
display: none;
|
||||
}
|
||||
main {
|
||||
padding: initial;
|
||||
margin: var(--wa-space-xl);
|
||||
}
|
||||
.anchor-heading a {
|
||||
display: none;
|
||||
}
|
||||
.preview-container {
|
||||
container: preview / inline-size;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- cSpell:dictionaries lorem-ipsum -->
|
||||
|
||||
<div class="preview-container wa:block-flow:3xl">
|
||||
<wa-breadcrumb>
|
||||
<wa-breadcrumb-item>Plants</wa-breadcrumb-item>
|
||||
<wa-breadcrumb-item>Indoor Plants</wa-breadcrumb-item>
|
||||
<wa-breadcrumb-item>Orchids</wa-breadcrumb-item>
|
||||
<wa-breadcrumb-item>Jupiter Moth Orchid</wa-breadcrumb-item>
|
||||
</wa-breadcrumb>
|
||||
<div class="wa:container wa:product-overview">
|
||||
<div class="wa:arrange">
|
||||
<div class="wa:product-overview:hero">
|
||||
<img src="https://images.pexels.com/photos/1021386/pexels-photo-1021386.jpeg" alt="">
|
||||
</div>
|
||||
<div class="wa:product-overview:description wa:block-flow:2xl">
|
||||
<div class="wa:product-overview:summary wa:block-flow:s">
|
||||
<wa-badge>20% Off</wa-badge>
|
||||
<h1>Jupiter Moth Orchid</h1>
|
||||
<p class="wa:product-overview:price"><s>$35</s> $28</p>
|
||||
<div class="wa:product-overview:rating wa:arrange:flex:gap-s">
|
||||
<wa-rating label="average stars" readonly precision="0.1" value="4.7"></wa-rating>
|
||||
<a href="#product-reviews"><small>419 reviews</small></a>
|
||||
</div>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</div>
|
||||
<div class="wa:product-overview:actions wa:arrange:flex:gap-s">
|
||||
<wa-input type="number" value="1" min="1" max="10"></wa-input>
|
||||
<wa-button class="wa:fill_space" variant="brand">Add to cart</wa-button>
|
||||
</div>
|
||||
<div class="wa:product-overview:details wa:block-flow:s">
|
||||
<wa-details summary="Details">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
|
||||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</wa-details>
|
||||
<wa-details summary="Care instructions">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
|
||||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</wa-details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:container wa:product-reviews" id="product-reviews">
|
||||
<wa-tab-group>
|
||||
<wa-tab slot="nav" panel="reviews">Reviews</wa-tab>
|
||||
<wa-tab slot="nav" panel="questions">Questions</wa-tab>
|
||||
<wa-tab-panel name="reviews" style="margin-top:var(--wa-space-s);">
|
||||
<div class="wa:arrange:aside-start">
|
||||
<div class="wa:product-reviews:overview wa:block-flow:2xl">
|
||||
<h2>Ratings and reviews</h2>
|
||||
<div class="wa:block-flow:s">
|
||||
<div class="wa:product-reviews:summary wa:arrange:flex:gap-s">
|
||||
<h3 class="wa:arrange:flex:gap-s">
|
||||
4.7
|
||||
<wa-rating label="average stars" readonly precision="0.1" value="4.7"></wa-rating>
|
||||
</h3>
|
||||
<small>Based on 419 reviews</small>
|
||||
</div>
|
||||
<div class="wa:product-reviews:breakdown">
|
||||
<ol>
|
||||
<li class="wa:arrange:flex:gap-s">
|
||||
<span>5</span>
|
||||
<wa-icon name="star"></wa-icon>
|
||||
<wa-progress-bar class="wa:fill_space" value="82"></wa-progress-bar>
|
||||
<span>340</span>
|
||||
</li>
|
||||
<li class="wa:arrange:flex:gap-s">
|
||||
<span>4</span>
|
||||
<wa-icon name="star"></wa-icon>
|
||||
<wa-progress-bar class="wa:fill_space" value="12"></wa-progress-bar>
|
||||
<span>53</span>
|
||||
</li>
|
||||
<li class="wa:arrange:flex:gap-s">
|
||||
<span>3</span>
|
||||
<wa-icon name="star"></wa-icon>
|
||||
<wa-progress-bar class="wa:fill_space" value="6"></wa-progress-bar>
|
||||
<span>24</span>
|
||||
</li>
|
||||
<li class="wa:arrange:flex:gap-s">
|
||||
<span>2</span>
|
||||
<wa-icon name="star"></wa-icon>
|
||||
<wa-progress-bar class="wa:fill_space" value="0"></wa-progress-bar>
|
||||
<span>0</span>
|
||||
</li>
|
||||
<li class="wa:arrange:flex:gap-s">
|
||||
<span>1</span>
|
||||
<wa-icon name="star"></wa-icon>
|
||||
<wa-progress-bar class="wa:fill_space" value="1"></wa-progress-bar>
|
||||
<span>2</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
<div class="wa:block-flow:s">
|
||||
<h3>Happy with your purchase?</h3>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
<wa-button outline size="small" style="width: 100%;">Write a review</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wa:product-reviews:list wa:block-flow:2xl">
|
||||
<div class="wa:product-reviews:review wa:block-flow:s">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<div class="wa:product-reviews:attribution">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<strong>Cory L.</strong> <wa-tag variant="success" size="small"><wa-icon name="check" style="margin-inline-end:var(--wa-space-2xs);"></wa-icon>Verified</wa-tag>
|
||||
</div>
|
||||
<small><wa-format-date month="long" day="numeric" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
</div>
|
||||
<wa-rating label="Rating" readonly value="5"></wa-rating>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</div>
|
||||
<div class="wa:product-reviews:review wa:block-flow:s">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<div class="wa:product-reviews:attribution">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<strong>Konnor R.</strong> <wa-tag variant="success" size="small"><wa-icon name="check" style="margin-inline-end:var(--wa-space-2xs);"></wa-icon>Verified</wa-tag>
|
||||
</div>
|
||||
<small><wa-format-date date="2023-11-16T09:17:00-04:00" month="long" day="numeric" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
</div>
|
||||
<wa-rating label="Rating" readonly value="4"></wa-rating>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</div>
|
||||
<div class="wa:product-reviews:review wa:block-flow:s">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<div class="wa:product-reviews:attribution">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<strong>Kelsey J.</strong> <wa-tag variant="success" size="small"><wa-icon name="check" style="margin-inline-end:var(--wa-space-2xs);"></wa-icon>Verified</wa-tag>
|
||||
</div>
|
||||
<small><wa-format-date date="2023-10-31T09:17:00-04:00" month="long" day="numeric" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
</div>
|
||||
<wa-rating label="Rating" readonly value="5"></wa-rating>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</div>
|
||||
<div class="wa:product-reviews:review wa:block-flow:s">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<wa-avatar label="User avatar"></wa-avatar>
|
||||
<div class="wa:product-reviews:attribution">
|
||||
<div class="wa:arrange:flex:gap-s">
|
||||
<strong>Lindsay M.</strong>
|
||||
</div>
|
||||
<small><wa-format-date date="2023-07-03T09:17:00-04:00" month="long" day="numeric" year="numeric"></wa-format-date></small>
|
||||
</div>
|
||||
</div>
|
||||
<wa-rating label="Rating" readonly value="5"></wa-rating>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</div>
|
||||
<wa-button outline size="small" style="width: 100%;">Load more reviews</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</wa-tab-panel>
|
||||
<wa-tab-panel name="questions">
|
||||
questions
|
||||
</wa-tab-panel>
|
||||
</wa-tab-group>
|
||||
</div>
|
||||
<div class="wa:container wa:product-list-simple">
|
||||
<h2>You may also like</h2>
|
||||
<div class="wa:product-list-simple:items wa:arrange:by-two:size-s">
|
||||
<wa-card>
|
||||
<div class="wa:frame:square" slot="image">
|
||||
<img src="https://images.pexels.com/photos/4076594/pexels-photo-4076594.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
Triumph Tulip<br>
|
||||
<strong>$14</strong><br>
|
||||
</wa-card>
|
||||
<wa-card>
|
||||
<div class="wa:frame:square" slot="image">
|
||||
<img src="https://images.pexels.com/photos/4994350/pexels-photo-4994350.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
White Doll's Daisy<br>
|
||||
<strong>$18</strong>
|
||||
</wa-card>
|
||||
<wa-card>
|
||||
<div class="wa:frame:square" slot="image">
|
||||
<img src="https://images.pexels.com/photos/2223890/pexels-photo-2223890.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
Common Poppy<br>
|
||||
<strong>$32</strong>
|
||||
</wa-card>
|
||||
<wa-card>
|
||||
<div class="wa:frame:square" slot="image">
|
||||
<img src="https://images.pexels.com/photos/1179026/pexels-photo-1179026.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="">
|
||||
</div>
|
||||
Stargazer Lily<br>
|
||||
<strong>$39</strong>
|
||||
</wa-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
meta:
|
||||
title: Patterns
|
||||
description: TBD
|
||||
toc: false
|
||||
---
|
||||
|
||||
<!-- cSpell:dictionaries lorem-ipsum -->
|
||||
|
||||
<style>
|
||||
.code-preview__preview > *:first-of-type {
|
||||
/* transform: scale(0.5); */
|
||||
}
|
||||
.code-preview {
|
||||
width: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
# Patterns
|
||||
|
||||
## Full demos
|
||||
|
||||
- [Ecommerce: Product Page](/experimental/demo_patterns/ecommerce_product_page)
|
||||
- [Blog: Listing Page](/experimental/demo_patterns/blog_listing)
|
||||
- [Blog: Post Page](/experimental/demo_patterns/blog_post)
|
||||
- [Dashboard](/experimental/demo_patterns/dashboard)
|
||||
|
||||
## Isolated patterns
|
||||
|
||||
- [Blog Post](/experimental/demo_patterns/blog_patterns)
|
||||
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 308 B |
|
Before Width: | Height: | Size: 356 B After Width: | Height: | Size: 356 B |
|
Before Width: | Height: | Size: 786 B After Width: | Height: | Size: 786 B |
|
Before Width: | Height: | Size: 607 B After Width: | Height: | Size: 607 B |
|
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 872 B After Width: | Height: | Size: 872 B |
|
Before Width: | Height: | Size: 465 B After Width: | Height: | Size: 465 B |
|
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 770 B |
|
Before Width: | Height: | Size: 330 B After Width: | Height: | Size: 330 B |
|
Before Width: | Height: | Size: 754 B After Width: | Height: | Size: 754 B |
|
Before Width: | Height: | Size: 812 B After Width: | Height: | Size: 812 B |
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 465 B After Width: | Height: | Size: 465 B |
|
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B |
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
|
Before Width: | Height: | Size: 267 B After Width: | Height: | Size: 267 B |
|
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 460 B |
|
Before Width: | Height: | Size: 333 B After Width: | Height: | Size: 333 B |
|
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 337 B |
|
Before Width: | Height: | Size: 383 B After Width: | Height: | Size: 383 B |
|
Before Width: | Height: | Size: 272 B After Width: | Height: | Size: 272 B |
|
Before Width: | Height: | Size: 421 B After Width: | Height: | Size: 421 B |
|
Before Width: | Height: | Size: 525 B After Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 1003 B After Width: | Height: | Size: 1003 B |
|
Before Width: | Height: | Size: 619 B After Width: | Height: | Size: 619 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 456 B |
|
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 387 B |
|
Before Width: | Height: | Size: 973 B After Width: | Height: | Size: 973 B |
|
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 334 B |
|
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
|
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 402 B |
|
Before Width: | Height: | Size: 225 B After Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 423 B After Width: | Height: | Size: 423 B |
|
Before Width: | Height: | Size: 789 B After Width: | Height: | Size: 789 B |
|
Before Width: | Height: | Size: 360 B After Width: | Height: | Size: 360 B |
|
Before Width: | Height: | Size: 267 B After Width: | Height: | Size: 267 B |
|
Before Width: | Height: | Size: 998 B After Width: | Height: | Size: 998 B |
|
Before Width: | Height: | Size: 399 B After Width: | Height: | Size: 399 B |
|
Before Width: | Height: | Size: 574 B After Width: | Height: | Size: 574 B |
|
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 454 B |
|
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 919 B |
|
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 375 B |
|
Before Width: | Height: | Size: 427 B After Width: | Height: | Size: 427 B |
|
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 308 B |
|
Before Width: | Height: | Size: 443 B After Width: | Height: | Size: 443 B |
|
Before Width: | Height: | Size: 492 B After Width: | Height: | Size: 492 B |