1
0
mirror of https://github.com/kognise/water.css.git synced 2025-08-09 06:37:05 +02:00

Merge branch 'documentation' into development

This commit is contained in:
Felix Mattick
2022-01-21 13:09:54 -06:00
15 changed files with 706 additions and 323 deletions

View File

@@ -0,0 +1,5 @@
---
"water.css": minor
---
Add description list styles

View File

@@ -0,0 +1,5 @@
---
"water.css": patch
---
Fix lack of top margin in details children

View File

@@ -0,0 +1,5 @@
---
"water.css": minor
---
Add header styles, change footer margin to last-of-type only

109
docs/docs.html Normal file
View File

@@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="en">
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Element Docs | Water.css</title>
<link rel="canonical" href="https://watercss.kognise.dev/docs.html" />
<meta
name="description"
content="Get started with Water.css, a drop-in collection of classless CSS styles."
/>
<link rel="apple-touch-icon" sizes="180x180" href="./icons/apple-touch-icon.png" />
<link rel="icon" id="icon-16" type="image/png" sizes="16x16" href="./icons/favicon-16x16.png" />
<link rel="icon" id="icon-32" type="image/png" sizes="32x32" href="./icons/favicon-32x32.png" />
<link rel="manifest" href="./site.webmanifest" />
<link rel="mask-icon" href="./icons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="shortcut icon" id="icon-ico" href="./icons/favicon.ico" />
<meta name="apple-mobile-web-app-title" content="Water.css" />
<meta name="application-name" content="Water.css" />
<meta name="msapplication-TileColor" content="#00aba9" />
<meta name="msapplication-config" content="./icons/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" />
<!-- Startup styles of water.css, so styles don't have to wait until JS is loaded -->
<link rel="stylesheet" id="js-startup-stylesheet" href="./water.css/water.min.css" />
<!-- Dynamic version of water.css, overwrites startup styles. JavaScript sets & updates href -->
<link rel="stylesheet" id="js-stylesheet" />
<!-- Custom styles for the documentation / version picker -->
<link rel="stylesheet" href="style.css" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://watercss.kognise.dev/docs.html" />
<meta property="og:title" content="Element Docs" />
<meta property="og:site_name" content="Water.css" />
<meta
property="og:description"
content="Get started with Water.css, a drop-in collection of classless CSS styles."
/>
<meta
property="og:image"
content="https://raw.githubusercontent.com/kognise/water.css/master/assets/logo.png"
/>
<meta property="og:image:width" content="1154" />
<meta property="og:image:height" content="444" />
<script>
// eslint-disable-next-line no-useless-escape
window.navigator.clipboard || document.write('<script src="https://unpkg.com/clipboard-polyfill@2.8.6/dist/clipboard-polyfill.promise.js"><\/script>')
</script>
<!-- Use bright favicons when the browser is in dark mode. -->
<script type="module">
import faviconSwitcher from 'https://unpkg.com/favicon-mode-switcher@1.0.4/dist/index.min.mjs'
faviconSwitcher([
{ element: '#icon-ico', href: { dark: './icons/light-favicon.ico' } },
{ element: '#icon-16', href: { dark: './icons/light-favicon-16x16.png' } },
{ element: '#icon-32', href: { dark: './icons/light-favicon-32x32.png' } }
])
</script>
</head>
<body>
<form id="theme-form" class="top-theme-form">
<input type="radio" value="auto" checked name="theme" id="theme-auto" />
<label for="theme-auto">Automatic 🌙 / ☀</label>
<input type="radio" value="dark" name="theme" id="theme-dark" />
<label for="theme-dark">Dark theme 🌙</label>
<input type="radio" value="light" name="theme" id="theme-light" />
<label for="theme-light">Light theme ☀</label>
</form>
<header>
<h1>Element Docs</h1>
<p>
Get started with Water.css, a drop-in collection of classless CSS styles.
</p>
<h2>Table of contents</h2>
<ul id="toc"></ul>
</header>
<main id="demos"></main>
<footer>
<a href="#">Back to top ⬆</a>
</footer>
<dialog id="dialog">
<header>This is a sample dialog</header>
<form method="dialog">
<p>What is your favorite pet animal?</p>
<menu>
<button value="feline">Cats</button>
<button value="canine">Dogs</button>
<button value="other">Others</button>
</menu>
</form>
</dialog>
<script src="scripts/docs.js"></script>
<script src="scripts/themer.js" defer></script>
</body>
</html>

View File

@@ -23,8 +23,6 @@
<meta name="theme-color" content="#ffffff" />
<!-- Startup styles of water.css, so styles don't have to wait until JS is loaded -->
<link rel="preload" as="style" href="./water.css/dark.min.css" />
<link rel="preload" as="style" href="./water.css/light.min.css" />
<link rel="stylesheet" id="js-startup-stylesheet" href="./water.css/water.min.css" />
<!-- Dynamic version of water.css, overwrites startup styles. JavaScript sets & updates href -->
@@ -37,6 +35,7 @@
<meta property="og:type" content="website" />
<meta property="og:url" content="https://watercss.kognise.dev/" />
<meta property="og:title" content="Water.css" />
<meta property="og:site_name" content="Water.css" />
<meta
property="og:description"
content="A drop-in collection of CSS styles to make simple websites like this just a little bit nicer."
@@ -74,41 +73,49 @@
</head>
<body>
<h1>Water.css</h1>
<header>
<div class="row">
<h1>Water.css</h1>
<p>
Water.css is a drop-in collection of CSS styles to make simple websites like this just a
little bit nicer.
</p>
<p>
Now you can write your simple static site with nice semantic html, and Water.css will manage
the styling for you.
</p>
<div class="row">
<div>
<a href="#installation"><b>Get it already!</b></a>
<br />
<a href="https://github.com/kognise/water.css"><b>GitHub</b></a>
<a
href="https://www.producthunt.com/posts/water-css?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-water-css"
target="_blank"
rel="noopener"
>
<img
id="product-hunt"
src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=150490&theme=dark&period=daily"
alt="Water.css - Make your tiny website just a little nicer | Product Hunt Embed"
style="width: 250px; height: 54px;"
width="250px"
height="54px"
/>
</a>
</div>
<a
href="https://www.producthunt.com/posts/water-css?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-water-css"
id="product-hunt"
target="_blank"
rel="noopener"
>
<img
src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=150490&theme=dark&period=daily"
alt="Water.css - Make your tiny website just a little nicer | Product Hunt Embed"
style="width: 250px; height: 54px;"
width="250px"
height="54px"
/>
</a>
</div>
<p>
Water.css is a drop-in collection of CSS styles to make simple websites like this just a little bit nicer.
</p>
<p>
Now you can write your simple static site with nice semantic html, and Water.css will manage the styling for you.
</p>
<ul>
<li>It's responsive</li>
<li>It's easy to theme</li>
<li>It has great browser support</li>
<li>It has a tiny size</li>
<li>It doesn't require <strong>any</strong> classes</li>
<li>It looks beautiful</li>
<li>It encourages semantic code</li>
</ul>
<p>
<b>Go to <a href="/docs.html" target="_blank">element documentation</a></b> or check out the
<a href="https://github.com/kognise/water.css" target="_blank" rel="nooopener noreferrer">GitHub</a>.
</p>
</header>
<h2>Installation</h2>
<div id="installation">
<header class="row">
<h3 id="link-snippet-headline">
@@ -162,24 +169,14 @@
</table>
</div>
<h2 id="goals">Goals</h2>
<ul>
<li>Responsive</li>
<li>Good code quality</li>
<li>Good browser support</li>
<li>Small size (&lt; 2kb)</li>
<li>Beautiful</li>
<li>No classes</li>
</ul>
<h2 id="responsive">Is it responsive?</h2>
<p>
<strong>Heck yeah!</strong> It doesn't include any fancy styles so it's easily mobile
responsive. Just add the famous
<a href="https://www.w3schools.com/css/css_rwd_viewport.asp">responsive viewport tag</a> and
<strong>Heck yeah!</strong> It doesn't include any fancy styles so it's mobile
responsive by default. Just add the famous
<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#viewport_basics">responsive viewport tag</a> and
you'll be good to go!
</p>
<p>In fact, try resizing this page. Everything flows super nicely as you'll see.</p>
<p>In fact, try resizing this page. Everything will flow super nicely.</p>
<h2 id="bookmarklet">Bookmarklet</h2>
<p>
@@ -194,182 +191,7 @@
</a>
</strong>
<h2 id="demo">Element demos</h2>
<p>This is supposed to be a demo page so we need more elements!</p>
<h3 id="form-elements">Form elements</h3>
<form onsubmit="return false;">
<label for="email">Email</label>
<input type="email" name="email" id="email" placeholder="john.doe@gmail.com" />
<label for="id">User id (read only)</label>
<input readonly name="id" id="id" value="04D6H89Z" />
<label for="disabled">Random disabled input</label>
<input disabled name="disabled" id="disabled" placeholder="Because why not?" />
<label for="about">About me</label>
<textarea name="about" id="about" placeholder="I am a textarea..."></textarea>
<label for="rating">Rate this site</label>
<input name="rating" id="rating" type="range" min="1" max="10"></input>
<label for="flavor">Choose a flavor</label>
<select name="flavor" id="flavor">
<option>Chocolate</option>
<option>Strawberry</option>
<option>Vanilla</option>
</select>
<fieldset>
<legend>Choose a Doe</legend>
<div>
<input type="radio" id="john" name="drone" value="john" checked />
<label for="john">John Doe</label>
</div>
<div>
<input type="radio" id="jane" name="drone" value="jane" />
<label for="jane">Jane Doe</label>
</div>
<div>
<input type="radio" id="johnny" name="drone" value="johnny" />
<label for="johnny">Johnny Doe</label>
</div>
</fieldset>
<br />
<input type="checkbox" name="remember" id="remember" checked />
<label for="remember">Remember me</label>
<input type="submit" value="Submit" />
<input type="reset" value="Reset" />
</form>
<h3 id="code">Code</h3>
<p>
Below is some code, you can copy it with <kbd>Ctrl-C</kbd>. Did you know,
<code>alert(1)</code> can show an alert in JavaScript!
</p>
<pre><code>// This logs a message to the console and check out the scrollbar.<br>console.log('Hello, world!')</code></pre>
<h3 id="other">Other</h3>
<p>Here's a horizontal rule and image because I don't know where else to put them.</p>
<img src="https://placekitten.com/408/287" alt="Example kitten" />
<hr />
<p>And here's a nicely marked up table!</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Godzilla</td>
<td>2</td>
<td>$299.99</td>
</tr>
<tr>
<td>Mozilla</td>
<td>10</td>
<td>$100,000.00</td>
</tr>
<tr>
<td>Quesadilla</td>
<td>1</td>
<td>$2.22</td>
</tr>
</tbody>
</table>
<details>
<summary>Some summary/details can't hurt!</summary>
<p>Lorem ipsum dolor sit blah blah.</p>
</details>
<p>The dialog (form, and menu) tag</p>
<div>
<button type="button" id="dialog-trigger">
Show me the dialog!
</button>
<span id="dialog-result"></span>
</div>
<dialog id="dialog">
<header>This is a sample dialog</header>
<form method="dialog">
<p>What is your favorite pet animal?</p>
<menu>
<button value="feline">Cats</button>
<button value="canine">Dogs</button>
<button value="other">Others</button>
</menu>
</form>
</dialog>
<h3 id="typography">Typography</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dictum hendrerit velit, quis
ullamcorper sem congue ac. Quisque id magna rhoncus, sodales massa vel, vestibulum elit. Duis
ornare accumsan egestas. Proin maximus lacus interdum leo molestie convallis. Orci varius
natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut iaculis risus eu
felis feugiat, eu mollis neque elementum. Donec interdum, nisl id dignissim iaculis, felis dui
aliquet dui, non fermentum velit lectus ac quam. Class aptent taciti sociosqu ad litora
torquent per conubia nostra, per inceptos himenaeos.
<strong>This is strong,</strong> this is normal, <b>this is just bold,</b>
<em>and this is emphasized!</em> And heck, <a href="/">here</a>'s a link.
</p>
<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote">
"The HTML blockquote Element (or HTML Block Quotation Element) indicates that the enclosed
text is an extended quotation. Usually, this is rendered visually by indentation (see
<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote#Usage_notes"
>Notes</a
>
for how to change it). A URL for the source of the quotation may be given using the
<code>cite</code> attribute, while a text representation of the source can be given using the
<code>&lt;cite&gt;</code> cite element."
<footer>
<cite>MDN, "The Block Quotation element"</cite>
</footer>
</blockquote>
<ul>
<li>Unordered list item 1</li>
<li>Unordered list item 2</li>
<li>Unordered list item 3</li>
</ul>
<ol>
<li>Ordered list item 1</li>
<li>Ordered list item 2</li>
<li>Ordered list item 3</li>
</ol>
<p>Addresses are also styled to be <strong>awesome</strong>!</p>
<address>
<a href="mailto:john.doe@example.com">john.doe@example.com</a><br />
<a href="tel:778-330-2389">778-330-2389</a><br />
<a href="sms:666-666-6666">666-666-6666</a><br />
</address>
<br />
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
<footer>
<a href="#">Back to top ⬆</a>
</footer>
<script src="script.js" defer></script>
<script src="scripts/themer.js" defer></script>
<script src="scripts/index.js" defer></script>
</body>
</html>

View File

@@ -1,88 +0,0 @@
'use strict'
const localBase = './water.css/'
const fileSizes = {
dark: 2.57,
light: 2.55,
auto: 3.27
}
const themeForm = document.getElementById('theme-form')
const stylesheet = document.getElementById('js-stylesheet')
const startupStylesheet = document.getElementById('js-startup-stylesheet')
const productHunt = document.querySelector('#product-hunt > img')
const copyButton = document.getElementById('copy-button')
const copyButtonFeedback = document.getElementById('copy-button-feedback')
const linkSnippets = [].slice.call(document.querySelectorAll('#link-snippet-container > pre'))
const table = {
fileName: document.getElementById('table-file-name'),
fileSize: document.getElementById('table-file-size'),
theme: document.getElementById('table-theme')
}
const prefersColorScheme = window.matchMedia('(prefers-color-scheme: light)')
const updateProductHunt = (theme) => {
theme = theme || (prefersColorScheme.matches ? 'light' : 'dark')
productHunt.src = `https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=150490&theme=${theme}&period=daily`
}
const updateTheme = () => {
const theme = themeForm.querySelector('input[name="theme"]:checked').value
const fileName = `${theme === 'auto' ? 'water' : theme}.min.css`
const localUrl = `${localBase}${fileName}`
stylesheet.href = localUrl
for (const snippet of linkSnippets) {
snippet.hidden = snippet.id.indexOf(theme) === -1
}
table.fileName.innerText = fileName
table.fileSize.innerText = `${fileSizes[theme].toFixed(2)} kb`
if (theme === 'auto') {
updateProductHunt()
table.theme.innerHTML = `
Respects user-defined theme settings using <a style="--links: var(--code)" href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme" target="_blank" rel="noopener"><code>prefers-color-scheme</code></a>.<br>
Light in browsers where the theme settings can't be detected.
`
} else {
updateProductHunt(theme)
table.theme.innerText = `Theme is forced to ${theme}.`
}
}
themeForm.addEventListener('change', updateTheme)
updateProductHunt()
prefersColorScheme.addListener(() => {
if (themeForm.theme.value !== 'auto') return
updateProductHunt()
})
updateTheme()
startupStylesheet.parentElement.removeChild(startupStylesheet)
copyButton.addEventListener('click', () => {
const clipboard = navigator.clipboard || window.clipboard
const theme = themeForm.querySelector('input[name="theme"]:checked').value
const snippetText = document.querySelector(`#link-snippet-${theme} code`).textContent
clipboard.writeText(snippetText)
.then(() => { copyButtonFeedback.textContent = '✔' })
.catch(() => { copyButtonFeedback.textContent = '❌' })
.then(() => setTimeout(() => { copyButtonFeedback.textContent = '' }, 1000))
})
document.getElementById('dialog-trigger').addEventListener('click', () => {
document.getElementById('dialog-result').innerText = ''
document.getElementById('dialog').showModal()
})
document.getElementById('dialog').addEventListener('close', (event) => {
document.getElementById('dialog-result').innerText = `Your answer: ${event.target.returnValue}`
})

407
docs/scripts/docs.js Normal file
View File

@@ -0,0 +1,407 @@
const categories = [
{
id: 'typography',
name: 'Typography',
description: 'HTML, being a markup language, has abundantly clear semantics for basic typography. Water.css leaves those semantics untouched.',
snippets: [
{
id: 'copy',
name: 'Headings and copy',
code: `
<h1>Heading 1</h1>
<p>
This is a paragraph that could contain long-form text. Heck, <a href="#">here's a link</a>.
<strong>This is important,</strong> this is normal, <em>and this is emphasized!</em>
</p>
<p>This is another paragraph that could contain long-form text.</p>
<h2>Heading 2</h2>
<p>You probably get the idea by now!</p>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h5>Heading 6</h5>
`
},
{
id: 'quotes',
name: 'Quotes',
code: `
<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote">
"The HTML blockquote Element (or HTML Block Quotation Element) indicates that the enclosed text is an extended quotation. Usually, this is rendered visually by indentation (see <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote#Usage_notes">Notes</a> for how to change it). A URL for the source of the quotation may be given using the <code>cite</code> attribute, while a text representation of the source can be given using the <code>&lt;cite&gt;</code> cite element."
<footer>
<cite>MDN, "The Block Quotation element"</cite>
</footer>
</blockquote>
<p>
Did you know HTML supports inline quotes? I didn't, until I read that
<q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">
the <code>&lt;q&gt;</code> HTML element indicates that the enclosed text is a short inline quotation
</q>.
</p>
`
},
{
id: 'lists',
name: 'Lists',
code: `
<ul>
<li>Unordered list item 1</li>
<li>Unordered list item 2</li>
<li>Unordered list item 3</li>
</ul>
<ol>
<li>Ordered list item 1</li>
<li>Ordered list item 2</li>
<li>Ordered list item 3</li>
</ol>
<dl>
<dt>Unordered lists</dt>
<dd>Represents an unordered list of items, typically rendered as a bulleted list</dd>
<dt>Ordered lists</dt>
<dd>Represents an ordered list of items, typically rendered as a numbered list</dd>
<dt>Description lists</dt>
<dd>Encloses a list of groups of terms and descriptions</dd>
<dd>Not commonly used, but still nifty</dd>
</dl>
`
},
{
id: 'code-etc',
name: 'Code samples, keyboard shortcuts, oh my',
code: `
<p>
Below is some code. If you select it, you can copy using <kbd>Ctrl-C</kbd>.
Did you know that <code>alert(1)</code> can show an alert in JavaScript?
</p>
<pre><code>// This logs a message to the console and check out the scrollbar.
console.log('Hello, world!')</code></pre>
<p>HTML also has elements for <var>variables</var> and sample output: <samp>Hello, world!</samp></p>
`
}
]
},
{
id: 'forms',
name: 'Form controls',
description: 'Water.css provides a set of styles for form controls, including text inputs, select boxes, buttons, and more.',
snippets: [
{
id: 'text-inputs',
name: 'Text inputs',
code: `
<form onsubmit="return false;">
<label for="email">Email</label>
<input type="email" name="email" id="email" placeholder="john.doe@gmail.com" />
<label for="id">User id (read only)</label>
<input readonly name="id" id="id" value="04D6H89Z" />
<label for="disabled">Random disabled input</label>
<input disabled name="disabled" id="disabled" placeholder="Because why not?" />
<label for="about">About me</label>
<textarea name="about" id="about" placeholder="I am a textarea..."></textarea>
</form>
`
},
{
id: 'buttons',
name: 'Buttons',
code: `
<button onclick="alert('Clicked!')">Hey look, a button!</button>
<br>
<form onsubmit="alert('Form submitted!'); return false;">
<label for="name-field">Your name</label>
<input type="text" id="name-field" name="name" />
<input type="submit" value="Submit" />
<input type="reset" value="Reset" />
</form>
`
},
{
id: 'assorted-inputs',
name: 'Assorted other controls',
code: `
<form onsubmit="return false;">
<label for="rating">Rate this site</label>
<input name="rating" id="rating" type="range" min="1" max="10"></input>
<label for="flavor">Choose a flavor</label>
<select name="flavor" id="flavor">
<option>Chocolate</option>
<option>Strawberry</option>
<option>Vanilla</option>
</select>
<fieldset>
<legend>Choose a Doe</legend>
<div>
<input type="radio" id="john" name="drone" value="john" checked />
<label for="john">John Doe</label>
</div>
<div>
<input type="radio" id="jane" name="drone" value="jane" />
<label for="jane">Jane Doe</label>
</div>
<div>
<input type="radio" id="johnny" name="drone" value="johnny" />
<label for="johnny">Johnny Doe</label>
</div>
</fieldset>
<input type="checkbox" name="remember" id="remember" checked />
<label for="remember">Remember me</label>
</form>
`
},
{
id: 'dialogs',
name: 'Dialogs',
caniuse: 'https://caniuse.com/dialog',
code: `
<div>
<button type="button" id="dialog-trigger">
Show me the dialog!
</button>
<span id="dialog-result"></span>
</div>
<dialog id="dialog">
<header>This is a sample dialog</header>
<form method="dialog">
<p>What is your favorite pet animal?</p>
<menu>
<button value="feline">Cats</button>
<button value="canine">Dogs</button>
<button value="other">Others</button>
</menu>
</form>
</dialog>
<script>
document.getElementById('dialog-trigger').addEventListener('click', () => {
document.getElementById('dialog-result').innerText = ''
document.getElementById('dialog').showModal()
})
document.getElementById('dialog').addEventListener('close', (event) => {
document.getElementById('dialog-result').innerText = \`Your answer: \${event.target.returnValue}\`
})
</script>
`,
realCode: `
<div>
<button type="button" id="dialog-trigger">
Show me the dialog!
</button>
<span id="dialog-result"></span>
</div>
`
}
]
},
{
id: 'misc',
name: 'Miscellaneous',
description: 'Styles are also provided for various other elements that don\'t strictly fit into the other categories. These include tables, dialogs, and images.',
snippets: [
{
id: 'tables',
name: 'Tables',
code: `
<table>
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Godzilla</td>
<td>2</td>
<td>$299.99</td>
</tr>
<tr>
<td>Mozilla</td>
<td>10</td>
<td>$100,000.00</td>
</tr>
<tr>
<td>Quesadilla</td>
<td>1</td>
<td>$2.22</td>
</tr>
</tbody>
</table>
`
},
{
id: 'details',
name: 'Summary/details',
caniuse: 'https://caniuse.com/details',
code: `
<details>
<summary>Some summary/details can't hurt!</summary>
<p>Lorem ipsum dolor sit blah blah.</p>
</details>
`
},
{
id: 'rules-etc',
name: 'Rules, images, and addresses',
code: `
<p>Here's a horizontal rule and image because I don't know where else to put them.</p>
<img src="https://placekitten.com/408/287" alt="Example kitten" />
<hr />
<p>Addresses are also styled to be <strong>awesome</strong>!</p>
<address>
<a href="mailto:john.doe@example.com">john.doe@example.com</a><br>
<a href="tel:778-330-2389">778-330-2389</a><br>
<a href="sms:666-666-6666">666-666-6666</a><br>
</address>
`
}
]
}
]
const tocContainer = document.getElementById('toc')
for (const category of categories) {
const li = document.createElement('li')
const a = document.createElement('a')
a.href = `#${category.id}`
a.innerText = category.name
li.appendChild(a)
const ul = document.createElement('ul')
for (const snippet of category.snippets) {
const li = document.createElement('li')
const a = document.createElement('a')
a.href = `#${snippet.id}`
a.innerText = snippet.name
li.appendChild(a)
ul.appendChild(li)
}
li.appendChild(ul)
tocContainer.appendChild(li)
}
const demosContainer = document.getElementById('demos')
let first = true
for (const category of categories) {
const h2 = document.createElement('h2')
h2.id = category.id
h2.innerText = category.name
demosContainer.appendChild(h2)
const p = document.createElement('p')
p.innerText = category.description
demosContainer.appendChild(p)
for (const snippet of category.snippets) {
const h3 = document.createElement('h3')
h3.id = snippet.id
h3.innerText = snippet.name
demosContainer.appendChild(h3)
if (snippet.caniuse) {
const p = document.createElement('p')
p.innerText = '⚠️ This may not be supported in all browsers. '
const a = document.createElement('a')
a.href = snippet.caniuse
a.target = '_blank'
a.rel = 'noopener noreferrer'
a.innerText = 'See caniuse for more info.'
p.appendChild(a)
demosContainer.appendChild(p)
}
const pre = document.createElement('pre')
const code = document.createElement('code')
code.innerText = snippet.code.trim()
code.style.position = 'relative'
const button = document.createElement('button')
button.innerText = 'Copy'
Object.assign(button.style, {
position: 'absolute',
top: '0',
right: '0',
margin: '6px',
padding: '8px'
})
let timeout = null
button.addEventListener('click', () => {
navigator.clipboard.writeText(snippet.code.trim())
button.innerText = 'Copied!'
clearTimeout(timeout)
timeout = setTimeout(() => { button.innerText = 'Copy' }, 1000)
})
code.appendChild(button)
pre.appendChild(code)
demosContainer.appendChild(pre)
const details = document.createElement('details')
details.id = `${snippet.id}-details`
details.innerHTML = snippet.realCode || snippet.code
// Execute any scripts in the HTML.
Array.from(details.querySelectorAll('script')).forEach((oldScript) => {
const newScript = document.createElement('script')
for (const { name, value } of oldScript.attributes) { newScript.setAttribute(name, value) }
newScript.appendChild(document.createTextNode(oldScript.innerHTML))
oldScript.parentNode.replaceChild(newScript, oldScript)
})
const summary = document.createElement('summary')
summary.innerText = 'Show output'
details.prepend(summary)
demosContainer.appendChild(details)
if (first) {
details.open = true
first = false
let firstToggle = true
details.addEventListener('toggle', () => {
if (!details.open || firstToggle) return
firstToggle = false
history.pushState({}, '', '#' + snippet.id)
})
} else {
details.addEventListener('toggle', () => {
if (!details.open) return
history.pushState({}, '', '#' + snippet.id)
})
}
}
}
const hashChange = () => {
const details = document.getElementById(`${window.location.hash.slice(1)}-details`)
if (!details) return
details.open = true
}
window.addEventListener('hashchange', hashChange, false)
hashChange()
// Dialog demo scripting.
document.getElementById('dialog-trigger').addEventListener('click', () => {
document.getElementById('dialog-result').innerText = ''
document.getElementById('dialog').showModal()
})
document.getElementById('dialog').addEventListener('close', (event) => {
document.getElementById('dialog-result').innerText = `Your answer: ${event.target.returnValue}`
})

14
docs/scripts/index.js Normal file
View File

@@ -0,0 +1,14 @@
const copyButton = document.getElementById('copy-button')
const copyButtonFeedback = document.getElementById('copy-button-feedback')
const themeForm = document.getElementById('theme-form')
copyButton.addEventListener('click', () => {
const clipboard = navigator.clipboard || window.clipboard
const theme = themeForm.querySelector('input[name="theme"]:checked').value
const snippetText = document.querySelector(`#link-snippet-${theme} code`).textContent
clipboard.writeText(snippetText)
.then(() => { copyButtonFeedback.textContent = '✅' })
.catch(() => { copyButtonFeedback.textContent = '❌' })
.then(() => setTimeout(() => { copyButtonFeedback.textContent = '' }, 1000))
})

73
docs/scripts/themer.js Normal file
View File

@@ -0,0 +1,73 @@
'use strict'
const localBase = './water.css/'
const fileSizes = {
dark: 2.57,
light: 2.55,
auto: 3.27
}
const themeForm = document.getElementById('theme-form')
const stylesheet = document.getElementById('js-stylesheet')
const startupStylesheet = document.getElementById('js-startup-stylesheet')
const productHunt = document.getElementById('product-hunt')
const linkSnippets = [...document.querySelectorAll('#link-snippet-container > pre')]
const table = {
fileName: document.getElementById('table-file-name'),
fileSize: document.getElementById('table-file-size'),
theme: document.getElementById('table-theme')
}
const prefersColorScheme = window.matchMedia('(prefers-color-scheme: light)')
const updateProductHunt = (theme) => {
if (!productHunt) return
theme = theme || (prefersColorScheme.matches ? 'light' : 'dark')
productHunt.src = `https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=150490&theme=${theme}&period=daily`
}
const updateTheme = () => {
const theme = document.querySelector('input[name="theme"]:checked').value
localStorage.setItem('theme', theme)
const fileName = `${theme === 'auto' ? 'water' : theme}.min.css`
const localUrl = `${localBase}${fileName}`
stylesheet.href = localUrl
for (const snippet of linkSnippets) {
snippet.hidden = snippet.id.indexOf(theme) === -1
}
if (table.theme) {
table.fileName.innerText = fileName
table.fileSize.innerText = `${fileSizes[theme].toFixed(2)} kb`
if (theme === 'auto') {
updateProductHunt()
table.theme.innerHTML = `
Respects user-defined theme settings using <a style="--links: var(--code)" href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme" target="_blank" rel="noopener"><code>prefers-color-scheme</code></a>.<br>
Light in browsers where the theme settings can't be detected.
`
} else {
updateProductHunt(theme)
table.theme.innerText = `Theme is forced to ${theme}.`
}
}
}
const storedTheme = localStorage.getItem('theme')
if (storedTheme) {
themeForm.querySelector(`input[name="theme"][value="${storedTheme}"]`).checked = true
}
updateTheme()
themeForm.addEventListener('change', updateTheme)
startupStylesheet.parentElement.removeChild(startupStylesheet)
prefersColorScheme.addListener(() => {
if (themeForm.theme.value !== 'auto') return
updateProductHunt()
})

View File

@@ -1,7 +1,3 @@
html {
scroll-behavior: smooth;
}
#product-hunt {
margin-top: 1rem;
}
@@ -63,3 +59,14 @@ body > footer {
align-items: center;
justify-content: space-between;
}
/* Hmmm yes great class name */
.top-theme-form {
padding: 10px 0;
top: 0;
width: 100%;
position: sticky;
margin-top: -20px;
z-index: 999;
background: var(--background-body);
}

View File

@@ -19,7 +19,7 @@ const postcssImport = require('postcss-import')
const postcssInlineSvg = require('postcss-inline-svg')
const paths = {
docs: { src: 'docs/**', dest: 'out/docs' },
docs: { src: 'docs/**/*', dest: 'out/docs' },
styles: { src: 'src/builds/*.css', dest: 'out', watch: 'src/**/*.css' }
}
@@ -89,8 +89,8 @@ const docs = () => {
return (
gulp
// Exclude all HTML files but index.html
.src(paths.docs.src, { ignore: '**/!(index).html' })
// Exclude all HTML files except for those ending with .html
.src(paths.docs.src, { ignore: '**/!(*).html' })
// * Process HTML *
.pipe(htmlOnly)

View File

@@ -6,7 +6,7 @@
"scripts": {
"build": "gulp build",
"dev": "gulp watch",
"lint:js": "eslint bookmarklet/original.js docs/script.js docs/index.html gulpfile.js",
"lint:js": "eslint bookmarklet/original.js docs/scripts/*.js docs/*.html gulpfile.js",
"lint:css": "stylelint src/**/*.css docs/style.css",
"lint": "yarn lint:js --fix && yarn lint:css --fix",
"accessibility": "yarn build && node accessibility.js",

View File

@@ -114,7 +114,7 @@ summary:focus {
text-decoration: underline;
}
details > :not(summary) {
details > :not(summary):first-child {
margin-top: 0;
}
@@ -151,6 +151,11 @@ footer {
color: var(--text-muted);
}
body > footer {
body > footer:last-of-type {
margin-top: 40px;
}
body > header:first-of-type {
border-bottom: 1px solid var(--border);
padding-bottom: 20px;
}

View File

@@ -78,3 +78,17 @@ a > code,
a > strong {
color: inherit;
}
dt {
font-weight: 600;
color: var(--text-bright);
}
dd {
margin: 5px 0;
margin-left: 40px;
}
dd + dt {
margin-top: 10px;
}

5
swift-dots-run.md Normal file
View File

@@ -0,0 +1,5 @@
---
"water.css": patch
---
Add comprehensive element documentation