add: better layout
This commit is contained in:
parent
2cc9ed7445
commit
dbd70d9592
19 changed files with 451 additions and 87 deletions
3
app/.gitignore
vendored
Normal file
3
app/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
public/docs/**/*
|
||||
!public/docs/metadata.md
|
||||
icons/
|
11
app/docs/metadata.md
Normal file
11
app/docs/metadata.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# What is metadata?
|
||||
|
||||
Each entry also includes a separate metadata content. Metadata is used to further customize the look and display of your entries to a finer degree than you can through just Markdown.
|
||||
|
||||
Metadata includes options to customize how your entries look when shared to other platforms, as well as to customize how your entries render when viewed.
|
||||
|
||||
All option names can either be in all lowercase, or all uppercase. While option values for `String` type metadata options _should_ be encased in double quotes, that will be done for you if you leave them out. This is included just for compatibility.
|
||||
|
||||
Metadata options go in the "Metadata" tab in the entry editor page. Each option should be on a new line, and should be formatted as `NAME = value`. If you're familiar with TOML, you should be comfortable with metadata formatting.
|
||||
|
||||
You can view a list of all options and what they do [here](http://localhost:9119/public/reference/attobin/model/struct.EntryMetadata.html#fields).
|
|
@ -224,3 +224,109 @@ globalThis.check_exists_input = (e) => {
|
|||
e.target.reportValidity();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// components
|
||||
function close_dropdowns() {
|
||||
for (const dropdown of Array.from(
|
||||
document.querySelectorAll(".inner.open"),
|
||||
)) {
|
||||
dropdown.classList.remove("open");
|
||||
}
|
||||
}
|
||||
|
||||
globalThis.open_dropdown = (event) => {
|
||||
event.stopImmediatePropagation();
|
||||
let target = event.target;
|
||||
|
||||
while (!target.matches(".dropdown")) {
|
||||
target = target.parentElement;
|
||||
}
|
||||
|
||||
// close all others
|
||||
close_dropdowns();
|
||||
|
||||
// open
|
||||
setTimeout(() => {
|
||||
for (const dropdown of Array.from(target.querySelectorAll(".inner"))) {
|
||||
// check y
|
||||
const box = target.getBoundingClientRect();
|
||||
|
||||
let parent = dropdown.parentElement;
|
||||
|
||||
while (!parent.matches("html, .window")) {
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
|
||||
let parent_height = parent.getBoundingClientRect().y;
|
||||
|
||||
if (parent.nodeName === "HTML") {
|
||||
parent_height = window.screen.height;
|
||||
}
|
||||
|
||||
const scroll = window.scrollY;
|
||||
const height = parent_height;
|
||||
const y = box.y + scroll;
|
||||
|
||||
if (y > height - scroll - 375) {
|
||||
dropdown.classList.add("top");
|
||||
} else {
|
||||
dropdown.classList.remove("top");
|
||||
}
|
||||
|
||||
// open
|
||||
dropdown.classList.add("open");
|
||||
|
||||
if (dropdown.classList.contains("open")) {
|
||||
dropdown.removeAttribute("aria-hidden");
|
||||
} else {
|
||||
dropdown.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
}
|
||||
}, 5);
|
||||
};
|
||||
|
||||
globalThis.init_dropdowns = (bind_to) => {
|
||||
for (const dropdown of Array.from(document.querySelectorAll(".inner"))) {
|
||||
dropdown.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
|
||||
bind_to.addEventListener("click", (event) => {
|
||||
if (
|
||||
event.target.matches(".dropdown") ||
|
||||
event.target.matches("[exclude=dropdown]")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const dropdown of Array.from(
|
||||
document.querySelectorAll(".inner.open"),
|
||||
)) {
|
||||
dropdown.classList.remove("open");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.METADATA_CSS_ENABLED = true;
|
||||
globalThis.toggle_metadata_css = (e) => {
|
||||
e.target.classList.add("yellow");
|
||||
|
||||
METADATA_CSS_ENABLED = !METADATA_CSS_ENABLED;
|
||||
if (!METADATA_CSS_ENABLED) {
|
||||
media_theme_pref(); // user user theme
|
||||
document.getElementById("metadata_css").remove(); // remove css
|
||||
|
||||
// reset colored text
|
||||
for (const element of Array.from(
|
||||
document.querySelectorAll(".color_block"),
|
||||
)) {
|
||||
element.removeAttribute("style");
|
||||
element.classList.remove("color_block");
|
||||
}
|
||||
|
||||
// strikethrough auto theme since it's disabled
|
||||
document.getElementById("auto_theme").style.textDecoration =
|
||||
"line-through";
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
|
1
app/public/reference
Symbolic link
1
app/public/reference
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../target/doc
|
|
@ -12,7 +12,7 @@
|
|||
--color-shadow: rgba(0, 0, 0, 0.08);
|
||||
--color-red: hsl(0, 84%, 40%);
|
||||
--color-green: hsl(100, 84%, 20%);
|
||||
--color-yellow: hsl(41, 63%, 75%);
|
||||
--color-yellow: oklch(47% 0.157 37.304);
|
||||
--color-purple: hsl(284, 84%, 20%);
|
||||
--color-primary: oklch(67.3% 0.182 276.935);
|
||||
|
||||
|
@ -24,6 +24,9 @@
|
|||
--pad-2: 0.35rem;
|
||||
--pad-3: 0.5rem;
|
||||
--pad-4: 1rem;
|
||||
|
||||
--radius: 0.2rem;
|
||||
--nav-height: 36px;
|
||||
}
|
||||
|
||||
* {
|
||||
|
@ -45,7 +48,7 @@
|
|||
--color-link: #93c5fd;
|
||||
--color-red: hsl(0, 94%, 82%);
|
||||
--color-green: hsl(100, 94%, 82%);
|
||||
--color-yellow: hsl(41, 63%, 65%);
|
||||
--color-yellow: oklch(90.1% 0.076 70.697);
|
||||
--color-purple: hsl(284, 94%, 82%);
|
||||
}
|
||||
|
||||
|
@ -73,7 +76,7 @@ main {
|
|||
|
||||
article {
|
||||
margin: var(--pad-2) 0;
|
||||
height: calc(100dvh - var(--pad-4) * 2);
|
||||
height: calc(100dvh - var(--pad-4) - var(--nav-height) * 2);
|
||||
}
|
||||
|
||||
.tab {
|
||||
|
@ -89,6 +92,14 @@ article {
|
|||
animation: fadein ease-in-out 1 0.5s forwards running;
|
||||
}
|
||||
|
||||
nav {
|
||||
/* background: var(--color-raised); */
|
||||
height: var(--nav-height);
|
||||
/* position: sticky;
|
||||
z-index: 2;
|
||||
top: 2; */
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
main,
|
||||
article,
|
||||
|
@ -117,7 +128,7 @@ article {
|
|||
}
|
||||
|
||||
.content_container {
|
||||
margin: var(--pad-2) auto;
|
||||
margin: 0 auto var(--pad-2);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
@ -167,7 +178,7 @@ video {
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: var(--gap-2);
|
||||
gap: var(--pad-2);
|
||||
padding: var(--pad-2) calc(var(--pad-3) * 1.5);
|
||||
cursor: pointer;
|
||||
background: var(--color-raised);
|
||||
|
@ -187,7 +198,7 @@ video {
|
|||
--h: 28px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
.button:not(:has(.button:hover)):not(.camo):hover {
|
||||
background: var(--color-super-raised);
|
||||
}
|
||||
|
||||
|
@ -196,10 +207,70 @@ video {
|
|||
color: inherit;
|
||||
}
|
||||
|
||||
.bar .button.camo:hover {
|
||||
.bar .button:not(.simple).camo:hover {
|
||||
color: var(--color-link);
|
||||
}
|
||||
|
||||
.button.simple {
|
||||
--size: 18px;
|
||||
font-weight: 600;
|
||||
padding: var(--pad-2) !important;
|
||||
border-radius: var(--radius);
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
aspect-ratio: 1 / 1;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.button.surface {
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
.button.surface.simple:is(.camo *) {
|
||||
background: var(--color-super-raised);
|
||||
}
|
||||
|
||||
/* dropdown */
|
||||
.dropdown {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown .inner {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
box-shadow: var(--shadow-x-offset) var(--shadow-y-offset) var(--shadow-size)
|
||||
var(--color-shadow);
|
||||
background: var(--color-raised);
|
||||
color: inherit;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 100%;
|
||||
}
|
||||
|
||||
.dropdown .inner.open {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dropdown .inner .button {
|
||||
padding: var(--pad-3) var(--pad-4);
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown:has(.inner.open) .button:nth-child(1):not(.inner *) {
|
||||
background: var(--color-raised);
|
||||
}
|
||||
|
||||
.dropdown .inner.top {
|
||||
top: unset;
|
||||
bottom: 100%;
|
||||
}
|
||||
|
||||
.dropdown .inner.left {
|
||||
left: 0;
|
||||
right: unset;
|
||||
}
|
||||
|
||||
/* input */
|
||||
input {
|
||||
--h: 36px;
|
||||
|
@ -276,6 +347,7 @@ pre {
|
|||
padding: var(--pad-2) var(--pad-4);
|
||||
border-left: solid 5px var(--color-primary);
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
code {
|
||||
|
@ -297,8 +369,22 @@ code * {
|
|||
font-size: 0.8rem !important;
|
||||
}
|
||||
|
||||
code:not(pre *) {
|
||||
padding: var(--pad-1) var(--pad-2);
|
||||
background: oklch(98% 0.016 73.684 / 25%);
|
||||
color: oklch(90.1% 0.076 70.697);
|
||||
border-radius: var(--radius);
|
||||
white-space: break-spaces;
|
||||
}
|
||||
|
||||
code:not(pre *):not(.dark *) {
|
||||
background: oklch(83.7% 0.128 66.29 / 25%);
|
||||
color: oklch(47% 0.157 37.304);
|
||||
}
|
||||
|
||||
svg.icon {
|
||||
stroke: currentColor;
|
||||
fill: currentColor;
|
||||
width: 18px;
|
||||
height: 1em;
|
||||
}
|
||||
|
@ -307,6 +393,10 @@ svg.icon.filled {
|
|||
fill: currentColor;
|
||||
}
|
||||
|
||||
.no_fill svg.icon {
|
||||
fill: transparent;
|
||||
}
|
||||
|
||||
button svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -384,6 +474,10 @@ a {
|
|||
color: var(--color-link);
|
||||
}
|
||||
|
||||
.color_block a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a.flush {
|
||||
color: inherit;
|
||||
}
|
||||
|
@ -477,12 +571,12 @@ blockquote {
|
|||
|
||||
.cm-comment,
|
||||
.hljs-keyword {
|
||||
color: rgb(153 27 27) !important;
|
||||
color: oklch(47% 0.157 37.304) !important;
|
||||
}
|
||||
|
||||
.cm-comment:is(.dark *),
|
||||
.hljs-keyword:is(.dark *) {
|
||||
color: rgb(254, 202, 202) !important;
|
||||
color: oklch(90.1% 0.076 70.697) !important;
|
||||
}
|
||||
|
||||
.cm-link {
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
(text "{% macro footer() -%}")
|
||||
(footer
|
||||
("class" "flex flex-col items-center gap-2")
|
||||
(hr ("style" "min-width: 20rem; margin-top: calc(var(--pad-4) * 4)"))
|
||||
(div
|
||||
("class" "w-full flex justify-between")
|
||||
(div ("style" "width: 50px"))
|
||||
(div
|
||||
("class" "flex flex-col gap-2 items-center")
|
||||
(div
|
||||
("class" "flex gap-2 flex-wrap")
|
||||
(a
|
||||
("href" "/")
|
||||
(text "new"))
|
||||
|
||||
(a
|
||||
("href" "/{{ what_page_slug }}")
|
||||
(text "what"))
|
||||
|
||||
(a
|
||||
("href" "https://trisua.com/t/attobin")
|
||||
(text "source")))
|
||||
|
||||
(span ("style" "font-size: 14px") ("class" "fade") (text "{{ name }}")))
|
||||
|
||||
; theme switches
|
||||
(button
|
||||
("class" "button camo fade")
|
||||
("id" "switch_light")
|
||||
("title" "Switch theme")
|
||||
("onclick" "set_theme('Dark')")
|
||||
(text "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-sun-icon lucide-sun icon\"><circle cx=\"12\" cy=\"12\" r=\"4\"/><path d=\"M12 2v2\"/><path d=\"M12 20v2\"/><path d=\"m4.93 4.93 1.41 1.41\"/><path d=\"m17.66 17.66 1.41 1.41\"/><path d=\"M2 12h2\"/><path d=\"M20 12h2\"/><path d=\"m6.34 17.66-1.41 1.41\"/><path d=\"m19.07 4.93-1.41 1.41\"/></svg>"))
|
||||
|
||||
(button
|
||||
("class" "button camo fade hidden")
|
||||
("id" "switch_dark")
|
||||
("title" "Switch theme")
|
||||
("onclick" "set_theme('Light')")
|
||||
(text "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-moon-icon lucide-moon icon\"><path d=\"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z\"/></svg>"))))
|
||||
(text "{%- endmacro %}")
|
9
app/templates_src/doc.lisp
Normal file
9
app/templates_src/doc.lisp
Normal file
|
@ -0,0 +1,9 @@
|
|||
(text "{% extends \"root.lisp\" %} {% block head %}")
|
||||
(title
|
||||
(text "{{ file_name }} - {{ name }}"))
|
||||
(link ("rel" "icon") ("href" "/public/favicon.svg"))
|
||||
(text "{% endblock %} {% block body %}")
|
||||
(div
|
||||
("class" "card container")
|
||||
(p (text "{{ text|markdown|safe }}")))
|
||||
(text "{% endblock %}")
|
|
@ -19,7 +19,13 @@
|
|||
("class" "button camo tab_button")
|
||||
("id" "metadata_tab_button")
|
||||
("onclick" "tab_metadata()")
|
||||
(text "Metadata")))
|
||||
(text "Metadata")
|
||||
(a
|
||||
("class" "button simple surface")
|
||||
("href" "/docs/metadata")
|
||||
("target" "_blank")
|
||||
("title" "Info")
|
||||
(text "i"))))
|
||||
(div
|
||||
("class" "card tab tabs container")
|
||||
("id" "tabs_group")
|
||||
|
@ -74,7 +80,6 @@
|
|||
("class" "button red")
|
||||
("ui_ident" "delete")
|
||||
(text "Delete"))))
|
||||
(text "{{ components::footer() }}")
|
||||
|
||||
; editor
|
||||
(script ("src" "https://unpkg.com/codemirror@5.39.2/lib/codemirror.js"))
|
||||
|
|
|
@ -6,5 +6,4 @@
|
|||
(div
|
||||
("class" "card")
|
||||
(p (text "{{ error }}")))
|
||||
(text "{{ components::footer() }}")
|
||||
(text "{% endblock %}")
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
(text "{% extends \"root.lisp\" %} {% block head %}")
|
||||
(title
|
||||
(text "{{ name }}"))
|
||||
|
||||
(meta ("property" "og:title") ("content" "{{ name }}"))
|
||||
(meta ("property" "twitter:title") ("content" "{{ name }}"))
|
||||
(link ("rel" "icon") ("href" "/public/favicon.svg"))
|
||||
(text "{% endblock %} {% block body %}")
|
||||
(div
|
||||
|
@ -19,7 +22,13 @@
|
|||
("class" "button camo tab_button")
|
||||
("id" "metadata_tab_button")
|
||||
("onclick" "tab_metadata()")
|
||||
(text "Metadata")))
|
||||
(text "Metadata")
|
||||
(a
|
||||
("class" "button simple surface")
|
||||
("href" "/docs/metadata")
|
||||
("target" "_blank")
|
||||
("title" "Info")
|
||||
(text "i"))))
|
||||
(div
|
||||
("class" "card tab tabs container")
|
||||
("id" "tabs_group")
|
||||
|
@ -55,7 +64,6 @@
|
|||
("name" "slug")
|
||||
("oninput" "check_exists_input(event)")
|
||||
("placeholder" "Custom url"))))
|
||||
(text "{{ components::footer() }}")
|
||||
|
||||
; editor
|
||||
(script ("src" "https://unpkg.com/codemirror@5.39.2/lib/codemirror.js"))
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
(text "{%- import \"components.lisp\" as components -%}")
|
||||
(text "<!doctype html>")
|
||||
(html
|
||||
("lang" "en")
|
||||
|
@ -19,8 +18,64 @@
|
|||
(text "{% block head %}{% endblock %}"))
|
||||
|
||||
(body
|
||||
; nav
|
||||
(nav
|
||||
("class" "flex w-full justify-between gap-2")
|
||||
(div
|
||||
("class" "flex side")
|
||||
(div
|
||||
("class" "dropdown")
|
||||
(button
|
||||
("onclick" "open_dropdown(event)")
|
||||
("exclude" "dropdown")
|
||||
("class" "button camo fade")
|
||||
(text "{{ icon \"menu\" }}"))
|
||||
(div
|
||||
("class" "inner")
|
||||
(a
|
||||
("class" "button")
|
||||
("href" "/")
|
||||
(text "new"))
|
||||
(a
|
||||
("class" "button")
|
||||
("href" "/{{ what_page_slug }}")
|
||||
(text "what"))
|
||||
(a
|
||||
("class" "button")
|
||||
("href" "https://trisua.com/t/attobin")
|
||||
(text "source"))))
|
||||
|
||||
(a
|
||||
("class" "button camo fade")
|
||||
("href" "/")
|
||||
("title" "new")
|
||||
(text "{{ icon \"plus\" }}")))
|
||||
|
||||
(div
|
||||
("class" "side flex")
|
||||
(text "{% block nav_extras %}{% endblock %}")
|
||||
|
||||
; theme switches
|
||||
(button
|
||||
("class" "button camo fade")
|
||||
("id" "switch_light")
|
||||
("title" "Switch theme")
|
||||
("onclick" "set_theme('Dark')")
|
||||
(text "{{ icon \"sun\" }}"))
|
||||
|
||||
(button
|
||||
("class" "button camo fade hidden")
|
||||
("id" "switch_dark")
|
||||
("title" "Switch theme")
|
||||
("onclick" "set_theme('Light')")
|
||||
(text "{{ icon \"moon\" }}"))))
|
||||
|
||||
; page
|
||||
(article
|
||||
("class" "content_container flex flex-col")
|
||||
("id" "page")
|
||||
(ul ("id" "messages"))
|
||||
(text "{% block body %}{% endblock %}"))))
|
||||
(text "{% block body %}{% endblock %}")
|
||||
(div ("style" "min-height: 32px")))
|
||||
|
||||
(script (text "setTimeout(() => init_dropdowns(document.body), 150);"))))
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
(text "{{ entry.slug }}"))
|
||||
(text "{%- endif %} {{ metadata_head|safe }}")
|
||||
|
||||
(text "{% if not metadata.share_title -%}")
|
||||
(meta ("property" "og:title") ("content" "{{ entry.slug }}"))
|
||||
(meta ("property" "twitter:title") ("content" "{{ entry.slug }}"))
|
||||
(text "{%- endif %}")
|
||||
|
||||
(text "{% if metadata.page_icon|length == 0 -%}")
|
||||
(link ("rel" "icon") ("href" "/public/favicon.svg"))
|
||||
(text "{%- endif %}")
|
||||
|
@ -30,7 +35,7 @@
|
|||
|
||||
; auto theme
|
||||
(text "{% if metadata.access_recommended_theme != 'None' -%}")
|
||||
(span (text "Auto theme: {{ metadata.access_recommended_theme }}"))
|
||||
(span ("id" "auto_theme") (text "Auto theme: {{ metadata.access_recommended_theme }}"))
|
||||
(script ("defer" "true") (text "setTimeout(() => { temporary_set_theme('{{ metadata.access_recommended_theme }}') }, 150);"))
|
||||
(text "{%- endif %}")
|
||||
|
||||
|
@ -44,11 +49,17 @@
|
|||
(a ("class" "button small") ("href" "/{{ metadata.access_easy_read }}") (b (text "E2R")))
|
||||
(text "{%- endif %}"))))
|
||||
|
||||
(text "{{ metadata_css|safe }}")
|
||||
(div ("style" "display: none") ("id" "metadata_css") (text "{{ metadata_css|safe }}"))
|
||||
|
||||
(link ("rel" "stylesheet") ("href" "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css"))
|
||||
(script ("src" "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"))
|
||||
(script (text "hljs.highlightAll();"))
|
||||
|
||||
(text "{{ components::footer() }}")
|
||||
(text "{% endblock %}")
|
||||
(text "{% block nav_extras %}")
|
||||
(button
|
||||
("class" "button camo fade no_fill")
|
||||
("title" "Toggle high-contrast")
|
||||
("onclick" "toggle_metadata_css(event)")
|
||||
(text "{{ icon \"contrast\" }}"))
|
||||
(text "{% endblock %}")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue