Files
eleith ad1ff198cb
ci/woodpecker/pr/web-theme Pipeline was successful
ci/woodpecker/pr/web-worker Pipeline was successful
ci/woodpecker/pr/web Pipeline was successful
[web] add native desktop sidenote previews
2026-11-08 10:00:09 -08:00

514 lines
10 KiB
CSS

/* Shiki Theme CSS */
pre.shiki,
.markdown pre {
overflow-x: auto;
}
pre.shiki code {
display: grid;
}
pre.shiki code .line:empty {
min-height: 1.4em;
}
pre.shiki,
.markdown pre {
background-color: var(--shiki-light-bg);
padding: var(--space-3);
}
pre.shiki code,
pre.shiki code span,
.markdown code,
.markdown code span {
color: var(--shiki-light);
background-color: var(--shiki-light-bg);
}
[data-theme='dark'] pre.shiki,
[data-theme='dark'] .markdown pre {
background-color: var(--shiki-dark-bg);
}
[data-theme='dark'] pre.shiki,
[data-theme='dark'] pre.shiki span,
[data-theme='dark'] .markdown pre,
[data-theme='dark'] .markdown pre span {
color: var(--shiki-dark);
background-color: var(--shiki-dark-bg);
}
/* Media query fallback for system preferences when data-theme is not explicitly set */
@media (prefers-color-scheme: dark) {
html:not([data-theme='light']) pre.shiki,
html:not([data-theme='light']) .markdown pre {
background-color: var(--shiki-dark-bg);
}
html:not([data-theme='light']) pre.shiki code,
html:not([data-theme='light']) pre.shiki span,
html:not([data-theme='light']) .markdown pre,
html:not([data-theme='light']) .markdown pre span {
color: var(--shiki-dark);
background-color: var(--shiki-dark-bg);
}
}
@position-try --sidenote-fit-viewport {
top: min(12px, max(0px, anchor(top)));
bottom: min(12px, max(0px, anchor(bottom)));
align-self: anchor-center;
}
@position-try --sidenote-fit-viewport-inline {
top: min(12px, max(0px, anchor(top)));
bottom: min(12px, max(0px, anchor(bottom)));
left: auto;
right: min(12px, max(0px, anchor(right)));
align-self: anchor-center;
}
@keyframes sidenote-sheet-in {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
.markdown {
line-height: 1.6;
:is(p, ul, ol) {
margin-block: 1em;
}
:is(h1, h2, h3, h4, h5, h6) {
margin-block: 1.5em 0.5em;
font-weight: 600;
line-height: 1.25;
}
h1 {
font-size: 1.65em;
}
h2 {
font-size: 1.35em;
}
h3 {
font-size: 1.15em;
}
:is(h4, h5, h6) {
font-size: 1em;
}
li + li {
margin-block-start: 0.25em;
}
li > :is(ul, ol) {
margin-block: 0.25em;
}
> :first-child,
blockquote > :first-child {
margin-block-start: 0;
}
> :last-child,
blockquote > :last-child {
margin-block-end: 0;
}
pre {
padding: var(--space-3);
border: 1px solid var(--color-outline);
border-radius: var(--radius-2);
margin: var(--space-4) 0;
}
:not(pre) > code {
background-color: var(--color-surface-dim);
padding: 0 var(--space-1);
border-radius: 0 var(--radius-small) var(--radius-small) 0;
}
code[data-line-numbers] {
counter-reset: line;
}
code[data-line-numbers] > [data-line]::before {
counter-increment: line;
content: counter(line);
display: inline-block;
width: 0.75rem;
margin-right: 2rem;
text-align: right;
color: gray;
}
code[data-line-numbers-max-digits='2'] > [data-line]::before {
width: 1.25rem;
}
code[data-line-numbers-max-digits='3'] > [data-line]::before {
width: 1.75rem;
}
code[data-line-numbers-max-digits='4'] > [data-line]::before {
width: 2.25rem;
}
figure[data-rehype-pretty-code-figure] {
position: relative;
}
figure figcaption[data-rehype-pretty-code-title] {
position: absolute;
top: 0;
left: 1rem;
transform: translateY(-50%);
padding: 0 0.1rem;
font-family: ui-monospace, monospace;
font-size: 0.75rem;
font-weight: 600;
background-color: var(--color-surface);
color: var(--color-on-surface);
}
table {
display: block;
border-collapse: collapse;
width: max-content;
max-width: 100%;
overflow-x: auto;
margin: var(--space-4) 0;
}
table,
th,
td {
border: 1px solid var(--color-outline);
}
th,
td {
padding: var(--space-2);
}
table tbody tr:nth-child(odd) {
background-color: transparent;
}
table tbody tr:nth-child(even) {
background-color: var(--color-surface-dim);
}
table thead tr {
background-color: var(--color-surface-dim);
}
ul.contains-task-list {
list-style: none;
padding-left: 0;
}
blockquote {
background: var(--color-surface-container-lowest);
border-left: 2px solid var(--color-primary);
padding: 0.75em 1em;
margin: var(--space-4) 0;
border-radius: 0 var(--radius-small) var(--radius-small) 0;
box-shadow: 0 2px 4px var(--color-shadow);
}
.sidenote__button {
display: none;
padding: 0 0.2rem;
border: 0;
background: none;
font: inherit;
min-inline-size: 1em;
min-block-size: 1.5em;
cursor: pointer;
}
.sidenote__button sup {
text-decoration: underline;
color: var(--color-secondary);
}
.sidenote__preview {
display: none;
}
.sidenote__id {
color: var(--color-secondary);
}
.sidenote__content[popover]::backdrop {
background: rgb(0 0 0 / 12%);
}
.sidenote__content[popover]:popover-open {
display: block;
position: fixed;
position-anchor: none;
inset: auto 0 0;
margin: 0 auto;
inline-size: 100%;
max-inline-size: 36rem;
min-block-size: min(10rem, 30dvh);
max-block-size: min(50dvh, 30rem);
padding: 1rem clamp(20px, 4vw, 24px) max(1rem, env(safe-area-inset-bottom));
overflow: auto;
overscroll-behavior: contain;
float: none;
clear: none;
filter: none;
font: inherit;
font-size: 1rem;
font-weight: 400;
font-style: normal;
color: var(--color-on-surface);
background: var(--color-surface-container-lowest);
border: 1px solid var(--color-outline);
border-block-end: 0;
border-radius: 0.5rem 0.5rem 0 0;
box-shadow: 0 -4px 20px var(--color-shadow);
&::before,
.sidenote__id {
display: none;
}
.sidenote__close {
display: inline;
}
}
.sidenote__close {
display: none;
min-inline-size: 1.5em;
padding: 0;
border: 0;
background: transparent;
color: var(--color-secondary);
font: inherit;
text-decoration: underline;
cursor: pointer;
}
:is(.sidenote__button, .sidenote__preview, .sidenote__close):focus-visible {
outline: 2px solid var(--color-secondary);
outline-offset: 2px;
}
@media (prefers-reduced-motion: no-preference) {
.sidenote__content[popover]:popover-open {
animation: sidenote-sheet-in 160ms ease-out;
}
}
@media screen {
@supports selector(:popover-open) {
.sidenote__button {
display: inline;
}
}
}
@media screen and (min-width: 1280px) {
.sidenote__content[popover]:popover-open {
animation: none;
}
.sidenote__content::before {
content: '\00a0';
display: flex;
align-items: flex-start;
justify-content: flex-end;
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 2px;
background: var(--color-secondary);
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.sidenote__content[popover]:not(:popover-open) {
display: block;
position: relative;
inset: auto;
height: auto;
border: 0;
background: transparent;
color: inherit;
}
.sidenote__content {
width: 25ch;
font-size: 0.75rem;
line-height: 1.4;
margin-top: -1.5ch;
padding: 0.5rem;
float: right;
clear: right;
margin-right: -28ch;
margin-bottom: 3ch;
border-radius: 0 0.5rem 0.5rem 0;
}
.sidenote__id {
margin-right: 1ch;
}
@supports (position-anchor: --sidenote) and (anchor-scope: --sidenote) and
(align-self: anchor-center) and (position-try-fallbacks: --sidenote-fit-viewport) {
.sidenote__slot {
display: block;
position: relative;
anchor-name: --sidenote;
anchor-scope: --sidenote;
float: right;
clear: right;
inline-size: 25ch;
font-size: 0.75rem;
font-weight: 400;
font-style: normal;
line-height: 1.4;
margin: -1.5ch -28ch 3ch 0;
padding: 0.5rem;
}
.sidenote__slot::before {
content: '';
position: absolute;
inset: 0.5rem auto 0.5rem 0;
inline-size: 2px;
background: var(--color-secondary);
}
.sidenote__preview {
display: block;
inline-size: 100%;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
text-align: start;
cursor: pointer;
}
.sidenote__excerpt {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
.sidenote__close {
min-inline-size: 0;
padding-inline-end: 1ch;
text-align: start;
}
/* Keep the invoker itself visible so native Escape can restore focus. */
.sidenote__slot:has(> :popover-open) > .sidenote__preview > .sidenote__excerpt,
.sidenote__slot:has(> :popover-open)::before {
visibility: hidden;
}
.sidenote__slot > .sidenote__content > :first-child {
margin-block-start: 0;
}
.sidenote__slot > .sidenote__content > :last-child {
margin-block-end: 0;
}
.sidenote__slot > .sidenote__content[popover]:not(:popover-open) {
display: none;
}
.sidenote__slot > .sidenote__content[popover]:popover-open {
position: fixed;
position-anchor: --sidenote;
position-visibility: always;
inset: auto;
top: anchor(top);
left: anchor(left);
align-self: auto;
inline-size: anchor-size(width);
max-inline-size: calc(100dvw - 24px);
block-size: auto;
min-block-size: 0;
max-block-size: min(50dvh, 30rem);
margin: 0;
padding: 0.5rem;
overflow: auto;
overscroll-behavior: contain;
position-try-fallbacks: --sidenote-fit-viewport, --sidenote-fit-viewport-inline;
border: 0;
font: inherit;
color: var(--color-on-surface);
background: var(--color-surface-container-lowest);
border-radius: 0 0.5rem 0.5rem 0;
box-shadow:
inset 2px 0 var(--color-secondary),
0 4px 20px var(--color-shadow);
}
}
}
@media print {
.sidenote__button {
display: inline;
min-inline-size: 0;
min-block-size: 0;
}
.sidenote__content[popover],
.sidenote__content[popover]:popover-open {
display: block;
position: static;
inset: auto;
inline-size: auto;
block-size: auto;
max-inline-size: none;
min-block-size: 0;
max-block-size: none;
margin: 0.5em 0;
padding: 0;
overflow: visible;
border: 0;
background: transparent;
color: inherit;
font: inherit;
box-shadow: none;
animation: none;
.sidenote__close {
display: none;
}
.sidenote__id {
display: inline;
}
}
.sidenote__content[popover]::backdrop {
background: none;
}
}
}