add document, fix tooltip position issue

This commit is contained in:
Tsanie Lily 2023-03-30 17:26:59 +08:00
parent f5bc42fa20
commit 5406eea20e
15 changed files with 432 additions and 117 deletions

View File

@ -8,7 +8,6 @@ $boxDisabledColor: #d9d9d9;
.check-box-inner {
position: relative;
display: inline-block;
margin-top: 2px;
padding: 0;
width: 14px;
height: 14px;

2
css/ui.min.css vendored
View File

@ -1 +1 @@
.checkbox-image>input[type=checkbox]{display:none}.checkbox-image>input[type=checkbox]:checked~.checked{display:inline}.checkbox-image>input[type=checkbox]:checked~.unchecked{display:none}.checkbox-image>.checked{display:none}.checkbox-image>.unchecked{display:inline}.checkbox-wrapper{display:flex;align-items:center;padding:0 8px;height:36px}.checkbox-wrapper .check-box-inner{position:relative;display:inline-block;margin-top:2px;padding:0;width:14px;height:14px;background-color:#fff;border:1px solid #999898;-moz-user-select:none;user-select:none;-webkit-user-select:none;border-radius:2px;transition:all .2s;cursor:pointer}.checkbox-wrapper .check-box-inner>svg{position:absolute;top:0;left:0;width:100%;height:100%;fill:#fff;transform:scale(0);opacity:0;transition:all .08s cubic-bezier(0.78, 0.14, 0.15, 0.86)}.checkbox-wrapper>input[type=checkbox]{display:none}.checkbox-wrapper>input[type=checkbox]:checked+.check-box-inner{border-color:#1890ff;background-color:#1890ff}.checkbox-wrapper>input[type=checkbox]:checked+.check-box-inner>svg{transform:scale(1);opacity:1}.checkbox-wrapper>input[type=checkbox]:disabled+.check-box-inner{border-color:#d9d9d9;cursor:default}.checkbox-wrapper>input[type=checkbox]:disabled:checked+.check-box-inner{border-color:#d9d9d9;background-color:#d9d9d9}.checkbox-wrapper>input[type=checkbox]:disabled~span{color:#d9d9d9;cursor:default}.checkbox-wrapper .check-box-inner{flex:0 0 auto}.checkbox-wrapper>span{flex:1 1 auto;font-weight:400;font-size:.875rem;padding-left:8px;padding-right:6px;align-self:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;color:#201f1e}.tooltip-color{background-color:#fff;color:#323130;border-color:rgba(204,204,204,.8);outline:none}.tooltip-wrapper{position:fixed;word-wrap:break-word;height:auto;text-align:left;z-index:250;min-width:75px;max-width:480px;min-height:32px;border-radius:2px;box-shadow:0 3.2px 7.2px 0 rgba(0,0,0,.13),0 .6px 1.8px 0 rgba(0,0,0,.11);transition:visibility 0s linear 120ms,opacity 120ms ease}.tooltip-wrapper>.tooltip-pointer{box-sizing:border-box;box-shadow:0 5px 15px 2px rgba(0,0,0,.3);border:1px solid #fff;z-index:-1;width:16px;height:16px;position:absolute;left:calc(50% - 8px);bottom:-8px;transform:rotate(-45deg);transform-origin:center}.tooltip-wrapper>.tooltip-curtain{position:absolute;width:100%;height:100%;z-index:-1}.tooltip-wrapper>.tooltip-content{font-size:.8125rem;line-height:1rem;white-space:normal;overflow:auto;margin:8px;height:calc(100% - 16px);-moz-user-select:none;user-select:none;-webkit-user-select:none}
.checkbox-image>input[type=checkbox]{display:none}.checkbox-image>input[type=checkbox]:checked~.checked{display:inline}.checkbox-image>input[type=checkbox]:checked~.unchecked{display:none}.checkbox-image>.checked{display:none}.checkbox-image>.unchecked{display:inline}.checkbox-wrapper{display:flex;align-items:center;padding:0 8px;height:36px}.checkbox-wrapper .check-box-inner{position:relative;display:inline-block;padding:0;width:14px;height:14px;background-color:#fff;border:1px solid #999898;-moz-user-select:none;user-select:none;-webkit-user-select:none;border-radius:2px;transition:all .2s;cursor:pointer}.checkbox-wrapper .check-box-inner>svg{position:absolute;top:0;left:0;width:100%;height:100%;fill:#fff;transform:scale(0);opacity:0;transition:all .08s cubic-bezier(0.78, 0.14, 0.15, 0.86)}.checkbox-wrapper>input[type=checkbox]{display:none}.checkbox-wrapper>input[type=checkbox]:checked+.check-box-inner{border-color:#1890ff;background-color:#1890ff}.checkbox-wrapper>input[type=checkbox]:checked+.check-box-inner>svg{transform:scale(1);opacity:1}.checkbox-wrapper>input[type=checkbox]:disabled+.check-box-inner{border-color:#d9d9d9;cursor:default}.checkbox-wrapper>input[type=checkbox]:disabled:checked+.check-box-inner{border-color:#d9d9d9;background-color:#d9d9d9}.checkbox-wrapper>input[type=checkbox]:disabled~span{color:#d9d9d9;cursor:default}.checkbox-wrapper .check-box-inner{flex:0 0 auto}.checkbox-wrapper>span{flex:1 1 auto;font-weight:400;font-size:.875rem;padding-left:8px;padding-right:6px;align-self:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;color:#201f1e}.tooltip-color{background-color:#fff;color:#323130;border-color:rgba(204,204,204,.8);outline:none}.tooltip-wrapper{position:fixed;word-wrap:break-word;height:auto;text-align:left;z-index:250;min-width:75px;max-width:480px;min-height:32px;border-radius:2px;box-shadow:0 3.2px 7.2px 0 rgba(0,0,0,.13),0 .6px 1.8px 0 rgba(0,0,0,.11);transition:visibility 0s linear 120ms,opacity 120ms ease}.tooltip-wrapper>.tooltip-pointer{box-sizing:border-box;box-shadow:0 5px 15px 2px rgba(0,0,0,.3);border:1px solid #fff;z-index:-1;width:16px;height:16px;position:absolute;left:calc(50% - 8px);bottom:-8px;transform:rotate(-45deg);transform-origin:center}.tooltip-wrapper>.tooltip-curtain{position:absolute;width:100%;height:100%;z-index:-1}.tooltip-wrapper>.tooltip-content{font-size:.8125rem;line-height:1rem;white-space:normal;overflow:auto;margin:8px;height:calc(100% - 16px);-moz-user-select:none;user-select:none;-webkit-user-select:none}

View File

@ -1,42 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>UI Lib</title>
<script type="module" src="/main.js"></script>
</head>
<body>
<div id="app">
<div>
<a
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript"
target="_blank"
>
<img id="js-logo" class="logo vanilla" alt="JavaScript logo" />
</a>
<div class="card">
<div id="create-icon" class="app-module">
<div>
<svg data-type="fa-solid" data-id="user-edit"></svg>
</div>
</div>
<div id="create-checkbox" class="app-module">
<label data-checkbox data-label="Case 1"></label>
</div>
<div id="buttons" class="app-module">
<button
data-title-lgid="editContacts"
data-lgid="editContacts"
title="Edit Contact"
>
Edit
</button>
<button id="button-fetch" title="Fetch">Fetch</button>
</div>
</div>
</div>
</div>
</body>
</html>
<head>
<meta charset="UTF-8" />
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>UI Lib</title>
<script type="module" src="/main.js"></script>
<script src="/dist/ui.min.js"></script>
</head>
<body>
<div id="directory">
<ul>
<li class="title">lib-ui</li>
<li>
<ol>
<li data-page="lib/ui/icon.html">icon</li>
<li data-page="lib/ui/checkbox.html">checkbox</li>
<li data-page="lib/ui/tooltip.html">tooltip</li>
</ol>
</li>
<li class="title">lib-utility</li>
<li>
<ol>
<li data-page="lib/utility/cookie.html">cookie</li>
<li data-page="lib/utility/lgres.html">lgres</li>
<li data-page="lib/utility/request.html">request</li>
<li data-page="lib/utility/strings.html">strings</li>
</ol>
</li>
</ul>
</div>
<div id="container"></div>
</body>
</html>

View File

@ -3,10 +3,13 @@ import { createCheckbox, resolveCheckbox } from "./ui/checkbox";
import { setTooltip, resolveTooltip } from "./ui/tooltip";
export {
// icon
createIcon,
resolveIcon,
// checkbox
createCheckbox,
resolveCheckbox,
// tooltip
setTooltip,
resolveTooltip
}

13
lib/ui/checkbox.d.ts vendored
View File

@ -1,2 +1,13 @@
export function createCheckbox(opts: any): HTMLElement
interface CheckboxOptions {
type?: string;
label?: string;
checked?: boolean;
isImage?: boolean;
imageHeight?: Number;
checkedNode?: HTMLElement;
uncheckedNode?: HTMLElement;
onchange?: (this: HTMLInputElement, ev: Event) => any;
}
export function createCheckbox(opts?: CheckboxOptions): HTMLElement
export function resolveCheckbox(container: HTMLElement): HTMLElement

93
lib/ui/checkbox.html Normal file
View File

@ -0,0 +1,93 @@
<div>
<h1>checkbox</h1>
<hr />
<p>
创建一个统一样式的复选框元素,或者解析转换页面上特定类型的 label
标签为复选框元素。
</p>
<h2>createCheckbox</h2>
<code>function createCheckbox(opts?: CheckboxOptions): HTMLElement</code>
<h3>opts?: CheckboxOptions</h3>
<p>
复选框初始参数,结构为
<pre>interface CheckboxOptions {
type?: string;
label?: string;
checked?: boolean;
isImage?: boolean;
imageHeight?: Number;
checkedNode?: HTMLElement;
uncheckedNode?: HTMLElement;
onchange?: (this: HTMLInputElement, ev: Event) => any;
}</pre>
</p>
<h3>type?: string</h3>
<p>
复选框图标的样式,可选值目前有 <code>fa-regular</code><code>fa-light</code><code>fa-solid</code>
</p>
<h3>label?: string</h3>
<p>
复选框的标签文本
</p>
<h3>checked?: boolean</h3>
<p>
初始是否选中
</p>
<h3>isImage?: boolean</h3>
<p>
是否为图片复选框
</p>
<h3>imageHeight?: Number</h3>
<p>
为图片复选框时的图片限制高度
</p>
<h3>checkedNode?: HTMLElement</h3>
<p>
为图片复选框时的选中时显示的元素
</p>
<h3>uncheckedNode?: HTMLElement</h3>
<p>
为图片复选框时的未选中时显示的元素
</p>
<h3>onchange?: (this: HTMLInputElement, ev: Event) => any</h3>
<p>
复选框改变时触发的事件
</p>
<h2>resolveCheckbox</h2>
<code>function resolveCheckbox(container: HTMLElement): HTMLElement</code>
<h3>container: HTMLElement</h3>
<p>
将把此 HTML 元素下的所有 <code>label[data-checkbox]</code> 元素解析为复选框,<code>[data-id]</code> 为复选框元素的 id包含
<code>[data-checked]</code> 时复选框默认选中。</p>
<p>当该元素无子元素时,<code>[data-type]</code> 同上述参数中的 <code>type?: string</code><code>[data-label]</code> 同上述参数中的
<code>label?: string</code>
</p>
<p>当该元素有子元素时解析为图片复选框class 为 <code>checked</code><code>unchecked</code> 的子元素将分别在选中与未选中时显示。</p>
<h2>示例</h2>
<pre>
&lt;div id="checkbox-sample"&gt;
&lt;label data-checkbox data-type="fa-light" data-label="Checkbox Light"&gt;&lt;/label&gt;
&lt;label data-checkbox data-checked data-label="Checkbox Regular"&gt;&lt;/label&gt;
&lt;label data-checkbox data-type="fa-solid" data-label="Checkbox Solid"&gt;&lt;/label&gt;
&lt;label data-checkbox&gt;
&lt;code class="checked"&gt;Checked&lt;/code&gt;
&lt;code class="unchecked"&gt;Unchecked&lt;/code&gt;
&lt;/label&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
window["lib-ui"].resolveCheckbox(document.querySelector("#checkbox-sample"));
&lt;/script&gt;</pre>
<div id="checkbox-sample">
<label data-checkbox data-type="fa-light" data-label="Checkbox Light"></label>
<label data-checkbox data-checked data-label="Checkbox Regular"></label>
<label data-checkbox data-type="fa-solid" data-label="Checkbox Solid"></label>
<label data-checkbox>
<code class="checked">Checked</code>
<code class="unchecked">Unchecked</code>
</label>
</div>
<script type="text/javascript">
window["lib-ui"].resolveCheckbox(document.querySelector("#checkbox-sample"));
</script>
</div>

View File

@ -18,6 +18,9 @@ function createCheckbox(opts) {
container.className = 'checkbox-wrapper';
const input = document.createElement('input');
input.setAttribute('type', 'checkbox');
if (opts.checked === true) {
input.checked = true;
}
if (typeof opts.onchange === 'function') {
input.addEventListener('change', opts.onchange);
}
@ -64,6 +67,13 @@ function resolveCheckbox(container) {
box.removeAttribute('data-label');
}
const input = document.createElement('input');
const id = box.getAttribute('data-id');
if (id != null && id.length > 0) {
input.id = id;
}
if (box.getAttribute('data-checked') != null) {
input.checked = true;
}
input.setAttribute('type', 'checkbox');
box.insertBefore(input, box.firstChild);
}

46
lib/ui/icon.html Normal file
View File

@ -0,0 +1,46 @@
<div>
<h1>icon</h1>
<hr />
<p>
创建一个 svg 矢量图标元素,或者解析转换页面上特定类型的 svg
标签到指定的图标元素。
</p>
<h2>createIcon</h2>
<code>function createIcon(type: string, id: string): SVGElement</code>
<h3>type: string</h3>
<p>
图标类型,可选值目前有 <code>fa-regular</code><code>fa-light</code><code>fa-solid</code>
</p>
<h3>id: string</h3>
<p>
图形 id例如
<code>user-edit</code><code>address-card</code><code>frog</code>……
</p>
<h2>resolveIcon</h2>
<code>function resolveIcon(container: HTMLElement): HTMLElement</code>
<h3>container: HTMLElement</h3>
<p>
将把此 HTML 元素下的所有 <code>svg[data-id]</code> 元素解析为图标,<code>[data-id]</code>
同上述 <code>id: string</code><code>[data-type]</code> 同上述
<code>type: string</code>
</p>
<h2>示例</h2>
<pre>
&lt;div id="icon-sample"&gt;
&lt;svg data-id="address-card" data-type="fa-regular"&gt;&lt;/svg&gt;
&lt;svg data-id="user-edit" data-type="fa-light"&gt;&lt;/svg&gt;
&lt;svg data-id="frog" data-type="fa-solid"&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
window["lib-ui"].resolveIcon(document.querySelector("#icon-sample"));
&lt;/script&gt;</pre>
<div id="icon-sample">
<svg data-id="address-card" data-type="fa-regular"></svg>
<svg data-id="user-edit" data-type="fa-light"></svg>
<svg data-id="frog" data-type="fa-solid"></svg>
</div>
<script type="text/javascript">
window["lib-ui"].resolveIcon(document.querySelector("#icon-sample"));
</script>
</div>

44
lib/ui/tooltip.html Normal file
View File

@ -0,0 +1,44 @@
<div>
<h1>tooltip</h1>
<hr />
<p>
给某个元素或者页面上含有 title 属性的元素设置一个统一样式的 tooltip。
</p>
<h2>setTooltip</h2>
<code>function setTooltip(container: HTMLElement, content: string | HTMLElement): void</code>
<h3>container: HTMLElement</h3>
<p>
要设置 tooltip 的元素
</p>
<h3>content: string | HTMLElement</h3>
<p>
要设置的 tooltip 内容,允许为字符串或者 HTML 元素
</p>
<h2>resolveTooltip</h2>
<code>function resolveTooltip(container: HTMLElement): HTMLElement</code>
<h3>container: HTMLElement</h3>
<p>
给此元素下的所有含有 title 属性的子元素设置成统一样式的 tooltip
</p>
<h2>示例</h2>
<pre>
&lt;div id="tooltip-sample"&gt;
&lt;blockquote title="From MDN Website"&gt;To send an HTTP request, create an XMLHttpRequest object, open a URL, and
send the request. After the transaction completes, the object will contain useful information such as the
response body and the HTTP status of the result.&lt;/blockquote&gt;
&lt;button title="Test to send request through XMLHttpRequest."&gt;Test&lt;/button&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
window["lib-ui"].resolveCheckbox(document.querySelector("#checkbox-sample"));
&lt;/script&gt;</pre>
<div id="tooltip-sample">
<blockquote title="From MDN Website">To send an HTTP request, create an XMLHttpRequest object, open a URL, and
send the request. After the transaction completes, the object will contain useful information such as the
response body and the HTTP status of the result.</blockquote>
<button title="Test to send request through XMLHttpRequest.">Test</button>
</div>
<script type="text/javascript">
window["lib-ui"].resolveTooltip(document.querySelector("#tooltip-sample"));
</script>
</div>

View File

@ -23,8 +23,16 @@ function setTooltip(container, content) {
container.addEventListener('mouseenter', () => {
tid && clearTimeout(tid);
tid = setTimeout(() => {
const left = container.offsetLeft + container.offsetWidth / 2 - wrapper.offsetWidth / 2;
const top = container.offsetTop - wrapper.offsetHeight - 14;
let left = container.offsetLeft;
let top = container.offsetTop;
let parent = container.parentElement;
while (parent != null) {
left -= parent.scrollLeft;
top -= parent.scrollTop;
parent = parent.parentElement;
}
left -= wrapper.offsetWidth / 2 - container.offsetWidth / 2;
top -= wrapper.offsetHeight + 14;
wrapper.style.left = `${left}px`;
wrapper.style.top = `${top}px`;
wrapper.style.visibility = 'visible';

View File

@ -4,15 +4,19 @@ import { get, post, upload } from "./utility/request";
import { nullOrEmpty, contains, endsWith, padStart } from "./utility/strings";
export {
// cookie
getCookie,
setCookie,
deleteCookie,
// lgres
init,
r,
lang,
// request
get,
post,
upload,
// strings
nullOrEmpty,
contains,
endsWith,

View File

@ -1,4 +1,9 @@
export function init(dom?: HTMLElement, ahead?: | { callback?: (result: any) => void }): Promise<any>
interface LgresOptions {
template?: string,
callback?: (result: any) => void
}
export function init(dom?: HTMLElement, options?: LgresOptions): Promise<any>
export function r(key: string, defaultValue?: any): any
export const lang: {
get current(): string,

View File

@ -45,23 +45,24 @@ function getStorageKey(lgid) {
return `res_${lgid}`;
}
async function doRefreshLgres() {
async function doRefreshLgres(template) {
template ??= '';
const lgid = getCurrentLgId();
const r = await get(`language/${lgid}/res.json`);
const r = await get(`language/${lgid}${template}`);
const dict = await r.json();
localStorage.setItem(getStorageKey(lgid), JSON.stringify(dict));
cache = dict;
return dict;
}
async function refreshLgres(lgres) {
async function refreshLgres(template, lgres) {
if (lgres == null || typeof consts === 'undefined') {
return await doRefreshLgres();
return await doRefreshLgres(template);
}
const ver = Number(consts.resver);
if (isNaN(lgres.ver) || isNaN(ver) || ver > lgres.ver) {
console.log(`found new language res version: ${lgres.ver} => ${ver}`);
return await doRefreshLgres();
return await doRefreshLgres(template);
}
cache = lgres;
return lgres;
@ -97,42 +98,40 @@ function applyLanguage(dom, result) {
}
}
async function init(dom, ahead) {
async function init(dom, options) {
options ??= {};
const lgid = getCurrentLgId();
let lgres = localStorage.getItem(getStorageKey(lgid));
let result;
if (lgres != null) {
try {
lgres = JSON.parse(lgres);
result = await refreshLgres(lgres);
result = await refreshLgres(options.template, lgres);
} catch (e) {
console.error('error while parsing lgres, try refresh ...', e);
result = await refreshLgres();
result = await refreshLgres(options.template);
}
} else {
result = await refreshLgres();
result = await refreshLgres(options.template);
}
try {
if (ahead != null) {
// not in defer mode
if (document.readyState === 'loading') {
return await new Promise((resolve, reject) => {
let tid = setTimeout(() => reject('timeout'), 30000);
document.addEventListener('DOMContentLoaded', () => {
clearTimeout(tid);
tid = void 0;
if (typeof ahead.callback === 'function') {
ahead.callback(result);
}
applyLanguage(dom, result);
resolve(result);
});
if (document.readyState === 'loading') {
return await new Promise((resolve, reject) => {
let tid = setTimeout(() => reject('timeout'), 30000);
document.addEventListener('DOMContentLoaded', () => {
clearTimeout(tid);
tid = void 0;
if (typeof options.callback === 'function') {
options.callback(result);
}
applyLanguage(dom, result);
resolve(result);
});
}
if (typeof ahead.callback === 'function') {
ahead.callback(result);
}
});
}
if (typeof options.callback === 'function') {
options.callback(result);
}
applyLanguage(dom, result);
return result;

33
main.js
View File

@ -1,8 +1,7 @@
import './css/ui.min.css'
import './style.css'
// import javascriptLogo from './javascript.svg'
import { resolveCheckbox, resolveIcon, resolveTooltip } from './lib/ui'
import { init, r, lang, get, post, upload } from './lib/utility'
import { get } from './lib/utility'
// document.querySelector('#js-logo').src = javascriptLogo
@ -11,7 +10,36 @@ window.consts = {
resver: 20230329
}
function navigate(page) {
get(page, {
accept: 'text/html'
})
.then(r => r.text())
.then(html => {
const range = document.createRange();
range.selectNode(document.body);
const doc = range.createContextualFragment(html);
document.querySelector('#container').replaceChildren(doc);
});
}
document.querySelector('#directory').addEventListener('click', (ev) => {
const page = ev.target.getAttribute('data-page');
if (typeof page === 'string') {
location.hash = page;
navigate(page);
}
});
let page = location.hash;
if (page.length > 1) {
page = page.substring(1);
navigate(page);
}
/*
init(null, {
template: '/res.json',
callback: (result) => console.log(result)
}).then(() => {
// document.querySelector('#create-icon').appendChild(createIcon('fa-solid', 'user-edit'))
@ -35,3 +63,4 @@ init(null, {
.then(blob => document.querySelector('#js-logo').src = URL.createObjectURL(blob));
});
});
*/

152
style.css
View File

@ -13,6 +13,46 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
--border-color: #ccc;
--hover-color: #666;
--mono-font-family: 'FantasqueSansMono NFM', 'Cascadia Code', 'PT Mono', Consolas, 'Courier New', monospace;
}
code, kbd, pre, samp {
font-family: var(--mono-font-family);
background-color: var(--hover-color);
padding: 0 10px;
}
code {
display: inline-block;
}
pre {
font-size: .875em;
}
h2 + code {
margin-left: 70px;
position: relative;
}
h2 + code::before {
content: '签名:';
position: absolute;
margin-left: -70px;
}
h3 {
font-family: var(--mono-font-family);
font-size: 1em;
margin-left: 10px;
/* font-weight: bold; */
}
h3 ~ p {
margin-left: 10px;
}
a {
@ -20,50 +60,11 @@ a {
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vanilla:hover {
filter: drop-shadow(0 0 2em #f7df1eaa);
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}
button {
border-radius: 8px;
border: 1px solid transparent;
@ -75,14 +76,74 @@ button {
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
body {
margin: 0;
display: flex;
height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
margin: 20px 0;
}
#directory {
width: 200px;
padding: 2rem;
border-right: 1px solid var(--border-color);
flex: 0 0 auto;
}
#directory>ul {
padding: 0;
line-height: 1.6em;
}
#directory>ul>li {
list-style: none;
user-select: none;
}
#directory>ul>li.title {
margin: 20px 0 6px;
font-weight: bold;
font-size: 1.25em;
}
#directory ol {
padding-left: 10px;
}
#directory ol>li {
padding: 0 6px;
list-style-position: inside;
cursor: pointer;
}
#directory ol>li:hover {
background-color: var(--hover-color);
}
#container {
flex: 1 1 auto;
overflow: auto;
}
#container>div {
padding: 20px;
}
.app-module {
margin: 8px 0;
}
@ -91,6 +152,7 @@ button:focus-visible {
display: flex;
justify-content: center;
}
#create-icon svg {
width: 20px;
height: 20px;
@ -101,11 +163,13 @@ button:focus-visible {
flex-direction: column;
align-items: center;
}
.checkbox-wrapper .check-box-inner {
width: 14px;
height: 14px;
}
.checkbox-wrapper > span {
.checkbox-wrapper>span {
font-size: 1em;
}
@ -113,11 +177,15 @@ button:focus-visible {
:root {
color: #213547;
background-color: #ffffff;
--border-color: #666;
--hover-color: #eee;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
}