squash and nuke dev
This commit is contained in:
parent
b2d43ad425
commit
f26e76c114
93 changed files with 33827 additions and 7831 deletions
|
|
@ -1,14 +1,11 @@
|
|||
---
|
||||
import "@styles/components/accordion.css";
|
||||
---
|
||||
<details class=`accordion ${Astro.props.class ?? ""}` {...Astro.props}>
|
||||
<summary>
|
||||
<slot name="header"/>
|
||||
</summary>
|
||||
|
||||
<details class={`accordion ${Astro.props.class ?? ""}`} {...Astro.props}>
|
||||
<summary><slot name="header" /></summary>
|
||||
<div class="accordion-container">
|
||||
<div>
|
||||
<slot/>
|
||||
</div>
|
||||
<div><slot /></div>
|
||||
</div>
|
||||
</details>
|
||||
<script>
|
||||
|
|
@ -16,7 +13,9 @@ import "@styles/components/accordion.css";
|
|||
document.querySelectorAll(".accordion").forEach(element => {
|
||||
const accordion = element as HTMLDetailsElement;
|
||||
const summary = accordion.querySelector("summary")!;
|
||||
const body = accordion.querySelector(".accordion-container") as HTMLDivElement;
|
||||
const body = accordion.querySelector(
|
||||
".accordion-container"
|
||||
) as HTMLDivElement;
|
||||
|
||||
summary.addEventListener("click", event => {
|
||||
if ((event.target as Element).tagName === "A") return;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
const production = import.meta.env.PRODUCTION;
|
||||
---
|
||||
|
||||
{production && <script is:inline defer data-domain="quickshell.outfoxxed.me" src="https://z.outfoxxed.me/z.js"></script>}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ export interface Props {
|
|||
|
||||
const { badgeText, withIcon = true, badgeIconName } = Astro.props;
|
||||
---
|
||||
|
||||
<span class="badge">
|
||||
{withIcon &&
|
||||
(
|
||||
badgeIconName ?
|
||||
<Icon name={badgeIconName}/>
|
||||
: <Icon name={"flag"}/>
|
||||
)
|
||||
}
|
||||
)}
|
||||
<span class="badge-text">{badgeText}</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ interface Props {
|
|||
}
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<Accordion class="docs-collapsible">
|
||||
<div slot="header">
|
||||
<Fragment set:html={collapsibleMarker}/>
|
||||
<Fragment set :html={collapsibleMarker} />
|
||||
{title}
|
||||
</div>
|
||||
<slot>
|
||||
<slot />
|
||||
</Accordion>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import matrixLogo from "@icons/matrix-logo.svg?raw";
|
||||
import discordLogo from "@icons/discord-logo.svg?raw";
|
||||
import gitLogo from "@icons/git-logo.svg?raw";
|
||||
import ThemeToggle from "./ThemeToggle.astro";
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
|
|
@ -9,6 +10,7 @@ interface Props {
|
|||
|
||||
const props = Astro.props;
|
||||
---
|
||||
|
||||
<footer class=`${props.class ?? ""}`>
|
||||
<div class="credits">
|
||||
<p class="hint">Brought to you by:</p>
|
||||
|
|
@ -18,6 +20,7 @@ const props = Astro.props;
|
|||
and our contributors
|
||||
</a>
|
||||
</div>
|
||||
<ThemeToggle />
|
||||
<div class="socials-changelog">
|
||||
<section class="socials">
|
||||
<a href="https://matrix.to/#/#quickshell:outfoxxed.me" target="_blank" aria-label="Join our matrix space">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import { ThemeSelect } from "@components/hooks/ThemeSwitch";
|
||||
import type { TypeData } from "@config/io/types";
|
||||
import ThemeToggle from "./ThemeToggle.astro";
|
||||
import type { TypeData } from "@config/_types";
|
||||
import Nav from "@components/navigation/sidebars/nav/index.astro";
|
||||
import TOC from "@components/navigation/sidebars/TOC.astro";
|
||||
import type { ConfigHeading } from "@components/navigation/sidebars/types";
|
||||
|
|
@ -14,16 +14,15 @@ interface Props {
|
|||
|
||||
const { title, headings, type } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="header">
|
||||
<div class="header-item header-left">
|
||||
<Nav mobile={true}/>
|
||||
<h3 class="header-title">
|
||||
<a href="/">Quickshell</a>
|
||||
</h3>
|
||||
<Nav mobile={true} />
|
||||
<h3 class="header-title"><a href="/">Quickshell</a></h3>
|
||||
</div>
|
||||
<div class="header-item header-right">
|
||||
<Search/>
|
||||
<ThemeSelect client:load />
|
||||
<TOC title={title} headings={headings} type={type} mobile={true}/>
|
||||
<Search />
|
||||
<ThemeToggle />
|
||||
<TOC title={title} headings={headings} type={type} mobile={true} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
50
src/components/ThemeToggle.astro
Normal file
50
src/components/ThemeToggle.astro
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
---
|
||||
|
||||
<label
|
||||
class="theme-toggle icon-button standard"
|
||||
title="Toggle theme"
|
||||
for="theme-manual-toggle"
|
||||
>
|
||||
<Icon
|
||||
name="moon"
|
||||
class="light-icon"
|
||||
style="width: 24px; height: 24px;"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<Icon
|
||||
name="sun"
|
||||
class="dark-icon"
|
||||
style="width: 24px; height: 24px;"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div class="state-layer"></div>
|
||||
</label>
|
||||
|
||||
<style>
|
||||
.theme-toggle {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.light-icon {
|
||||
display: block;
|
||||
}
|
||||
.dark-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:global(html:has(input#theme-manual-toggle:checked)) .light-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:global(html:has(input#theme-manual-toggle:checked)) .dark-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.theme-toggle:focus-within {
|
||||
outline: 2px solid var(--accent-600);
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
---
|
||||
import { processMarkdown } from "@config/io/markdown";
|
||||
|
||||
const codeDesktop = await processMarkdown("N/A", `\`\`\`qml
|
||||
const codeDesktop = await processMarkdown(
|
||||
"N/A",
|
||||
`\`\`\`qml
|
||||
// a standard desktop window
|
||||
FloatingWindow {
|
||||
Timer {
|
||||
|
|
@ -19,9 +21,12 @@ FloatingWindow {
|
|||
// change the window's color when timer.invert changes
|
||||
color: timer.invert ? "purple" : "green"
|
||||
}
|
||||
\`\`\``);
|
||||
\`\`\``
|
||||
);
|
||||
|
||||
const codeMobile = await processMarkdown("N/A", `\`\`\`qml
|
||||
const codeMobile = await processMarkdown(
|
||||
"N/A",
|
||||
`\`\`\`qml
|
||||
// a standard desktop window
|
||||
FloatingWindow {
|
||||
Timer {
|
||||
|
|
@ -47,19 +52,22 @@ FloatingWindow {
|
|||
? "purple"
|
||||
: "green"
|
||||
}
|
||||
\`\`\``);
|
||||
\`\`\``
|
||||
);
|
||||
---
|
||||
|
||||
<ul class="featurelist">
|
||||
<li class="featurelist-item hot-reloading left">
|
||||
<section class="feature-text">
|
||||
<h3 class="feature-title">See your changes in real time</h3>
|
||||
<span class="feature-subtitle">
|
||||
Quickshell loads changes as soon as they're saved, letting you iterate as fast as you can type.
|
||||
Quickshell loads changes as soon as they're saved, letting you iterate
|
||||
as fast as you can type.
|
||||
</span>
|
||||
</section>
|
||||
<section class="feature-showcase">
|
||||
<video preload="metadata" controls={false} autoplay loop>
|
||||
<source src="/assets/simple-shell-livereload.mp4" type="video/mp4"/>
|
||||
<source src="/assets/simple-shell-livereload.mp4" type="video/mp4">
|
||||
</video>
|
||||
</section>
|
||||
</li>
|
||||
|
|
@ -67,46 +75,69 @@ FloatingWindow {
|
|||
<section class="feature-text">
|
||||
<h3 class="feature-title">Easy to use language</h3>
|
||||
<span class="feature-subtitle">
|
||||
Quickshell is configured in QML, a simple language designed for creating flexible user interfaces.
|
||||
It also has LSP support.
|
||||
Quickshell is configured in QML, a simple language designed for creating
|
||||
flexible user interfaces. It also has LSP support.
|
||||
</span>
|
||||
</section>
|
||||
<section class="feature-showcase" id="qml-showcase">
|
||||
<div class="showcase-desktop">
|
||||
<Fragment set:html={codeDesktop}/>
|
||||
</div>
|
||||
<div class="showcase-mobile">
|
||||
<Fragment set:html={codeMobile}/>
|
||||
</div>
|
||||
<div class="showcase-desktop"><Fragment set :html={codeDesktop} /></div>
|
||||
<div class="showcase-mobile"><Fragment set :html={codeMobile} /></div>
|
||||
</section>
|
||||
</li>
|
||||
<li class="featurelist-item cloud-li left">
|
||||
<section class="feature-text">
|
||||
<h3 class="feature-title">Extensive integrations</h3>
|
||||
<span class="feature-subtitle">
|
||||
Quickshell comes with a large set of integrations, with new ones arriving all the time.
|
||||
Quickshell comes with a large set of integrations, with new ones
|
||||
arriving all the time.
|
||||
</span>
|
||||
</section>
|
||||
<section class="feature-showcase cloud">
|
||||
<section class="feature-cloud">
|
||||
<div class="cloud-center">
|
||||
<img src="/favicon.svg" alt="Quickshell" />
|
||||
<img src="/favicon.svg" alt="Quickshell">
|
||||
</div>
|
||||
<div class="cloud-items-wrapper">
|
||||
<span class="cloud-item wayland">
|
||||
<div><img class="feature-icon" src="/assets/logos/wayland.svg" alt="Wayland" /></div>
|
||||
<div>
|
||||
<img
|
||||
class="feature-icon"
|
||||
src="/assets/logos/wayland.svg"
|
||||
alt="Wayland"
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
<span class="cloud-item hyprland">
|
||||
<div><img class="feature-icon" src="/assets/logos/hyprland.svg" alt="Hyprland" /></div>
|
||||
<div>
|
||||
<img
|
||||
class="feature-icon"
|
||||
src="/assets/logos/hyprland.svg"
|
||||
alt="Hyprland"
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
<span class="cloud-item pipewire">
|
||||
<div><img class="feature-icon" src="/assets/logos/pipewire.svg" alt="Pipewire" /></div>
|
||||
<div>
|
||||
<img
|
||||
class="feature-icon"
|
||||
src="/assets/logos/pipewire.svg"
|
||||
alt="Pipewire"
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
<span class="cloud-item x-org">
|
||||
<div><img class="feature-icon" src="/assets/logos/xorg.svg" alt="X.Org" /></div>
|
||||
<div>
|
||||
<img
|
||||
class="feature-icon"
|
||||
src="/assets/logos/xorg.svg"
|
||||
alt="X.Org"
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
<span class="cloud-item sway">
|
||||
<div><img class="feature-icon" src="/assets/logos/sway.svg" alt="Sway" /></div>
|
||||
<div>
|
||||
<img class="feature-icon" src="/assets/logos/sway.svg" alt="Sway">
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
---
|
||||
|
||||
---
|
||||
|
||||
<script>
|
||||
setTimeout(() => {
|
||||
// code copy
|
||||
let blocks = document.querySelectorAll("pre");
|
||||
if (blocks.length > 0) {
|
||||
blocks.forEach((block) => {
|
||||
let button = document.createElement("button");
|
||||
button.className = "copy-button";
|
||||
button.innerHTML = `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 256 256"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M200 32h-36.26a47.92 47.92 0 0 0-71.48 0H56a16 16 0 0 0-16 16v168a16 16 0 0 0 16 16h144a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16m-72 0a32 32 0 0 1 32 32H96a32 32 0 0 1 32-32m72 184H56V48h26.75A47.9 47.9 0 0 0 80 64v8a8 8 0 0 0 8 8h80a8 8 0 0 0 8-8v-8a47.9 47.9 0 0 0-2.75-16H200Z"
|
||||
/>
|
||||
</svg>
|
||||
`;
|
||||
button.onclick = () => {
|
||||
let snippet = block.innerText ?? "";
|
||||
navigator.clipboard.writeText(snippet);
|
||||
button.classList.toggle("copied");
|
||||
setTimeout(() => button.classList.remove("copied"), 1000);
|
||||
};
|
||||
block.appendChild(button);
|
||||
});
|
||||
}
|
||||
}, 3001)
|
||||
|
||||
// heading copy
|
||||
let headings = document.getElementsByClassName("heading")
|
||||
if (headings.length > 0) {
|
||||
for (const heading of headings) {
|
||||
let button = heading.querySelector("span")
|
||||
if (button) {
|
||||
button.onclick = () => {
|
||||
let link = window.location.href.split("#")[0];
|
||||
link += `#-${heading.textContent?.slice(10).trimEnd().replaceAll(" ", "-").toLowerCase()}`;
|
||||
window.location.href = link
|
||||
navigator.clipboard.writeText(link);
|
||||
heading.classList.toggle("copied")
|
||||
setTimeout(() => heading.classList.remove("copied"), 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
---
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
const heading = entry.target.querySelector('h1, h2, h3, h4, h5, h6')
|
||||
if(heading) {
|
||||
const id = heading.id
|
||||
if (entry.intersectionRatio > 0) {
|
||||
const desktopElement = document.querySelector(`.toc-wrapper li a[href="#${id}"]`);
|
||||
const mobileElement = document.querySelector(`.toc-wrapper-mobile li a[href="#${id}"]`);
|
||||
const element = mobileElement?.checkVisibility() ? mobileElement : desktopElement;
|
||||
element?.parentElement?.classList.add('active')
|
||||
} else {
|
||||
const desktopElement = document.querySelector(`.toc-wrapper li a[href="#${id}"]`);
|
||||
const mobileElement = document.querySelector(`.toc-wrapper-mobile li a[href="#${id}"]`);
|
||||
const element = mobileElement?.checkVisibility() ? mobileElement : desktopElement;
|
||||
element?.parentElement?.classList.remove('active')
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('section[data-heading-rank]').forEach((section) => {
|
||||
observer.observe(section);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
import {
|
||||
createSignal,
|
||||
createEffect,
|
||||
onCleanup,
|
||||
onMount,
|
||||
type VoidComponent,
|
||||
} from "solid-js";
|
||||
|
||||
import Sun from "@icons/sun.svg?raw";
|
||||
import Moon from "@icons/moon.svg?raw";
|
||||
|
||||
export interface ThemeProps {
|
||||
theme: "light" | "dark";
|
||||
system: "light" | "dark";
|
||||
}
|
||||
|
||||
export const getCurrentTheme = (): ThemeProps => {
|
||||
if (
|
||||
typeof localStorage !== "undefined" &&
|
||||
(localStorage.theme === "dark" ||
|
||||
(!("theme" in localStorage) &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)")
|
||||
.matches))
|
||||
) {
|
||||
return {
|
||||
theme: "dark",
|
||||
system: window.matchMedia("(prefers-color-scheme: dark)")
|
||||
.matches
|
||||
? "dark"
|
||||
: "light",
|
||||
};
|
||||
}
|
||||
return {
|
||||
theme: "light",
|
||||
system: window.matchMedia("(prefers-color-scheme: dark)")
|
||||
.matches
|
||||
? "dark"
|
||||
: "light",
|
||||
};
|
||||
};
|
||||
|
||||
const updateTheme = () => {
|
||||
document.documentElement.classList.add("changing-theme");
|
||||
if (
|
||||
localStorage.theme === "dark" ||
|
||||
(!("theme" in localStorage) &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
document.documentElement.classList.remove("changing-theme");
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const ThemeSelect: VoidComponent = () => {
|
||||
const [currentTheme, setCurrentTheme] =
|
||||
createSignal<ThemeProps>({
|
||||
theme: "dark",
|
||||
system: "dark",
|
||||
});
|
||||
const [mounted, setMounted] = createSignal(false);
|
||||
|
||||
const toggleTheme = () => {
|
||||
if (!mounted()) return;
|
||||
setCurrentTheme(getCurrentTheme());
|
||||
if (currentTheme()!.theme !== currentTheme()!.system) {
|
||||
localStorage.removeItem("theme");
|
||||
} else {
|
||||
localStorage.theme =
|
||||
currentTheme()!.theme === "dark" ? "light" : "dark";
|
||||
}
|
||||
updateTheme();
|
||||
setCurrentTheme(getCurrentTheme());
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
setMounted(true);
|
||||
setCurrentTheme(getCurrentTheme());
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
const mediaQuery = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)"
|
||||
);
|
||||
mediaQuery.addEventListener("change", updateTheme);
|
||||
window.addEventListener("storage", updateTheme);
|
||||
|
||||
onCleanup(() => {
|
||||
mediaQuery.removeEventListener("change", updateTheme);
|
||||
window.removeEventListener("storage", updateTheme);
|
||||
setMounted(false);
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
onclick={toggleTheme}
|
||||
class="theme-toggle"
|
||||
innerHTML={
|
||||
(mounted() && currentTheme().theme === "light") ||
|
||||
currentTheme().system === "light"
|
||||
? Sun
|
||||
: Moon
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,145 +1,18 @@
|
|||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
const videos = [
|
||||
{
|
||||
author: '<a href="https://github.com/soramanew">soramane</a>',
|
||||
source: "https://github.com/caelestia-dots/shell",
|
||||
path: "/assets/showcase/soramane.mp4",
|
||||
installable: true,
|
||||
},
|
||||
{
|
||||
author: '<a href="https://github.com/end-4">end_4</a>',
|
||||
source: "https://github.com/end-4/dots-hyprland",
|
||||
path: "/assets/showcase/end4.mp4",
|
||||
installable: true,
|
||||
},
|
||||
{
|
||||
author: '<a href="https://outfoxxed.me">outfoxxed</a>',
|
||||
source: "https://git.outfoxxed.me/outfoxxed/nixnew/src/branch/master/modules/user/modules/quickshell",
|
||||
path: "/assets/showcase/outfoxxed.mp4",
|
||||
},
|
||||
{
|
||||
author: '<a href="https://github.com/pfaj/">pfaj</a> and <a href="https://github.com/bdebiase">bdebiase</a>',
|
||||
path: "/assets/showcase/pfaj-bdeblase.mp4",
|
||||
},
|
||||
{
|
||||
author: '<a href="https://github.com/flickowoa">flicko</a>',
|
||||
source: "https://github.com/flickowoa/zephyr",
|
||||
path: "/assets/showcase/flicko.mp4",
|
||||
},
|
||||
{
|
||||
author: '<a href="https://vaxry.net">vaxry</a>',
|
||||
path: "/assets/showcase/vaxry.mp4",
|
||||
},
|
||||
];
|
||||
import MarqueeContent from "./MarqueeContent.astro";
|
||||
---
|
||||
|
||||
<div class="marquee">
|
||||
<div class="marquee-scroll">
|
||||
<div id="marquee-scroll-left" class="marquee-scroll-arrow">
|
||||
<div><Icon name="caret-left"/></div>
|
||||
<div><Icon name="caret-left" /></div>
|
||||
</div>
|
||||
<div id="marquee-scroll-right" class="marquee-scroll-arrow">
|
||||
<div><Icon name="caret-right"/></div>
|
||||
<div><Icon name="caret-right" /></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="marquee-content" class="marquee-content" data-scroll="0" data-media-index="0">
|
||||
{videos.map(({ author, source, installable, path }, index) => <div class="marquee-item">
|
||||
<div>
|
||||
<video
|
||||
data-media-index={index}
|
||||
data-media-author={author}
|
||||
id="showcase-video"
|
||||
class="marquee-item-spacing marquee-item-content"
|
||||
muted
|
||||
controls
|
||||
playsinline
|
||||
preload="metadata"
|
||||
>
|
||||
<source src={path} type="video/mp4"/>
|
||||
</video>
|
||||
<p>
|
||||
Configuration by <Fragment set:html={author}/>
|
||||
{source && !installable && <>(<a href={source}>source code</a>)</>}
|
||||
{source && installable && <>(<a href={source}>install</a>)</>}
|
||||
</p>
|
||||
</div>
|
||||
</div>)}
|
||||
</div>
|
||||
<MarqueeContent />
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const videoCount = 6; // last array index
|
||||
const marquee = document.getElementById("marquee-content")!;
|
||||
marquee.style.setProperty("--scroll", "0")
|
||||
|
||||
window.addEventListener("load", autoplayInit, false);
|
||||
const videos = document.getElementsByClassName("marquee-item-content") as HTMLCollectionOf<HTMLVideoElement>;
|
||||
let currentVideoIndex = 0;
|
||||
let currentVideo: HTMLVideoElement | null = null;
|
||||
|
||||
function autoplayInit() {
|
||||
setActiveVideo(0);
|
||||
currentVideo!.play();
|
||||
}
|
||||
|
||||
function setActiveVideo(index: number) {
|
||||
currentVideo?.pause();
|
||||
|
||||
currentVideoIndex = index;
|
||||
currentVideo = videos[currentVideoIndex];
|
||||
currentVideo.currentTime = 0;
|
||||
marquee.style.setProperty("--scroll", `-${currentVideoIndex*100}%`)
|
||||
}
|
||||
|
||||
function offsetCarousel(offset: number) {
|
||||
let nextIndex = currentVideoIndex + offset;
|
||||
if (nextIndex < 0) nextIndex += videoCount;
|
||||
nextIndex = nextIndex % videoCount;
|
||||
setActiveVideo(nextIndex);
|
||||
}
|
||||
|
||||
const intersectionOptions = {
|
||||
root: marquee,
|
||||
rootMargin: "0px",
|
||||
threshold: 0.0,
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
const video = entry.target as HTMLVideoElement;
|
||||
if (!entry.isIntersecting) {
|
||||
video.pause();
|
||||
} else if (video === currentVideo) {
|
||||
video.play();
|
||||
}
|
||||
});
|
||||
}, intersectionOptions);
|
||||
|
||||
for (const video of videos) {
|
||||
observer.observe(video);
|
||||
|
||||
video.addEventListener("ended", () => {
|
||||
// The "ended" event might just mean its buffering.
|
||||
if (video == currentVideo && video.duration !== 0 && video.currentTime === video.duration) {
|
||||
offsetCarousel(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let wasPaused = false;
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (currentVideo) {
|
||||
if (document.hidden) {
|
||||
wasPaused = currentVideo.paused;
|
||||
currentVideo.pause();
|
||||
} else if (!wasPaused) {
|
||||
currentVideo.play();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// left-right buttons
|
||||
document.getElementById("marquee-scroll-left")!.addEventListener("mousedown", () => offsetCarousel(-1));
|
||||
document.getElementById("marquee-scroll-right")!.addEventListener("mousedown", () => offsetCarousel(1));
|
||||
</script>
|
||||
<script src="@config/styling/marquee.ts" />
|
||||
|
|
|
|||
66
src/components/marquee/MarqueeContent.astro
Normal file
66
src/components/marquee/MarqueeContent.astro
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
const videos = [
|
||||
{
|
||||
author: '<a href="https://github.com/soramanew">soramane</a>',
|
||||
source: "https://github.com/caelestia-dots/shell",
|
||||
path: "/assets/showcase/soramane.mp4",
|
||||
installable: true,
|
||||
},
|
||||
{
|
||||
author: '<a href="https://github.com/end-4">end_4</a>',
|
||||
source: "https://github.com/end-4/dots-hyprland",
|
||||
path: "/assets/showcase/end4.mp4",
|
||||
installable: true,
|
||||
},
|
||||
{
|
||||
author: '<a href="https://outfoxxed.me">outfoxxed</a>',
|
||||
source:
|
||||
"https://git.outfoxxed.me/outfoxxed/nixnew/src/branch/master/modules/user/modules/quickshell",
|
||||
path: "/assets/showcase/outfoxxed.mp4",
|
||||
},
|
||||
{
|
||||
author:
|
||||
'<a href="https://github.com/pfaj/">pfaj</a> and <a href="https://github.com/bdebiase">bdebiase</a>',
|
||||
path: "/assets/showcase/pfaj-bdeblase.mp4",
|
||||
},
|
||||
{
|
||||
author: '<a href="https://github.com/flickowoa">flicko</a>',
|
||||
source: "https://github.com/flickowoa/zephyr",
|
||||
path: "/assets/showcase/flicko.mp4",
|
||||
},
|
||||
{
|
||||
author: '<a href="https://vaxry.net">vaxry</a>',
|
||||
path: "/assets/showcase/vaxry.mp4",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<div
|
||||
id="marquee-content"
|
||||
class="marquee-content"
|
||||
data-scroll="0"
|
||||
data-media-index="0"
|
||||
>
|
||||
{videos.map(({ author, source, installable, path }, index) => {
|
||||
return (
|
||||
<div class=`marquee-item`>
|
||||
<video
|
||||
data-media-index={index}
|
||||
data-media-author={author}
|
||||
id="showcase-video"
|
||||
class="marquee-item-spacing marquee-item-content"
|
||||
muted
|
||||
controls
|
||||
playsinline
|
||||
preload="metadata"
|
||||
>
|
||||
<source src={path} type="video/mp4"/>
|
||||
</video>
|
||||
<p>
|
||||
Configuration by <Fragment set:html={author}/>
|
||||
{source && !installable && <>(<a href={source}>source code</a>)</>}
|
||||
{source && installable && <>(<a href={source}>install</a>)</>}
|
||||
</p>
|
||||
</div>
|
||||
)})}
|
||||
</div>
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
import "@pagefind/default-ui/css/ui.css";
|
||||
import magnifierIcon from "@icons/magnifier.svg?raw"
|
||||
import magnifierIcon from "@icons/magnifier.svg?raw";
|
||||
---
|
||||
|
||||
<site-search class="search-wrapper">
|
||||
<button
|
||||
data-open-modal
|
||||
|
|
@ -10,141 +11,161 @@ import magnifierIcon from "@icons/magnifier.svg?raw"
|
|||
aria-keyshortcuts="Control+K"
|
||||
class="search-button"
|
||||
>
|
||||
<Fragment set:html={magnifierIcon}/>
|
||||
<Fragment set :html={magnifierIcon} />
|
||||
<span class="search-label" aria-hidden="true">Search</span>
|
||||
<kbd class="search-kbd">
|
||||
<kbd>Ctrl</kbd><kbd>K</kbd>
|
||||
</kbd>
|
||||
<kbd class="search-kbd"> <kbd>Ctrl</kbd><kbd>K</kbd> </kbd>
|
||||
</button>
|
||||
<dialog aria-label="Search" class="search-dialog">
|
||||
<div class="dialog-frame">
|
||||
<button data-close-modal class="search-cancel">
|
||||
Cancel
|
||||
</button>
|
||||
<button data-close-modal class="search-cancel">Cancel</button>
|
||||
<div class="search-container">
|
||||
<div id="qs_search"/>
|
||||
<div id="qs_search" />
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</site-search>
|
||||
{
|
||||
/**
|
||||
{/**
|
||||
* NOTE: YOINKED FROM STARLIGHT
|
||||
* This is intentionally inlined to avoid briefly showing an invalid shortcut.
|
||||
* Purposely using the deprecated `navigator.platform` property to detect Apple devices, as the
|
||||
* user agent is spoofed by some browsers when opening the devtools.
|
||||
*/
|
||||
}
|
||||
*/}
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const openBtn = document.querySelector('button[data-open-modal]');
|
||||
const shortcut = openBtn?.querySelector('kbd');
|
||||
if (!openBtn || !(shortcut instanceof HTMLElement)) return;
|
||||
const platformKey = shortcut.querySelector('kbd');
|
||||
if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
|
||||
platformKey.textContent = '⌘';
|
||||
openBtn.setAttribute('aria-keyshortcuts', 'Meta+K');
|
||||
}
|
||||
shortcut.style.display = '';
|
||||
})();
|
||||
(() => {
|
||||
const openBtn = document.querySelector("button[data-open-modal]");
|
||||
const shortcut = openBtn?.querySelector("kbd");
|
||||
if (!openBtn || !(shortcut instanceof HTMLElement)) return;
|
||||
const platformKey = shortcut.querySelector("kbd");
|
||||
if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
|
||||
platformKey.textContent = "⌘";
|
||||
openBtn.setAttribute("aria-keyshortcuts", "Meta+K");
|
||||
}
|
||||
shortcut.style.display = "";
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { getQMLTypeLinkObject, getQMLTypeLink, getIconForLink } from '@src/config/io/helpers';
|
||||
class SiteSearch extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const openBtn = this.querySelector<HTMLButtonElement>('button[data-open-modal]')!;
|
||||
const closeBtn = this.querySelector<HTMLButtonElement>('button[data-close-modal]')!;
|
||||
const dialog = this.querySelector('dialog')!;
|
||||
const dialogFrame = this.querySelector('.dialog-frame')!;
|
||||
import {
|
||||
getQMLTypeLinkObject,
|
||||
getQMLTypeLink,
|
||||
getIconForLink,
|
||||
} from "@src/config/io/helpers";
|
||||
class SiteSearch extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const openBtn = this.querySelector<HTMLButtonElement>(
|
||||
"button[data-open-modal]"
|
||||
)!;
|
||||
const closeBtn = this.querySelector<HTMLButtonElement>(
|
||||
"button[data-close-modal]"
|
||||
)!;
|
||||
const dialog = this.querySelector("dialog")!;
|
||||
const dialogFrame = this.querySelector(".dialog-frame")!;
|
||||
|
||||
/** Close the modal if a user clicks on a link or outside of the modal. */
|
||||
const onClick = (event: MouseEvent) => {
|
||||
const isLink = 'href' in (event.target || {});
|
||||
if (
|
||||
isLink ||
|
||||
(document.body.contains(event.target as Node) &&
|
||||
!dialogFrame.contains(event.target as Node))
|
||||
) {
|
||||
closeModal();
|
||||
}
|
||||
};
|
||||
/** Close the modal if a user clicks on a link or outside of the modal. */
|
||||
const onClick = (event: MouseEvent) => {
|
||||
const isLink = "href" in (event.target || {});
|
||||
if (
|
||||
isLink ||
|
||||
(document.body.contains(event.target as Node) &&
|
||||
!dialogFrame.contains(event.target as Node))
|
||||
) {
|
||||
closeModal();
|
||||
}
|
||||
};
|
||||
|
||||
const openModal = (event?: MouseEvent) => {
|
||||
dialog.showModal();
|
||||
document.body.toggleAttribute('data-search-modal-open', true);
|
||||
this.querySelector('input')?.focus();
|
||||
event?.stopPropagation();
|
||||
window.addEventListener('click', onClick);
|
||||
};
|
||||
const openModal = (event?: MouseEvent) => {
|
||||
dialog.showModal();
|
||||
document.body.toggleAttribute("data-search-modal-open", true);
|
||||
this.querySelector("input")?.focus();
|
||||
event?.stopPropagation();
|
||||
window.addEventListener("click", onClick);
|
||||
};
|
||||
|
||||
const closeModal = () => dialog.close();
|
||||
const closeModal = () => dialog.close();
|
||||
|
||||
openBtn.addEventListener('click', openModal);
|
||||
openBtn.disabled = false;
|
||||
closeBtn.addEventListener('click', closeModal);
|
||||
openBtn.addEventListener("click", openModal);
|
||||
openBtn.disabled = false;
|
||||
closeBtn.addEventListener("click", closeModal);
|
||||
|
||||
dialog.addEventListener('close', () => {
|
||||
document.body.toggleAttribute('data-search-modal-open', false);
|
||||
window.removeEventListener('click', onClick);
|
||||
});
|
||||
dialog.addEventListener("close", () => {
|
||||
document.body.toggleAttribute("data-search-modal-open", false);
|
||||
window.removeEventListener("click", onClick);
|
||||
});
|
||||
|
||||
// Listen for `ctrl + k` and `cmd + k` keyboard shortcuts.
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'k') {
|
||||
dialog.open ? closeModal() : openModal();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
const processExcerpt = (sub_resultExcerpt:string):string => {
|
||||
// Listen for `ctrl + k` and `cmd + k` keyboard shortcuts.
|
||||
window.addEventListener("keydown", e => {
|
||||
if ((e.metaKey === true || e.ctrlKey === true) && e.key === "k") {
|
||||
dialog.open ? closeModal() : openModal();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
const processExcerpt = (sub_resultExcerpt: string): string => {
|
||||
const linkRegex = /TYPE99(\w+.)99TYPE/g;
|
||||
let excerpt = sub_resultExcerpt;
|
||||
const match = [...excerpt.matchAll(linkRegex)];
|
||||
if (match.length > 0){
|
||||
if (match.length > 0) {
|
||||
for (const matching of match) {
|
||||
const linkObject = getQMLTypeLinkObject(matching[1]);
|
||||
const link = getQMLTypeLink("NOVERSION", linkObject);
|
||||
const icon = linkObject.mtype ? getIconForLink(linkObject.mtype, false) : null;
|
||||
const icon = linkObject.mtype
|
||||
? getIconForLink(linkObject.mtype, false)
|
||||
: null;
|
||||
|
||||
// for signal
|
||||
const bracketString = getIconForLink("func", false)
|
||||
const bracketString = getIconForLink("func", false);
|
||||
|
||||
const newLink = `<span class="type${linkObject.mtype}-link typedata-link">${icon ? icon : ""}<a href=${link}>${linkObject.mname || linkObject.name}</a>${linkObject.mtype === "signal" ? bracketString : ""}</span>`;
|
||||
excerpt = excerpt.replace(matching[0], newLink)
|
||||
excerpt = excerpt.replace(matching[0], newLink);
|
||||
}
|
||||
}
|
||||
return excerpt
|
||||
}
|
||||
return excerpt;
|
||||
};
|
||||
|
||||
const formatURL = (path: string) => path;
|
||||
|
||||
const formatURL = (path: string) => path;
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));
|
||||
onIdle(async () => {
|
||||
// @ts-expect-error — Missing types for @pagefind/default-ui package.
|
||||
const { PagefindUI } = await import('@pagefind/default-ui');
|
||||
new PagefindUI({
|
||||
element: '#qs_search',
|
||||
baseUrl: import.meta.env.BASE_URL,
|
||||
bundlePath: import.meta.env.BASE_URL.replace(/\/$/, '') + '/pagefind/',
|
||||
showImages: false,
|
||||
showSubResults: true,
|
||||
processResult: (result: { url: string; excerpt:string; sub_results: Array<{ url: string, excerpt:string }> }) => {
|
||||
result.url = formatURL(result.url);
|
||||
result.excerpt = processExcerpt(result.excerpt)
|
||||
result.sub_results = result.sub_results.map((sub_result) => {
|
||||
sub_result.url = formatURL(sub_result.url);
|
||||
sub_result.excerpt = processExcerpt(sub_result.excerpt)
|
||||
return sub_result;
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define('site-search', SiteSearch);
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
const onIdle = window.requestIdleCallback || (cb => setTimeout(cb, 1));
|
||||
onIdle(async () => {
|
||||
const { PagefindUI } = await import(
|
||||
//@ts-expect-error — Missing types for @pagefind/default-ui package.
|
||||
"@pagefind/default-ui"
|
||||
);
|
||||
new PagefindUI({
|
||||
element: "#qs_search",
|
||||
baseUrl: import.meta.env.BASE_URL,
|
||||
bundlePath:
|
||||
import.meta.env.BASE_URL.replace(/\/$/, "") + "/pagefind/",
|
||||
showImages: false,
|
||||
showSubResults: true,
|
||||
processResult: (result: {
|
||||
url: string;
|
||||
excerpt: string;
|
||||
meta: {
|
||||
source: string;
|
||||
};
|
||||
extra_class: string;
|
||||
sub_results: Array<{
|
||||
url: string;
|
||||
excerpt: string;
|
||||
}>;
|
||||
}) => {
|
||||
if (result.meta.source === "Qt Framework") {
|
||||
result.extra_class = "qt-result-badge";
|
||||
}
|
||||
result.url = formatURL(result.url);
|
||||
result.excerpt = processExcerpt(result.excerpt);
|
||||
result.sub_results = result.sub_results.map(sub_result => {
|
||||
sub_result.url = formatURL(sub_result.url);
|
||||
sub_result.excerpt = processExcerpt(sub_result.excerpt);
|
||||
return sub_result;
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define("site-search", SiteSearch);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
---
|
||||
import TableOfContents from "./toc";
|
||||
import type { ConfigHeading, TypeTOC } from "./types.d.ts";
|
||||
import type { TypeData } from "@config/io/types";
|
||||
import type {
|
||||
TypeData,
|
||||
QuickshellFunction,
|
||||
// QuickshellSignal,
|
||||
// QuickshellVariant,
|
||||
// QuickshellProps,
|
||||
} from "@config/_types";
|
||||
|
||||
export interface Props {
|
||||
title?: string;
|
||||
|
|
@ -12,13 +18,16 @@ export interface Props {
|
|||
|
||||
const { title, headings, type, mobile } = Astro.props;
|
||||
|
||||
const types: TypeTOC | null = type ? {
|
||||
properties: Object.keys(type.properties ?? {}),
|
||||
functions: (type.functions ?? []).map(f => f.name),
|
||||
signals: Object.keys(type.signals ?? {}),
|
||||
variants: Object.keys(type.variants ?? {}),
|
||||
} : null;
|
||||
const types: TypeTOC | null = type
|
||||
? {
|
||||
properties: Object.keys(type.properties ?? {}),
|
||||
functions: (type.functions ?? []).map((f: QuickshellFunction) => f.name),
|
||||
signals: Object.keys(type.signals ?? {}),
|
||||
variants: Object.keys(type.variants ?? {}),
|
||||
}
|
||||
: null;
|
||||
---
|
||||
|
||||
{((headings?.length ?? 0) != 0 || types) &&
|
||||
<div id="toc" aria-mobile={mobile} class=`toc-wrapper${mobile ? "-mobile":""}`>
|
||||
<TableOfContents
|
||||
|
|
@ -28,5 +37,4 @@ const types: TypeTOC | null = type ? {
|
|||
mobile={mobile}
|
||||
client:idle
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ interface Props {
|
|||
|
||||
const { title, link, current, showIcon } = Astro.props;
|
||||
---
|
||||
|
||||
<a class=`nav-component nav-item nav-link ${current ? "nav-current" : ""}` href={link}>
|
||||
{ showIcon ? (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ interface Props {
|
|||
}
|
||||
const { title, link, current } = Astro.props;
|
||||
---
|
||||
|
||||
<Accordion class=`nav-component nav-collapsible ${current ? "nav-current" : ""}` {...(current ? { open: "_" } : {})}>
|
||||
<div slot="header">
|
||||
<a class=`nav-link ${current ? "nav-current" : ""}` href={link}>{title}</a>
|
||||
|
|
@ -16,5 +17,5 @@ const { title, link, current } = Astro.props;
|
|||
<Fragment set:html={navMarker}/>
|
||||
</div>
|
||||
</div>
|
||||
<slot>
|
||||
<slot />
|
||||
</Accordion>
|
||||
|
|
|
|||
|
|
@ -13,19 +13,25 @@ import Link from "./Link.astro";
|
|||
|
||||
const versions = await getVersionsData();
|
||||
const versionName = Astro.params.version;
|
||||
const modules = versions.versions.find(version => version.name === versionName)?.modules;
|
||||
const modules = versions.versions.find(
|
||||
version => version.name === versionName
|
||||
)?.modules;
|
||||
|
||||
const currentPath = Astro.url.pathname.split('/').filter(s => s !== "");
|
||||
const currentPath = Astro.url.pathname.split("/").filter(s => s !== "");
|
||||
|
||||
const guidePages = await getGuideCollection(versionName ?? "");
|
||||
|
||||
interface NavTree {
|
||||
title: string,
|
||||
slug: string,
|
||||
entries?: NavTree[],
|
||||
title: string;
|
||||
slug: string;
|
||||
entries?: NavTree[];
|
||||
}
|
||||
|
||||
function mkTree(mount: string, pathIdx: number, { title, slug, entries }: NavTree): TreeEntry {
|
||||
function mkTree(
|
||||
mount: string,
|
||||
pathIdx: number,
|
||||
{ title, slug, entries }: NavTree
|
||||
): TreeEntry {
|
||||
const link = `${mount}/${slug}`;
|
||||
|
||||
return {
|
||||
|
|
@ -38,7 +44,9 @@ function mkTree(mount: string, pathIdx: number, { title, slug, entries }: NavTre
|
|||
|
||||
function genGuideNav(base: string): NavTree[] | undefined {
|
||||
const pages = guidePages
|
||||
.filter(page => page.id.match(`^${base}[^/]*$`) !== null && page.id !== "index")
|
||||
.filter(
|
||||
page => page.id.match(`^${base}[^/]*$`) !== null && page.id !== "index"
|
||||
)
|
||||
.sort((a, b) => a.data.index - b.data.index)
|
||||
.map(page => ({
|
||||
title: page.data.title,
|
||||
|
|
@ -68,8 +76,8 @@ if (versionName) {
|
|||
entries: module.types.map(type => ({
|
||||
title: type.name,
|
||||
slug: type.name,
|
||||
}))
|
||||
}))
|
||||
})),
|
||||
})),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -84,6 +92,7 @@ if (versionName) {
|
|||
};
|
||||
}
|
||||
---
|
||||
|
||||
<nav class="navtree">
|
||||
<Link
|
||||
title="About"
|
||||
|
|
@ -95,9 +104,9 @@ if (versionName) {
|
|||
link="/changelog"
|
||||
current={currentPath.length === 1 && currentPath[0] === "changelog"}
|
||||
/>
|
||||
{ versionedEntries && <Tree {...versionsTree as TreeEntry}/>}
|
||||
<hr/>
|
||||
{ versionedEntries && (
|
||||
{versionedEntries && <Tree {...versionsTree as TreeEntry}/>}
|
||||
<hr>
|
||||
{versionedEntries && (
|
||||
<Tree {...versionedEntries.guide}/>
|
||||
<Tree {...versionedEntries.types}/>
|
||||
<Link
|
||||
|
|
@ -111,7 +120,7 @@ if (versionName) {
|
|||
showIcon={true}
|
||||
/>
|
||||
)}
|
||||
{ !versionedEntries && versions.versions.map(version => (
|
||||
{!versionedEntries && versions.versions.map(version => (
|
||||
<Link
|
||||
title={`Quickshell Documentation (${version.name})`}
|
||||
link={`/docs/${version.name}/guide`}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ const NavComponent: Component<SidebarContent> = props => {
|
|||
if (
|
||||
isLink ||
|
||||
!isInBody ||
|
||||
//@ts-expect-error
|
||||
(isInBody && !navRef.contains(event.target as Node))
|
||||
) {
|
||||
setOpen(false);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ interface Props extends TreeEntry {}
|
|||
|
||||
const { title, link, entries, current } = Astro.props;
|
||||
---
|
||||
|
||||
<NavCollapsible title={title} link={link} current={current ?? false}>
|
||||
{entries?.map(entry => entry.entries ? (
|
||||
<Self {...entry}/>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export interface Props {
|
|||
|
||||
const { mobile } = Astro.props;
|
||||
---
|
||||
|
||||
<aside class=`nav-wrapper${mobile ? "-mobile" : ""} id="nav"`>
|
||||
{ mobile ? (
|
||||
<SidebarWrapper client:load>
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@ export const Table: Component<{
|
|||
if (configTOC) {
|
||||
return (
|
||||
<div class="toc-content">
|
||||
{title && <>
|
||||
<p>{title}</p>
|
||||
<hr/>
|
||||
</>}
|
||||
{title && (
|
||||
<>
|
||||
<p>{title}</p>
|
||||
<hr />
|
||||
</>
|
||||
)}
|
||||
<For each={configTOC}>
|
||||
{heading => (
|
||||
<Heading
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
import { createSignal, type Component } from "solid-js";
|
||||
|
||||
import { Article } from "@icons";
|
||||
import { Table } from "./Table";
|
||||
import type {
|
||||
TOCProps,
|
||||
TypeTOC,
|
||||
ConfigHeading,
|
||||
} from "../types";
|
||||
import { buildHierarchy } from "@config/io/helpers";
|
||||
|
||||
const TableOfContents: Component<TOCProps> = props => {
|
||||
const [open, setOpen] = createSignal<boolean>(false);
|
||||
const [typeProps] = createSignal<TypeTOC | undefined>(
|
||||
props.type
|
||||
);
|
||||
const [configProps] = createSignal<
|
||||
ConfigHeading[] | undefined
|
||||
>(props.config);
|
||||
|
||||
function toggle(e: MouseEvent) {
|
||||
e.preventDefault();
|
||||
setOpen(!open());
|
||||
}
|
||||
|
||||
if (!props.mobile) {
|
||||
return typeProps() ? (
|
||||
<Table typeTOC={typeProps()} />
|
||||
) : (
|
||||
<Table configTOC={buildHierarchy(configProps()!)} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="menu-toggle">
|
||||
<div onclick={e => toggle(e)}>
|
||||
<Article />
|
||||
</div>
|
||||
<div class={`menu-items ${open() ? "shown" : ""}`}>
|
||||
{typeProps() ? (
|
||||
<Table typeTOC={typeProps()} />
|
||||
) : (
|
||||
<Table
|
||||
configTOC={buildHierarchy(configProps()!)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContents;
|
||||
|
|
@ -6,7 +6,7 @@ import {
|
|||
type Component,
|
||||
} from "solid-js";
|
||||
|
||||
import { Article } from "@icons";
|
||||
import { Article, MenuToX } from "@icons";
|
||||
import { Table } from "./Table";
|
||||
import type { TOCProps } from "../types";
|
||||
import { buildHierarchy } from "@config/io/helpers";
|
||||
|
|
@ -27,7 +27,10 @@ const TableOfContents: Component<TOCProps> = props => {
|
|||
return type ? (
|
||||
<Table typeTOC={type} />
|
||||
) : (
|
||||
<Table title={title} configTOC={buildHierarchy(config!)} />
|
||||
<Table
|
||||
title={title}
|
||||
configTOC={buildHierarchy(config!)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +40,7 @@ const TableOfContents: Component<TOCProps> = props => {
|
|||
if (
|
||||
isLink ||
|
||||
!isInBody ||
|
||||
//@ts-expect-error
|
||||
(isInBody && !tocRef.contains(event.target as Node))
|
||||
) {
|
||||
setOpen(false);
|
||||
|
|
@ -92,13 +96,17 @@ const TableOfContents: Component<TOCProps> = props => {
|
|||
id="toc-toggle"
|
||||
>
|
||||
<div onclick={e => toggle(e)}>
|
||||
<Article />
|
||||
<Article class={`toc-icon ${!open() ? "active" : ""}`} />
|
||||
<MenuToX class={`toc-icon ${open() ? "active" : ""}`} />
|
||||
</div>
|
||||
<div class={`toc-mobile ${open() ? "shown" : ""}`}>
|
||||
{type ? (
|
||||
<Table typeTOC={type} />
|
||||
) : (
|
||||
<Table title={title} configTOC={buildHierarchy(config!)} />
|
||||
<Table
|
||||
title={title}
|
||||
configTOC={buildHierarchy(config!)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
---
|
||||
import type {
|
||||
QMLTypeLinkObject,
|
||||
QuickshellFunction,
|
||||
} from "@config/io/types";
|
||||
import type { QMLTypeLinkObject, QuickshellFunction } from "@config/_types";
|
||||
import { getQMLTypeLink } from "@config/io/helpers";
|
||||
import { Tag } from "@icons";
|
||||
import TypeDetails from "./TypeDetails.astro";
|
||||
|
|
@ -15,9 +12,9 @@ export interface Props {
|
|||
const { funcData } = Astro.props;
|
||||
const { version } = Astro.params;
|
||||
---
|
||||
|
||||
<ul class="typedata typefuncs">
|
||||
{
|
||||
funcData.map(item => {
|
||||
{funcData.map((item:QuickshellFunction) => {
|
||||
const functionParams = item.params.length > 0 ? item.params.map((funcparam,index) => `${funcparam.name}${index !== item.params.length -1 ? ", ":""}`) : undefined
|
||||
const retTypeLink = getQMLTypeLink(version!, item.ret as unknown as QMLTypeLinkObject)
|
||||
let genericType:string|undefined;
|
||||
|
|
@ -57,6 +54,5 @@ const { version } = Astro.params;
|
|||
<TypeDetails markdown={item.details} />
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
})}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ import { getQMLTypeLink } from "@config/io/helpers";
|
|||
import type {
|
||||
QMLTypeLinkObject,
|
||||
QuickshellProps,
|
||||
} from "@config/io/types";
|
||||
QuickshellInstance,
|
||||
} from "@config/_types";
|
||||
import { Tag } from "@icons";
|
||||
import TypeTitle from "./TypeTitle.astro";
|
||||
|
||||
|
|
@ -16,56 +17,56 @@ export interface Props {
|
|||
const { props } = Astro.props;
|
||||
const { version } = Astro.params;
|
||||
---
|
||||
|
||||
<ul class="typedata typeprops">
|
||||
{
|
||||
Object.entries(props).map(([name, propData]) => {
|
||||
let typeLink:string;
|
||||
let linkText:string;
|
||||
let genericType:string|undefined;
|
||||
let genericTypeLink:string|undefined;
|
||||
const gadget = propData.type.gadget;
|
||||
if (gadget) {
|
||||
typeLink = "#"
|
||||
linkText = `[${Object.keys(gadget).toString()}]`
|
||||
} else {
|
||||
typeLink = getQMLTypeLink(version!, propData.type)
|
||||
linkText = propData.type.name || propData.type.type
|
||||
}
|
||||
if (propData.type.of) {
|
||||
genericType = propData.type.of.name;
|
||||
genericTypeLink = getQMLTypeLink(version!, propData.type.of)
|
||||
}
|
||||
return (
|
||||
<li id={ name } class="typedata-root typeprop-root">
|
||||
<TypeTitle
|
||||
typekind="prop"
|
||||
typename={name}
|
||||
typelink={typeLink}
|
||||
typelink_text={linkText}
|
||||
typename_generic={genericType}
|
||||
typelink_generic={genericTypeLink}
|
||||
badges={propData.flags}
|
||||
/>
|
||||
{
|
||||
gadget ? (
|
||||
<p class="typedata-params typefunc-params">
|
||||
{
|
||||
Object.keys(gadget).map((key) => {
|
||||
const gadgetData = gadget[key]
|
||||
return (
|
||||
<span class="typedata-param typefunc-param">
|
||||
<Tag client:idle/>
|
||||
{key}:<span><a href={getQMLTypeLink(version!, gadgetData as unknown as QMLTypeLinkObject)}>{gadgetData.name}</a></span>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
}
|
||||
</p>
|
||||
):null
|
||||
}
|
||||
<TypeDetails markdown={propData.details} />
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
{Object.keys(props).map((name) => {
|
||||
const propData:QuickshellInstance = props[name];
|
||||
let typeLink: string;
|
||||
let linkText: string;
|
||||
let genericType: string|undefined;
|
||||
let genericTypeLink: string|undefined;
|
||||
const gadget = propData.type.gadget;
|
||||
if (gadget) {
|
||||
typeLink = "#"
|
||||
linkText = `[${Object.keys(gadget).toString()}]`
|
||||
} else {
|
||||
typeLink = getQMLTypeLink(version!, propData.type)
|
||||
linkText = propData.type.name || propData.type.type
|
||||
}
|
||||
if (propData.type.of) {
|
||||
genericType = propData.type.of.name;
|
||||
genericTypeLink = getQMLTypeLink(version!, propData.type.of)
|
||||
}
|
||||
return (
|
||||
<li id={ name } class="typedata-root typeprop-root">
|
||||
<TypeTitle
|
||||
typekind="prop"
|
||||
typename={ name }
|
||||
typelink={typeLink}
|
||||
typelink_text={linkText}
|
||||
typename_generic={genericType}
|
||||
typelink_generic={genericTypeLink}
|
||||
badges={propData.flags}
|
||||
/>
|
||||
{
|
||||
gadget ? (
|
||||
<p class="typedata-params typefunc-params">
|
||||
{
|
||||
Object.keys(gadget).map((key) => {
|
||||
const gadgetData = gadget[key]
|
||||
return (
|
||||
<span class="typedata-param typefunc-param">
|
||||
<Tag client:idle/>
|
||||
{key}:<span><a href={getQMLTypeLink(version!, gadgetData as unknown as QMLTypeLinkObject)}>{gadgetData.name}</a></span>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
}
|
||||
</p>
|
||||
):null
|
||||
}
|
||||
<TypeDetails markdown={propData.details} />
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import { getQMLTypeLink } from "@config/io/helpers";
|
||||
import type { QuickshellSignal } from "@config/io/types";
|
||||
import type { QuickshellSignal } from "@config/_types";
|
||||
import { Tag } from "@icons";
|
||||
import TypeDetails from "./TypeDetails.astro";
|
||||
import TypeTitle from "./TypeTitle.astro";
|
||||
|
|
@ -12,44 +12,51 @@ export interface Props {
|
|||
const { signals } = Astro.props;
|
||||
const { version } = Astro.params;
|
||||
---
|
||||
|
||||
<ul class="typedata typesignals">
|
||||
{
|
||||
Object.entries(signals).map(([name, signalData]) => {
|
||||
const paramKeys = signalData.params.length > 0 ? signalData.params.map((param,index) => `${param.name}${index !== signalData.params.length -1 ? ", ":""}`) : []
|
||||
let genericType:string|undefined;
|
||||
let genericTypeLink:string|undefined;
|
||||
return (
|
||||
<li id={ name } class="typedata-root typesignal-root">
|
||||
<TypeTitle
|
||||
typekind="signal"
|
||||
typename={name}
|
||||
typelink="/docs/configuration/qml-overview#-signals"
|
||||
typelink_text=""
|
||||
typename_generic={genericType}
|
||||
typelink_generic={genericTypeLink}
|
||||
typedata_params={paramKeys}
|
||||
/>
|
||||
{
|
||||
signalData.params && signalData.params.length > 0 ? (
|
||||
<p class="typedata-params typesignal-params">
|
||||
{
|
||||
signalData.params.map((param, _) => {
|
||||
return (
|
||||
<span class="typedata-param typesignal-param">
|
||||
<Tag client:idle/>
|
||||
{param.name}<span class="type-datatype">: <a
|
||||
href={getQMLTypeLink(version!, param.type)}
|
||||
>{param.type.name}</a></span>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
}
|
||||
</p>
|
||||
) : null
|
||||
}
|
||||
<TypeDetails markdown={signalData.details} />
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
{(Object.entries(signals) as [
|
||||
keyof QuickshellSignal,
|
||||
QuickshellSignal[keyof QuickshellSignal],
|
||||
][]).map(([name, signalData]) => {
|
||||
const paramKeys = signalData.params.length > 0
|
||||
? signalData.params.map((param,index) => `${param.name}${
|
||||
index !== signalData.params.length -1
|
||||
? ", "
|
||||
:""
|
||||
}`): []
|
||||
let genericType:string|undefined;
|
||||
let genericTypeLink:string|undefined;
|
||||
return (
|
||||
<li id={ name.toString() } class="typedata-root typesignal-root">
|
||||
<TypeTitle
|
||||
typekind="signal"
|
||||
typename={ name.toString() }
|
||||
typelink="/docs/configuration/qml-overview#-signals"
|
||||
typelink_text=""
|
||||
typename_generic={genericType}
|
||||
typelink_generic={genericTypeLink}
|
||||
typedata_params={paramKeys}
|
||||
/>
|
||||
{
|
||||
signalData.params && signalData.params.length > 0 ? (
|
||||
<p class="typedata-params typesignal-params">
|
||||
{
|
||||
signalData.params.map((param, _) => {
|
||||
return (
|
||||
<span class="typedata-param typesignal-param">
|
||||
<Tag client:idle/>
|
||||
{param.name}<span class="type-datatype">: <a
|
||||
href={getQMLTypeLink(version!, param.type)}
|
||||
>{param.type.name}</a></span>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
}
|
||||
</p>
|
||||
) : null
|
||||
}
|
||||
<TypeDetails markdown={signalData.details} />
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const { version } = Astro.params;
|
|||
|
||||
const html = markdown ? await processMarkdown(version!, markdown) : null;
|
||||
---
|
||||
|
||||
<section class="typedata-details">
|
||||
{html ? <div class="typedata-detailsdata" set:html={html} /> : <em>No details provided</em>}
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -31,14 +31,17 @@ const iconSelector: { [key: string]: string } = {
|
|||
variant: "fourdiamonds",
|
||||
};
|
||||
---
|
||||
|
||||
<div class={`typedata-title type${typekind}-title`}>
|
||||
<section class={`typedata-name type${typekind}-name`}>
|
||||
{typekind !== "func" && <Icon name={iconSelector[typekind]}/>}
|
||||
<span>{ typename }{ (typekind === "func" || typekind === "signal") ?
|
||||
<span
|
||||
>{typename}
|
||||
{(typekind === "func" || typekind === "signal") ?
|
||||
(<span>(</span><span class="typedata-param">{typedata_params}</span><span>)</span>)
|
||||
:""}
|
||||
</span>
|
||||
{ typekind !== "variant" &&
|
||||
{typekind !== "variant" &&
|
||||
<span class=`type-datatype ${typekind === "signal" && "typesignal-doclink"}`>{typekind !== "signal" &&":"}
|
||||
<a href={typelink}>{ typelink_text }</a>
|
||||
{typename_generic &&
|
||||
|
|
@ -46,12 +49,11 @@ const iconSelector: { [key: string]: string } = {
|
|||
<span class="type-generic"><span class="type-datatype"><</span><a href={typelink_generic}>{typename_generic}</a><span class="type-datatype">></span></span>
|
||||
)
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</span>}
|
||||
</section>
|
||||
<section class="type-badges">
|
||||
{badges && badges.length > 0 ? (
|
||||
badges.map(badgeText => <Badge badgeText={badgeText}/>)
|
||||
badges.map((badgeText:string) => <Badge badgeText={badgeText}/>)
|
||||
) : null}
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import type { QuickshellVariant } from "@config/io/types";
|
||||
import type { QuickshellVariant } from "@config/_types";
|
||||
import TypeDetails from "./TypeDetails.astro";
|
||||
import TypeTitle from "./TypeTitle.astro";
|
||||
|
||||
|
|
@ -9,17 +9,20 @@ export interface Props {
|
|||
|
||||
const { variants } = Astro.props;
|
||||
---
|
||||
|
||||
<ul class="typedata typevariants">
|
||||
{
|
||||
Object.entries(variants).map(([name, variantData]) => {
|
||||
{(Object.entries(variants) as [
|
||||
keyof QuickshellVariant,
|
||||
QuickshellVariant[keyof QuickshellVariant],
|
||||
][]).map(([name, variantData]) => {
|
||||
const paramKeys = variantData.params && variantData.params.length > 0
|
||||
? variantData.params.map(param => param.name)
|
||||
: [];
|
||||
return (
|
||||
<li id={ name } class="typedata-root typevariant-root">
|
||||
<li id={ name.toString() } class="typedata-root typevariant-root">
|
||||
<TypeTitle
|
||||
typekind="variant"
|
||||
typename={name}
|
||||
typename={ name.toString() }
|
||||
typelink=""
|
||||
typelink_text=""
|
||||
/>
|
||||
|
|
@ -36,7 +39,5 @@ const { variants } = Astro.props;
|
|||
<TypeDetails markdown={variantData.details} />
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
})}
|
||||
</ul>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,30 +12,48 @@ interface Props {
|
|||
const { title, description } = Astro.props;
|
||||
---
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<link rel="canonical" href={Astro.url} />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="generator" content={Astro.generator}>
|
||||
<link rel="canonical" href={Astro.url}>
|
||||
<link rel="sitemap" href="/sitemap-index.xml">
|
||||
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="description" content={description}>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
|
||||
<script is:inline>
|
||||
const theme = (() => {
|
||||
if (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||
return "dark";
|
||||
}
|
||||
return "light";
|
||||
})();
|
||||
|
||||
if (theme === "dark") {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta name="og:type" content="website" />
|
||||
<meta name="og:site_name" content="quickshell" />
|
||||
<meta name="og:url" content={Astro.url} />
|
||||
<meta name="og:title" content={title} />
|
||||
<meta name="og:description" content={description} />
|
||||
<meta name="og:type" content="website">
|
||||
<meta name="og:site_name" content="quickshell">
|
||||
<meta name="og:url" content={Astro.url}>
|
||||
<meta name="og:title" content={title}>
|
||||
<meta name="og:description" content={description}>
|
||||
<!-- <meta name="og:image" content={image} /> -->
|
||||
|
||||
<!-- Twitter Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:domain" content="quickshell.outfoxxed.me" />
|
||||
<meta name="twitter:url" content={Astro.url} />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:domain" content="quickshell.outfoxxed.me">
|
||||
<meta name="twitter:url" content={Astro.url}>
|
||||
<meta name="twitter:title" content={title}>
|
||||
<meta name="twitter:description" content={description}>
|
||||
<!-- <meta name="twitter:image" content={image} /> -->
|
||||
|
||||
<Analytics/>
|
||||
<Analytics />
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
|
||||
---
|
||||
|
||||
<script is:inline>
|
||||
function updateTheme() {
|
||||
if (
|
||||
localStorage.theme === "dark" ||
|
||||
(!("theme" in localStorage) &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
}
|
||||
|
||||
// Run on initial load
|
||||
updateTheme();
|
||||
|
||||
// Run on view transitions
|
||||
document.addEventListener("astro:after-swap", updateTheme);
|
||||
</script>
|
||||
9
src/config/_types/codeblock.ts
Normal file
9
src/config/_types/codeblock.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
interface CopyButtonOptions {
|
||||
duration?: number;
|
||||
copyIcon?: string;
|
||||
successIcon?: string;
|
||||
display?: "hover" | "ready";
|
||||
cssVariables?: string;
|
||||
}
|
||||
|
||||
export type { CopyButtonOptions };
|
||||
9
src/config/_types/helper.ts
Normal file
9
src/config/_types/helper.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
interface QMLTypeLinkObject {
|
||||
type: string;
|
||||
module?: string;
|
||||
name?: string;
|
||||
mtype?: string;
|
||||
mname?: string;
|
||||
}
|
||||
|
||||
export type { QMLTypeLinkObject };
|
||||
33
src/config/_types/index.ts
Normal file
33
src/config/_types/index.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import type { QMLTypeLinkObject } from "./helper";
|
||||
import type {
|
||||
ModuleData,
|
||||
QuickshellBase,
|
||||
QuickshellFunction,
|
||||
QuickshellGadget,
|
||||
QuickshellInstance,
|
||||
QuickshellProps,
|
||||
QuickshellSignal,
|
||||
QuickshellVariant,
|
||||
TypeData,
|
||||
VersionData,
|
||||
VersionsData,
|
||||
} from "./module";
|
||||
import type { SearchLists } from "./search";
|
||||
import type { CopyButtonOptions } from "./codeblock";
|
||||
|
||||
export type {
|
||||
QMLTypeLinkObject,
|
||||
QuickshellBase,
|
||||
QuickshellInstance,
|
||||
QuickshellGadget,
|
||||
QuickshellProps,
|
||||
QuickshellFunction,
|
||||
QuickshellSignal,
|
||||
QuickshellVariant,
|
||||
TypeData,
|
||||
ModuleData,
|
||||
VersionData,
|
||||
VersionsData,
|
||||
SearchLists,
|
||||
CopyButtonOptions,
|
||||
};
|
||||
|
|
@ -1,15 +1,3 @@
|
|||
//#FIXME fuseConfig.ts
|
||||
// --
|
||||
|
||||
// generateSearchLists.ts
|
||||
interface SearchLists {
|
||||
slug: string;
|
||||
link: string;
|
||||
summary: string;
|
||||
}
|
||||
// --
|
||||
|
||||
// generateTypeData.ts
|
||||
interface QuickshellBase {
|
||||
type: string;
|
||||
module: string;
|
||||
|
|
@ -53,7 +41,7 @@ interface QuickshellSignal {
|
|||
};
|
||||
}
|
||||
|
||||
export interface QuickshellVariant {
|
||||
interface QuickshellVariant {
|
||||
[key: string]: {
|
||||
name?: string;
|
||||
details: string;
|
||||
|
|
@ -61,7 +49,7 @@ export interface QuickshellVariant {
|
|||
};
|
||||
}
|
||||
|
||||
export interface TypeData {
|
||||
interface TypeData {
|
||||
name: string;
|
||||
description: string;
|
||||
details: string;
|
||||
|
|
@ -72,37 +60,27 @@ export interface TypeData {
|
|||
functions?: QuickshellFunction[];
|
||||
signals?: QuickshellSignal;
|
||||
variants?: QuickshellVariant;
|
||||
subtypes?: QuickshellData[];
|
||||
// FIXME: QuickshellData[]
|
||||
subtypes?: any[];
|
||||
}
|
||||
|
||||
export interface ModuleData {
|
||||
interface ModuleData {
|
||||
name: string;
|
||||
description: string;
|
||||
details: string;
|
||||
types: TypeData[];
|
||||
}
|
||||
|
||||
export interface VersionData {
|
||||
interface VersionData {
|
||||
name: string;
|
||||
changelog?: string;
|
||||
modules: ModuleData[];
|
||||
}
|
||||
|
||||
export interface VersionsData {
|
||||
interface VersionsData {
|
||||
default: string;
|
||||
versions: VersionData[];
|
||||
}
|
||||
// --
|
||||
|
||||
// helpers.ts
|
||||
interface QMLTypeLinkObject {
|
||||
type: string;
|
||||
module?: string;
|
||||
name?: string;
|
||||
mtype?: string;
|
||||
mname?: string;
|
||||
}
|
||||
// --
|
||||
|
||||
export type {
|
||||
QuickshellBase,
|
||||
|
|
@ -116,5 +94,4 @@ export type {
|
|||
ModuleData,
|
||||
VersionData,
|
||||
VersionsData,
|
||||
QMLTypeLinkObject,
|
||||
};
|
||||
7
src/config/_types/search.ts
Normal file
7
src/config/_types/search.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
interface SearchLists {
|
||||
slug: string;
|
||||
link: string;
|
||||
summary: string;
|
||||
}
|
||||
|
||||
export type { SearchLists };
|
||||
|
|
@ -1,36 +1,45 @@
|
|||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import type { VersionsData, ModuleData } from "./types";
|
||||
import type { VersionsData, ModuleData } from "@_types";
|
||||
|
||||
async function readModulesData(basePath: string): Promise<ModuleData[]> {
|
||||
async function readModulesData(
|
||||
basePath: string
|
||||
): Promise<ModuleData[]> {
|
||||
const moduleDirs = await fs.readdir(basePath);
|
||||
|
||||
const modules = await Promise.all(moduleDirs.map(async moduleDir => {
|
||||
const modulePath = path.join(basePath, moduleDir);
|
||||
const modules = await Promise.all(
|
||||
moduleDirs.map(async moduleDir => {
|
||||
const modulePath = path.join(basePath, moduleDir);
|
||||
|
||||
const indexPromise = async () => {
|
||||
const indexPath = path.join(modulePath, "index.json");
|
||||
const indexContent = await fs.readFile(indexPath, "utf8");
|
||||
return JSON.parse(indexContent);
|
||||
};
|
||||
const indexPromise = async () => {
|
||||
const indexPath = path.join(modulePath, "index.json");
|
||||
const indexContent = await fs.readFile(indexPath, "utf8");
|
||||
return JSON.parse(indexContent);
|
||||
};
|
||||
|
||||
const typeNames = (await fs.readdir(modulePath)).filter(name => name !== "index.json");
|
||||
const typePromises = typeNames.map(async fileName => {
|
||||
const typePath = path.join(modulePath, fileName);
|
||||
const fileContent = await fs.readFile(typePath, "utf8");
|
||||
return JSON.parse(fileContent);
|
||||
});
|
||||
const typeNames = (await fs.readdir(modulePath)).filter(
|
||||
name => name !== "index.json"
|
||||
);
|
||||
const typePromises = typeNames.map(async fileName => {
|
||||
const typePath = path.join(modulePath, fileName);
|
||||
const fileContent = await fs.readFile(typePath, "utf8");
|
||||
return JSON.parse(fileContent);
|
||||
});
|
||||
|
||||
const [index, ...types] = await Promise.all([indexPromise(), ...typePromises]);
|
||||
const [index, ...types] = await Promise.all([
|
||||
indexPromise(),
|
||||
...typePromises,
|
||||
]);
|
||||
|
||||
return {
|
||||
name: index.name,
|
||||
description: index.description,
|
||||
details: index.details,
|
||||
types,
|
||||
}
|
||||
}));
|
||||
return {
|
||||
name: index.name,
|
||||
description: index.description,
|
||||
details: index.details,
|
||||
types,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
|
@ -44,19 +53,31 @@ async function readVersionsData(): Promise<VersionsData> {
|
|||
);
|
||||
}
|
||||
|
||||
const resolvedPath = path.join(process.cwd(), versionsPath);
|
||||
console.log(resolvedPath);
|
||||
const content = await fs.readFile(versionsPath, "utf8");
|
||||
const data = JSON.parse(content);
|
||||
|
||||
const versions = await Promise.all(data.versions.map(async (d: { name: string, changelog?: string, types: any }) => ({
|
||||
name: d.name,
|
||||
changelog: d.changelog ? await fs.readFile(d.changelog, "utf8") : undefined,
|
||||
modules: await readModulesData(d.types),
|
||||
})));
|
||||
const versions = await Promise.all(
|
||||
data.versions.map(
|
||||
async (d: {
|
||||
name: string;
|
||||
changelog?: string;
|
||||
types: any;
|
||||
}) => ({
|
||||
name: d.name,
|
||||
changelog: d.changelog
|
||||
? await fs.readFile(d.changelog, "utf8")
|
||||
: undefined,
|
||||
modules: await readModulesData(d.types),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
versions,
|
||||
default: data.default,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let globalVersionsData: Promise<VersionsData>;
|
||||
|
|
@ -71,5 +92,6 @@ export function getVersionsData(): Promise<VersionsData> {
|
|||
|
||||
export async function getModulesData(): Promise<ModuleData[]> {
|
||||
const versions = await getVersionsData();
|
||||
return versions.versions.find(v => v.name === versions.default)!.modules;
|
||||
return versions.versions.find(v => v.name === versions.default)!
|
||||
.modules;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
import { type CollectionEntry, getCollection } from "astro:content";
|
||||
import {
|
||||
type CollectionEntry,
|
||||
getCollection,
|
||||
} from "astro:content";
|
||||
import { getVersionsData } from "@config/io/generateTypeData";
|
||||
|
||||
// load latest version of each page for version
|
||||
async function buildGuideCollection(version: string): Promise<CollectionEntry<'guide'>[]> {
|
||||
async function buildGuideCollection(
|
||||
version: string
|
||||
): Promise<CollectionEntry<"guide">[]> {
|
||||
const { versions } = await getVersionsData();
|
||||
const guidePages = await getCollection("guide");
|
||||
|
||||
const pages: { [key: string]: CollectionEntry<'guide'> } = {};
|
||||
const pages: { [key: string]: CollectionEntry<"guide"> } = {};
|
||||
|
||||
for (const currentVersion of versions.toReversed()) {
|
||||
for (const page of guidePages) {
|
||||
let [guideVersion, id] = page.id.split('/');
|
||||
guideVersion = guideVersion.replaceAll('_', '.');
|
||||
let [guideVersion, id] = page.id.split("/");
|
||||
guideVersion = guideVersion.replaceAll("_", ".");
|
||||
id = id ?? "index";
|
||||
if (guideVersion !== currentVersion.name) continue;
|
||||
|
||||
|
|
@ -24,12 +29,18 @@ async function buildGuideCollection(version: string): Promise<CollectionEntry<'g
|
|||
return Object.values(pages);
|
||||
}
|
||||
|
||||
let guideCollections: { [key: string]: Promise<CollectionEntry<'guide'>[]> } = {};
|
||||
let guideCollections: {
|
||||
[key: string]: Promise<CollectionEntry<"guide">[]>;
|
||||
} = {};
|
||||
|
||||
export async function getGuideCollection(version: string): Promise<CollectionEntry<'guide'>[]> {
|
||||
async function getGuideCollection(
|
||||
version: string
|
||||
): Promise<CollectionEntry<"guide">[]> {
|
||||
if (!(version in guideCollections)) {
|
||||
guideCollections[version] = buildGuideCollection(version);
|
||||
}
|
||||
|
||||
return guideCollections[version];
|
||||
}
|
||||
|
||||
export { getGuideCollection };
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type {
|
|||
ConfigHeading,
|
||||
ConfigTOC,
|
||||
} from "@components/navigation/sidebars/types";
|
||||
import type { QMLTypeLinkObject } from "./types";
|
||||
import type { QMLTypeLinkObject } from "@_types";
|
||||
|
||||
export function buildHierarchy(headings: ConfigHeading[]) {
|
||||
const toc: ConfigTOC[] = [];
|
||||
|
|
@ -30,7 +30,7 @@ export function buildHierarchy(headings: ConfigHeading[]) {
|
|||
let depth = heading.depth - 1;
|
||||
let parent = null;
|
||||
|
||||
while (!parent && depth != 0) {
|
||||
while (!parent && depth !== 0) {
|
||||
parent = parentHeadings.get(depth);
|
||||
depth -= 1;
|
||||
}
|
||||
|
|
@ -96,13 +96,10 @@ export function getQMLTypeLinkObject(unparsed: string) {
|
|||
return hashMap[index]();
|
||||
}
|
||||
|
||||
export function getQMLTypeLink(version: string, {
|
||||
type,
|
||||
module,
|
||||
name,
|
||||
mtype,
|
||||
mname,
|
||||
}: QMLTypeLinkObject) {
|
||||
export function getQMLTypeLink(
|
||||
version: string,
|
||||
{ type, module, name, mtype, mname }: QMLTypeLinkObject
|
||||
) {
|
||||
if (type === "unknown") {
|
||||
return "#unknown";
|
||||
}
|
||||
|
|
@ -116,7 +113,9 @@ export function getQMLTypeLink(version: string, {
|
|||
return localLink;
|
||||
},
|
||||
qt: () => {
|
||||
const isSpecific = mname ? `#${mname}-${mtype === "func" ? "method" : mtype}` : "";
|
||||
const isSpecific = mname
|
||||
? `#${mname}-${mtype === "func" ? "method" : mtype}`
|
||||
: "";
|
||||
const qtLink = `${qtStart}${module!.toLowerCase().replace(".", "-")}-${name!.toLowerCase()}.html${isSpecific}`;
|
||||
return qtLink;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,115 +14,127 @@ import { remarkAlert } from "remark-github-blockquote-alert";
|
|||
import rehypeShiki from "@shikijs/rehype";
|
||||
import sectionize from "@hbsnow/rehype-sectionize";
|
||||
import type { ShikiTransformer } from "shiki";
|
||||
import { h } from "hastscript";
|
||||
|
||||
import {
|
||||
getQMLTypeLinkObject,
|
||||
getQMLTypeLink,
|
||||
getIconForLink,
|
||||
} from "./helpers.ts";
|
||||
import type { CopyButtonOptions } from "@_types";
|
||||
|
||||
let currentVersion = "NOVERSION";
|
||||
|
||||
const remarkParseAtTypes: RemarkPlugin<[]> = () => (root: Md.Root): Md.Root => {
|
||||
visit(root as Unist.Parent, (rawNode: Unist.Node) => {
|
||||
if (
|
||||
rawNode.type === "text" ||
|
||||
(rawNode.type === "code" &&
|
||||
(rawNode as Md.Code).lang === "qml")
|
||||
) {
|
||||
const node = rawNode as Md.Literal;
|
||||
const remarkParseAtTypes: RemarkPlugin<[]> =
|
||||
() =>
|
||||
(root: Md.Root): Md.Root => {
|
||||
visit(root as Unist.Parent, (rawNode: Unist.Node) => {
|
||||
if (
|
||||
rawNode.type === "text" ||
|
||||
(rawNode.type === "code" &&
|
||||
(rawNode as Md.Code).lang === "qml")
|
||||
) {
|
||||
const node = rawNode as Md.Literal;
|
||||
node.value = node.value.replace(
|
||||
/@@(?<path>([A-Z]\w*\.)*([A-Z]\w*))?((?<member>[a-z]\w*)((?<function>\(\))|(?<signal>\(s\)))?)?(?=[$.,;:)\s]|$)/g,
|
||||
(_full, ...args) => {
|
||||
type Capture = {
|
||||
path: string | undefined;
|
||||
member: string | undefined;
|
||||
function: string | undefined;
|
||||
signal: string | undefined;
|
||||
};
|
||||
|
||||
node.value = node.value.replace(
|
||||
/@@(?<path>([A-Z]\w*\.)*([A-Z]\w*))?((?<member>[a-z]\w*)((?<function>\(\))|(?<signal>\(s\)))?)?(?=[$.,;:)\s]|$)/g,
|
||||
(_full, ...args) => {
|
||||
type Capture = {
|
||||
path: string | undefined;
|
||||
member: string | undefined;
|
||||
function: string | undefined;
|
||||
signal: string | undefined;
|
||||
};
|
||||
const groups = args.pop() as Capture;
|
||||
const pathp = (groups.path ?? "")
|
||||
.split(".")
|
||||
.filter(Boolean);
|
||||
let type = pathp.length >= 1 ? pathp.pop() : "";
|
||||
let module = pathp.join("_");
|
||||
|
||||
const groups = args.pop() as Capture;
|
||||
const pathp = (groups.path ?? "").split('.').filter(Boolean);
|
||||
let type = (pathp.length >= 1 ? pathp.pop() : "");
|
||||
let module = pathp.join('_');
|
||||
if (module) {
|
||||
const isQs = module.startsWith("Quickshell");
|
||||
module = `99M${isQs ? "QS" : "QT_qml"}_${module}`;
|
||||
} else module = ""; // WARNING: rehype parser can't currently handle intra-module links
|
||||
|
||||
if (module) {
|
||||
const isQs = module.startsWith("Quickshell");
|
||||
module = `99M${isQs ? "QS" : "QT_qml"}_${module}`;
|
||||
} else module = ""; // WARNING: rehype parser can't currently handle intra-module links
|
||||
|
||||
type = type ? `99N${type}` : "";
|
||||
groups.member = groups.member
|
||||
? `99V${groups.member}`
|
||||
: "";
|
||||
const typep = groups.member
|
||||
? `99T${groups.function ? "func" : groups.signal ? "signal" : "prop"}`
|
||||
: "";
|
||||
return `TYPE${module}${type}${groups.member}${typep}99TYPE`;
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
return root;
|
||||
};
|
||||
|
||||
const rehypeRewriteTypelinks: RehypePlugin<[]> = () => (root: Html.Root): Html.Root => {
|
||||
visit(
|
||||
root as Unist.Parent,
|
||||
"text",
|
||||
(node: Html.Text, index: number, parent: Html.Parent) => {
|
||||
let changed = false;
|
||||
|
||||
node.value = node.value.replace(
|
||||
/TYPE99(\w+.)99TYPE/g,
|
||||
(_full: string, match: string) => {
|
||||
changed = true;
|
||||
|
||||
const linkObject = getQMLTypeLinkObject(match);
|
||||
const link = getQMLTypeLink(currentVersion, linkObject);
|
||||
const icon =
|
||||
linkObject.mtype && linkObject.mtype !== "func"
|
||||
? getIconForLink(linkObject.mtype, false)
|
||||
: null;
|
||||
const hasParens =
|
||||
linkObject.mtype === "func" ||
|
||||
linkObject.mtype === "signal";
|
||||
const hasDot = linkObject.name && linkObject.mname;
|
||||
|
||||
return `<a class="type${linkObject.mtype}-link typedata-link" href=${link}>${icon ?? ""}${linkObject.name ?? ""}${hasDot ? "." : ""}${linkObject.mname ?? ""}${hasParens ? "()" : ""}</a>`;
|
||||
}
|
||||
);
|
||||
|
||||
if (changed) {
|
||||
const fragment = fromHtml(node.value, {
|
||||
fragment: true,
|
||||
});
|
||||
parent.children.splice(index, 1, ...fragment.children);
|
||||
return SKIP;
|
||||
type = type ? `99N${type}` : "";
|
||||
groups.member = groups.member
|
||||
? `99V${groups.member}`
|
||||
: "";
|
||||
const typep = groups.member
|
||||
? `99T${groups.function ? "func" : groups.signal ? "signal" : "prop"}`
|
||||
: "";
|
||||
return `TYPE${module}${type}${groups.member}${typep}99TYPE`;
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
return root;
|
||||
};
|
||||
|
||||
return CONTINUE;
|
||||
}
|
||||
);
|
||||
const rehypeRewriteTypelinks: RehypePlugin<[]> =
|
||||
() =>
|
||||
(root: Html.Root): Html.Root => {
|
||||
visit(
|
||||
root as Unist.Parent,
|
||||
"text",
|
||||
(node: Html.Text, index: number, parent: Html.Parent) => {
|
||||
let changed = false;
|
||||
|
||||
return root;
|
||||
};
|
||||
node.value = node.value.replace(
|
||||
/TYPE99(\w+.)99TYPE/g,
|
||||
(_full: string, match: string) => {
|
||||
changed = true;
|
||||
|
||||
const rehypeRewriteVersionedDoclinks: RehypePlugin<[]> = () => (root: Html.Root): Html.Root => {
|
||||
visit(
|
||||
root as Unist.Parent,
|
||||
"element",
|
||||
({ tagName, properties }: Html.Element) => {
|
||||
if (tagName !== "a") return CONTINUE;
|
||||
if (!(properties.href as string ?? "").startsWith("@docs")) return CONTINUE;
|
||||
properties.href = `/docs/${currentVersion}/${(properties.href as string).slice(6)}`;
|
||||
return CONTINUE;
|
||||
}
|
||||
);
|
||||
const linkObject = getQMLTypeLinkObject(match);
|
||||
const link = getQMLTypeLink(
|
||||
currentVersion,
|
||||
linkObject
|
||||
);
|
||||
const icon =
|
||||
linkObject.mtype && linkObject.mtype !== "func"
|
||||
? getIconForLink(linkObject.mtype, false)
|
||||
: null;
|
||||
const hasParens =
|
||||
linkObject.mtype === "func" ||
|
||||
linkObject.mtype === "signal";
|
||||
const hasDot = linkObject.name && linkObject.mname;
|
||||
|
||||
return root;
|
||||
};
|
||||
return `<a class="type${linkObject.mtype}-link typedata-link" href=${link}>${icon ?? ""}${linkObject.name ?? ""}${hasDot ? "." : ""}${linkObject.mname ?? ""}${hasParens ? "()" : ""}</a>`;
|
||||
}
|
||||
);
|
||||
|
||||
if (changed) {
|
||||
const fragment = fromHtml(node.value, {
|
||||
fragment: true,
|
||||
});
|
||||
parent.children.splice(index, 1, ...fragment.children);
|
||||
return SKIP;
|
||||
}
|
||||
}
|
||||
);
|
||||
return root;
|
||||
};
|
||||
|
||||
const rehypeRewriteVersionedDoclinks: RehypePlugin<[]> =
|
||||
() =>
|
||||
(root: Html.Root): Html.Root => {
|
||||
visit(
|
||||
root as Unist.Parent,
|
||||
"element",
|
||||
({ tagName, properties }: Html.Element) => {
|
||||
if (tagName !== "a") return CONTINUE;
|
||||
if (
|
||||
!((properties.href as string) ?? "").startsWith("@docs")
|
||||
)
|
||||
return CONTINUE;
|
||||
properties.href = `/docs/${currentVersion}/${(properties.href as string).slice(6)}`;
|
||||
return CONTINUE;
|
||||
}
|
||||
);
|
||||
|
||||
return root;
|
||||
};
|
||||
|
||||
const shikiRewriteTypelinks: ShikiTransformer = {
|
||||
name: "rewrite-typelinks",
|
||||
|
|
@ -141,7 +153,69 @@ const shikiRewriteTypelinks: ShikiTransformer = {
|
|||
},
|
||||
};
|
||||
|
||||
export const markdownConfig: AstroMarkdownOptions = {
|
||||
const shikiCopyButton: ShikiTransformer = {
|
||||
name: "copy-button",
|
||||
pre(node) {
|
||||
const options: CopyButtonOptions = {
|
||||
duration: 3000,
|
||||
};
|
||||
const button = h(
|
||||
"button",
|
||||
{
|
||||
class: "copy-button",
|
||||
role: "button",
|
||||
"aria-label": "Copy to clipboard",
|
||||
"alia-live": "polite",
|
||||
"data-code": this.source,
|
||||
onclick: `
|
||||
navigator.clipboard.writeText(this.dataset.code);
|
||||
this.classList.add('copied');
|
||||
this.setAttribute('aria-pressed', 'true');
|
||||
setTimeout(() => { this.classList.remove('copied'); this.setAttribute('aria-pressed', 'false');}, ${options.duration})
|
||||
`,
|
||||
},
|
||||
[
|
||||
h(
|
||||
"svg",
|
||||
{
|
||||
class: "copy-icon",
|
||||
role: "icon",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
width: "1em",
|
||||
height: "1em",
|
||||
viewBox: "0 0 256 256",
|
||||
},
|
||||
[
|
||||
h("path", {
|
||||
fill: "currentColor",
|
||||
d: "M200 32h-36.26a47.92 47.92 0 0 0-71.48 0H56a16 16 0 0 0-16 16v168a16 16 0 0 0 16 16h144a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16m-72 0a32 32 0 0 1 32 32H96a32 32 0 0 1 32-32m72 184H56V48h26.75A47.9 47.9 0 0 0 80 64v8a8 8 0 0 0 8 8h80a8 8 0 0 0 8-8v-8a47.9 47.9 0 0 0-2.75-16H200Z",
|
||||
}),
|
||||
]
|
||||
),
|
||||
h(
|
||||
"svg",
|
||||
{
|
||||
class: "check-icon",
|
||||
role: "icon",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
width: "1em",
|
||||
height: "1em",
|
||||
viewBox: "0 0 256 256",
|
||||
},
|
||||
[
|
||||
h("path", {
|
||||
fill: "currentColor",
|
||||
d: "M229.66 77.66l-128 128a8 8 0 0 1-11.32 0l-56-56a8 8 0 0 1 11.32-11.32L96 188.69L218.34 66.34a8 8 0 0 1 11.32 11.32Z",
|
||||
}),
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
node.children.splice(0, 0, button);
|
||||
},
|
||||
};
|
||||
|
||||
const markdownConfig: AstroMarkdownOptions = {
|
||||
syntaxHighlight: false,
|
||||
remarkPlugins: [
|
||||
remarkParseAtTypes,
|
||||
|
|
@ -168,7 +242,7 @@ export const markdownConfig: AstroMarkdownOptions = {
|
|||
},
|
||||
defaultColor: false,
|
||||
wrap: true,
|
||||
transformers: [shikiRewriteTypelinks],
|
||||
transformers: [shikiRewriteTypelinks, shikiCopyButton],
|
||||
},
|
||||
],
|
||||
// FIXME: incompatible types between unified/Plugin and Astro/RehypePlugin
|
||||
|
|
@ -185,18 +259,23 @@ let globalMarkdownProcessor: Promise<MarkdownProcessor>;
|
|||
|
||||
async function getMarkdownProcessor(): Promise<MarkdownProcessor> {
|
||||
if (!globalMarkdownProcessor) {
|
||||
globalMarkdownProcessor = createMarkdownProcessor(markdownConfig);
|
||||
globalMarkdownProcessor =
|
||||
createMarkdownProcessor(markdownConfig);
|
||||
}
|
||||
|
||||
return globalMarkdownProcessor;
|
||||
}
|
||||
|
||||
export async function processMarkdown(
|
||||
async function processMarkdown(
|
||||
version: string,
|
||||
markdown: string,
|
||||
markdown: string
|
||||
): Promise<string> {
|
||||
currentVersion = version;
|
||||
const r = (await (await getMarkdownProcessor()).render(markdown)).code;
|
||||
const r = (
|
||||
await (await getMarkdownProcessor()).render(markdown)
|
||||
).code;
|
||||
currentVersion = "NOVERSION";
|
||||
return r;
|
||||
}
|
||||
|
||||
export { markdownConfig, processMarkdown };
|
||||
|
|
|
|||
69
src/config/styling/animations_helper.ts
Normal file
69
src/config/styling/animations_helper.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
export function initAnimations() {
|
||||
const observerOptions = {
|
||||
root: null,
|
||||
rootMargin: "0px",
|
||||
threshold: 0.1,
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add("visible");
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
},
|
||||
observerOptions
|
||||
);
|
||||
|
||||
const animatedElements = document.querySelectorAll(
|
||||
".animate-fade-up, .stagger-parent"
|
||||
);
|
||||
animatedElements.forEach(el => observer.observe(el));
|
||||
}
|
||||
|
||||
export function initTOCHighlighting() {
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
const heading = entry.target.querySelector(
|
||||
"h1, h2, h3, h4, h5, h6"
|
||||
);
|
||||
if (heading) {
|
||||
const id = heading.id;
|
||||
const desktopElement = document.querySelector(
|
||||
`.toc-wrapper li a[href="#${id}"]`
|
||||
);
|
||||
const mobileElement = document.querySelector(
|
||||
`.toc-wrapper-mobile li a[href="#${id}"]`
|
||||
);
|
||||
|
||||
if (entry.isIntersecting) {
|
||||
desktopElement?.parentElement?.classList.add("active");
|
||||
mobileElement?.parentElement?.classList.add("active");
|
||||
} else {
|
||||
desktopElement?.parentElement?.classList.remove(
|
||||
"active"
|
||||
);
|
||||
mobileElement?.parentElement?.classList.remove(
|
||||
"active"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document
|
||||
.querySelectorAll("section[data-heading-rank]")
|
||||
.forEach(section => {
|
||||
observer.observe(section);
|
||||
});
|
||||
}
|
||||
|
||||
// auto-init on DOMContentLoaded
|
||||
if (typeof document !== "undefined") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
initAnimations();
|
||||
initTOCHighlighting();
|
||||
});
|
||||
}
|
||||
260
src/config/styling/marquee.ts
Normal file
260
src/config/styling/marquee.ts
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const container = document.querySelector(
|
||||
".marquee"
|
||||
) as HTMLDivElement;
|
||||
const scroller = document.querySelector(
|
||||
".marquee-content"
|
||||
) as HTMLDivElement;
|
||||
const btnLeft = document.getElementById("marquee-scroll-left");
|
||||
const btnRight = document.getElementById(
|
||||
"marquee-scroll-right"
|
||||
);
|
||||
|
||||
if (!container || !scroller) return;
|
||||
|
||||
const bufferSize = 2;
|
||||
let items = Array.from(
|
||||
scroller.querySelectorAll(".marquee-item")
|
||||
) as HTMLDivElement[];
|
||||
const originalCount = items.length;
|
||||
if (originalCount === 0) return;
|
||||
|
||||
let itemWidth = 0;
|
||||
let sequenceWidth = 0;
|
||||
let targetScrollX = 0;
|
||||
let currentScrollX = 0;
|
||||
let isAnimating = false;
|
||||
let isDown = false;
|
||||
let lastTouchX = 0;
|
||||
let touchVelocity = 0;
|
||||
let lastTouchTime = 0;
|
||||
const smoothFactor = 0.1;
|
||||
const snapThreshold = 0.1;
|
||||
|
||||
// setup clones
|
||||
const setupClones = () => {
|
||||
// remove existing clones
|
||||
scroller.querySelectorAll(".clone").forEach(c => c.remove());
|
||||
|
||||
const originals = Array.from(
|
||||
scroller.querySelectorAll(".marquee-item")
|
||||
) as HTMLDivElement[];
|
||||
|
||||
// add clones after
|
||||
for (let i = 0; i < bufferSize; i++) {
|
||||
originals.forEach(item => {
|
||||
const clone = item.cloneNode(true) as HTMLDivElement;
|
||||
clone.classList.add("clone");
|
||||
scroller.appendChild(clone);
|
||||
});
|
||||
}
|
||||
|
||||
// add clones before
|
||||
const beforeContainer = document.createDocumentFragment();
|
||||
for (let i = 0; i < bufferSize; i++) {
|
||||
originals.forEach(item => {
|
||||
const clone = item.cloneNode(true) as HTMLDivElement;
|
||||
clone.classList.add("clone");
|
||||
beforeContainer.appendChild(clone);
|
||||
});
|
||||
}
|
||||
scroller.insertBefore(beforeContainer, scroller.firstChild);
|
||||
|
||||
items = Array.from(
|
||||
scroller.querySelectorAll(".marquee-item")
|
||||
) as HTMLDivElement[];
|
||||
};
|
||||
|
||||
const updateDimensions = () => {
|
||||
itemWidth = container.clientWidth;
|
||||
if (itemWidth === 0) return;
|
||||
|
||||
sequenceWidth = originalCount * itemWidth;
|
||||
|
||||
// standardize width
|
||||
scroller.style.width = `${items.length * itemWidth}px`;
|
||||
items.forEach(item => {
|
||||
item.style.width = `${itemWidth}px`;
|
||||
item.style.flex = `0 0 ${itemWidth}px`;
|
||||
item.style.maxWidth = `${itemWidth}px`;
|
||||
});
|
||||
|
||||
targetScrollX =
|
||||
bufferSize * sequenceWidth +
|
||||
(targetScrollX % sequenceWidth);
|
||||
currentScrollX = targetScrollX;
|
||||
scroller.style.transform = `translateX(-${currentScrollX}px)`;
|
||||
};
|
||||
|
||||
const lerp = (start: number, end: number, factor: number) =>
|
||||
start + (end - start) * factor;
|
||||
|
||||
const animate = () => {
|
||||
if (!isDown && Math.abs(touchVelocity) < 0.1) {
|
||||
// snap to nearest item if not interacting and close to one
|
||||
const nearestItemScroll =
|
||||
Math.round(targetScrollX / itemWidth) * itemWidth;
|
||||
if (
|
||||
Math.abs(targetScrollX - nearestItemScroll) <
|
||||
itemWidth * 0.5
|
||||
) {
|
||||
targetScrollX = lerp(
|
||||
targetScrollX,
|
||||
nearestItemScroll,
|
||||
0.1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
currentScrollX = lerp(
|
||||
currentScrollX,
|
||||
targetScrollX,
|
||||
smoothFactor
|
||||
);
|
||||
|
||||
// boundary reset
|
||||
if (currentScrollX > (bufferSize + 1) * sequenceWidth) {
|
||||
currentScrollX -= sequenceWidth;
|
||||
targetScrollX -= sequenceWidth;
|
||||
} else if (
|
||||
currentScrollX <
|
||||
(bufferSize - 1) * sequenceWidth
|
||||
) {
|
||||
currentScrollX += sequenceWidth;
|
||||
targetScrollX += sequenceWidth;
|
||||
}
|
||||
|
||||
scroller.style.transform = `translateX(-${currentScrollX}px)`;
|
||||
|
||||
// fade in-out and scale items based on distance from center
|
||||
items.forEach((item, index) => {
|
||||
const itemCenter = index * itemWidth;
|
||||
const distance = Math.abs(currentScrollX - itemCenter);
|
||||
const progress = Math.min(distance / itemWidth, 1); // 0 at center, 1 at edge
|
||||
|
||||
const opacity = 1 - progress;
|
||||
const scale = 1 - progress * 0.1; // scale down as it leaves
|
||||
const yOffset = progress * 20; // slide down as it leaves
|
||||
|
||||
item.style.opacity = opacity.toString();
|
||||
// NOTE: apply transform to the video container specifically
|
||||
// to keep layout stable
|
||||
const content = item.querySelector(
|
||||
".marquee-item-content"
|
||||
) as HTMLElement;
|
||||
if (content) {
|
||||
content.style.transform = `scale(${scale}) translateY(${yOffset}px)`;
|
||||
}
|
||||
});
|
||||
|
||||
const diff = Math.abs(targetScrollX - currentScrollX);
|
||||
const interaction = isDown || Math.abs(touchVelocity) > 0.1;
|
||||
|
||||
if (diff > snapThreshold || interaction) {
|
||||
requestAnimationFrame(animate);
|
||||
} else {
|
||||
isAnimating = false;
|
||||
currentScrollX = targetScrollX;
|
||||
scroller.style.transform = `translateX(-${currentScrollX}px)`;
|
||||
}
|
||||
};
|
||||
|
||||
const startAnimation = () => {
|
||||
if (!isAnimating) {
|
||||
isAnimating = true;
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
};
|
||||
|
||||
// video handling
|
||||
const videos = scroller.querySelectorAll("video");
|
||||
const observerOptions = {
|
||||
root: container,
|
||||
threshold: 0.5,
|
||||
};
|
||||
|
||||
const videoObserver = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
const video = entry.target as HTMLVideoElement;
|
||||
if (entry.isIntersecting) {
|
||||
video.play().catch(() => {}); // Handle potential autoplay blocks
|
||||
} else {
|
||||
video.pause();
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
videos.forEach(v => {
|
||||
videoObserver.observe(v);
|
||||
v.addEventListener("ended", () => {
|
||||
targetScrollX += itemWidth;
|
||||
startAnimation();
|
||||
});
|
||||
});
|
||||
|
||||
// events
|
||||
btnLeft?.addEventListener("click", () => {
|
||||
targetScrollX -= itemWidth;
|
||||
startAnimation();
|
||||
});
|
||||
|
||||
btnRight?.addEventListener("click", () => {
|
||||
targetScrollX += itemWidth;
|
||||
startAnimation();
|
||||
});
|
||||
|
||||
container.addEventListener(
|
||||
"wheel",
|
||||
e => {
|
||||
e.preventDefault();
|
||||
targetScrollX += e.deltaY;
|
||||
startAnimation();
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
container.addEventListener("touchstart", e => {
|
||||
isDown = true;
|
||||
lastTouchX = e.touches[0].clientX;
|
||||
lastTouchTime = Date.now();
|
||||
touchVelocity = 0;
|
||||
});
|
||||
|
||||
container.addEventListener("touchmove", e => {
|
||||
if (!isDown) return;
|
||||
const currentTouchX = e.touches[0].clientX;
|
||||
const deltaX = lastTouchX - currentTouchX;
|
||||
targetScrollX += deltaX * 1.5;
|
||||
|
||||
const now = Date.now();
|
||||
const dt = now - lastTouchTime;
|
||||
if (dt > 0) touchVelocity = deltaX / dt;
|
||||
|
||||
lastTouchX = currentTouchX;
|
||||
lastTouchTime = now;
|
||||
startAnimation();
|
||||
});
|
||||
|
||||
container.addEventListener("touchend", () => {
|
||||
isDown = false;
|
||||
targetScrollX += touchVelocity * 100; // Momentum
|
||||
touchVelocity = 0;
|
||||
startAnimation();
|
||||
});
|
||||
|
||||
window.addEventListener("resize", updateDimensions);
|
||||
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (document.hidden) {
|
||||
videos.forEach(v => v.pause());
|
||||
}
|
||||
});
|
||||
|
||||
// init
|
||||
setupClones();
|
||||
setTimeout(() => {
|
||||
updateDimensions();
|
||||
container.classList.add("initialized");
|
||||
startAnimation();
|
||||
}, 50);
|
||||
});
|
||||
89
src/config/styling/theme_persistence.ts
Normal file
89
src/config/styling/theme_persistence.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
interface ThemeProps {
|
||||
theme: "light" | "dark";
|
||||
system: "light" | "dark";
|
||||
}
|
||||
|
||||
export const getCurrentTheme = (): ThemeProps => {
|
||||
const isDarkSystem = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)"
|
||||
).matches;
|
||||
const systemTheme = isDarkSystem ? "dark" : "light";
|
||||
|
||||
if (typeof localStorage !== "undefined") {
|
||||
if (localStorage.theme === "dark") {
|
||||
return { theme: "dark", system: systemTheme };
|
||||
}
|
||||
if (localStorage.theme === "light") {
|
||||
return { theme: "light", system: systemTheme };
|
||||
}
|
||||
}
|
||||
|
||||
return { theme: systemTheme, system: systemTheme };
|
||||
};
|
||||
|
||||
export const updateTheme = (transition = true) => {
|
||||
const theme = getCurrentTheme();
|
||||
const toggle = document.getElementById(
|
||||
"theme-manual-toggle"
|
||||
) as HTMLInputElement;
|
||||
|
||||
if (transition) {
|
||||
document.documentElement.classList.add("changing-theme");
|
||||
document.documentElement.style.setProperty(
|
||||
"--theme-transition",
|
||||
"0.3s var(--ease-in-out)"
|
||||
);
|
||||
} else {
|
||||
document.documentElement.style.removeProperty(
|
||||
"--theme-transition"
|
||||
);
|
||||
}
|
||||
|
||||
if (theme.theme === "dark") {
|
||||
document.documentElement.classList.add("dark");
|
||||
if (toggle) toggle.checked = true;
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
if (toggle) toggle.checked = false;
|
||||
}
|
||||
|
||||
if (transition) {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
document.documentElement.classList.remove(
|
||||
"changing-theme"
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const initTheme = () => {
|
||||
const toggle = document.getElementById(
|
||||
"theme-manual-toggle"
|
||||
) as HTMLInputElement;
|
||||
|
||||
if (toggle) {
|
||||
toggle.addEventListener("change", () => {
|
||||
localStorage.theme = toggle.checked ? "dark" : "light";
|
||||
updateTheme();
|
||||
});
|
||||
}
|
||||
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", () => updateTheme());
|
||||
window.addEventListener("storage", () => updateTheme());
|
||||
|
||||
// initial sync
|
||||
updateTheme(false);
|
||||
};
|
||||
|
||||
// auto-init on client
|
||||
if (typeof document !== "undefined") {
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", initTheme);
|
||||
} else {
|
||||
initTheme();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,11 @@ import { defineCollection, z } from "astro:content";
|
|||
import { glob } from "astro/loaders";
|
||||
|
||||
const guide = defineCollection({
|
||||
loader: glob({ pattern: "**/*.md", base: "src/guide" }),
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
loader: glob({ pattern: "**/*.{md,mdx}", base: "src/guide" }),
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
index: z.number(),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { guide };
|
||||
|
|
|
|||
46
src/env.d.ts
vendored
46
src/env.d.ts
vendored
|
|
@ -1,2 +1,46 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro-icon/empty-types" />
|
||||
|
||||
declare module "astro-icon/components" {
|
||||
export const Icon: typeof import("astro-icon/components").Icon;
|
||||
}
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VERSION_FILE_PATH: string;
|
||||
readonly BASE_URL: string;
|
||||
readonly PRODUCTION: string | undefined;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
// fix astro-breadcrumbs
|
||||
declare module "astro-breadcrumbs" {
|
||||
interface BreadcrumbsProps {
|
||||
indexText?: string;
|
||||
mainText?: string;
|
||||
crumbs: {
|
||||
text: string;
|
||||
href: string;
|
||||
}[];
|
||||
linkTextFormat?: string;
|
||||
truncated?: boolean;
|
||||
case?:
|
||||
| "lower"
|
||||
| "upper"
|
||||
| "capitalize"
|
||||
| "title"
|
||||
| "original";
|
||||
// Add other props you use here
|
||||
}
|
||||
export const Breadcrumbs: (props: BreadcrumbsProps) => any;
|
||||
export default Breadcrumbs;
|
||||
}
|
||||
|
||||
// fix for "?raw" imports
|
||||
declare module "*?raw" {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,11 +75,11 @@ To start with, let's make a clock. To get the time, we'll use the `date` command
|
|||
> [!note/Note]
|
||||
> Quickshell can do more than just run processes. Read until the end for more information.
|
||||
|
||||
We can use a [Process](@docs/types/quickshell.io/process) object to run commands
|
||||
We can use a [Process](@docs/types/Quickshell.Io/Process) object to run commands
|
||||
and a @@Quickshell.Io.StdioCollector to read their output.
|
||||
|
||||
We'll listen to the @@Quickshell.Io.StdioCollector.streamFinished(s) signal with
|
||||
a [signal handler](@docs/guide/qml-language/#signal-handlers)
|
||||
a [signal handler](@docs/guide/qml-language#signal-handlers)
|
||||
to update the text on the clock.
|
||||
|
||||
> [!note/Note]
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ Name {
|
|||
|
||||
Every object can contain [properties](#properties), [functions](#functions),
|
||||
and [signals](#signals). You can find out what properties are available for a type
|
||||
by looking it up in the [Type Reference](@docs/types/).
|
||||
by looking it up in the [Type Reference](@docs/types).
|
||||
|
||||
#### Properties
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
title: "QML Language"
|
||||
index: 10
|
||||
---
|
||||
import Collapsible from "@components/Collapsible.astro";
|
||||
|
||||
Quickshell is configured using the Qt Modeling Language, or QML.
|
||||
This page explains what you need to know about QML to start using Quickshell.
|
||||
|
|
@ -186,7 +187,7 @@ Name {
|
|||
|
||||
Every object can contain [properties](#properties), [functions](#functions),
|
||||
and [signals](#signals). You can find out what properties are available for a type
|
||||
by looking it up in the [Type Reference](@docs/types/).
|
||||
by looking it up in the [Type Reference](@docs/types).
|
||||
|
||||
#### Properties
|
||||
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
//import Header from "@components/Header.astro";
|
||||
import Head from "@config/Head.astro";
|
||||
import PreTheme from "@config/PreTheme.astro";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
|
|
@ -14,10 +13,20 @@ const { title, description } = Astro.props;
|
|||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<Head description={description} title={title} />
|
||||
<PreTheme />
|
||||
</head>
|
||||
<body class="baselayout">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="theme-manual-toggle"
|
||||
class="theme-toggle-input"
|
||||
style="display: none;"
|
||||
aria-label="Toggle theme (light/dark)"
|
||||
>
|
||||
<!--<Header />-->
|
||||
<slot />
|
||||
<script>
|
||||
import "@config/styling/animations_helper.ts";
|
||||
import "@config/styling/theme_persistence.ts";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -2,29 +2,29 @@
|
|||
import { Breadcrumbs } from "astro-breadcrumbs";
|
||||
import "astro-breadcrumbs/breadcrumbs.css";
|
||||
|
||||
import CreateCopyButtons from "@components/hooks/CreateCopyButtons.astro";
|
||||
import PreTheme from "@config/PreTheme.astro";
|
||||
import Header from "@components/Header.astro";
|
||||
import Head from "@config/Head.astro";
|
||||
import Nav from "@components/navigation/sidebars/nav/index.astro";
|
||||
import type { ConfigHeading } from "@src/components/navigation/sidebars/types";
|
||||
import Footer from "@src/components/Footer.astro";
|
||||
import type { TypeData } from "@config/io/types";
|
||||
import type { TypeData } from "@config/_types";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
headings?: ConfigHeading[];
|
||||
type?: TypeData
|
||||
type?: TypeData;
|
||||
}
|
||||
|
||||
const { title, description, headings, type } = Astro.props;
|
||||
let url = Astro.url.pathname.split("/").filter(s => s !== "");
|
||||
let url = Astro.url.pathname.split("/").filter((s: string) => s !== "");
|
||||
|
||||
const breadcrumbs = [{
|
||||
text: "custom",
|
||||
href: "/",
|
||||
}];
|
||||
const breadcrumbs = [
|
||||
{
|
||||
text: "custom",
|
||||
href: "/",
|
||||
},
|
||||
];
|
||||
|
||||
let linkPath = "";
|
||||
if (url[0] === "docs") {
|
||||
|
|
@ -49,16 +49,27 @@ for (const segment of url) {
|
|||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<Head description={description} title={title} />
|
||||
<PreTheme />
|
||||
<CreateCopyButtons />
|
||||
</head>
|
||||
<body class="docslayout">
|
||||
<Header title={title} headings={headings} type={type}/>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="theme-manual-toggle"
|
||||
class="theme-toggle-input"
|
||||
aria-label="Toggle theme (light/dark)"
|
||||
style="display: none;"
|
||||
>
|
||||
<Header title={title} headings={headings} type={type} />
|
||||
<div class="docslayout-root">
|
||||
<Nav mobile={false}/>
|
||||
<Nav mobile={false} />
|
||||
<div class="docslayout-inner" data-pagefind-body>
|
||||
<Breadcrumbs crumbs={breadcrumbs} linkTextFormat="sentence" truncated={true} data-pagefind-ignore>
|
||||
<Breadcrumbs
|
||||
crumbs={breadcrumbs}
|
||||
linkTextFormat="sentence"
|
||||
truncated={true}
|
||||
data-pagefind-ignore
|
||||
>
|
||||
<svg
|
||||
<!-- @ts-expect-error -->
|
||||
slot="index"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
|
|
@ -69,25 +80,61 @@ for (const segment of url) {
|
|||
<path
|
||||
fill="currentColor"
|
||||
d="m219.31 108.68l-80-80a16 16 0 0 0-22.62 0l-80 80A15.87 15.87 0 0 0 32 120v96a8 8 0 0 0 8 8h64a8 8 0 0 0 8-8v-56h32v56a8 8 0 0 0 8 8h64a8 8 0 0 0 8-8v-96a15.87 15.87 0 0 0-4.69-11.32M208 208h-48v-56a8 8 0 0 0-8-8h-48a8 8 0 0 0-8 8v56H48v-88l80-80l80 80Z"
|
||||
></path></svg
|
||||
>
|
||||
></path>
|
||||
</svg>
|
||||
<svg
|
||||
<!-- @ts-expect-error -->
|
||||
slot="separator"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 256 256"
|
||||
><path
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m181.66 133.66l-80 80a8 8 0 0 1-11.32-11.32L164.69 128L90.34 53.66a8 8 0 0 1 11.32-11.32l80 80a8 8 0 0 1 0 11.32"
|
||||
></path></svg
|
||||
>
|
||||
></path>
|
||||
</svg>
|
||||
</Breadcrumbs>
|
||||
<slot/>
|
||||
<slot />
|
||||
</div>
|
||||
<slot name="alongside-content"/>
|
||||
<slot name="alongside-content" />
|
||||
</div>
|
||||
<Footer/>
|
||||
<Footer />
|
||||
<script>
|
||||
import "@config/styling/animations_helper.ts";
|
||||
import "@config/styling/theme_persistence.ts";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script>
|
||||
// FIXME: need to make this work properly, or fold into the markdown processor
|
||||
let headings = document.getElementsByClassName("heading");
|
||||
if (headings.length > 0) {
|
||||
//@ts-expect-error
|
||||
for (const heading of headings) {
|
||||
let button = heading.querySelector("h2");
|
||||
if (button) {
|
||||
button.onclick = () => {
|
||||
let link = window.location.href.split("#")[0];
|
||||
link += `#${button.textContent?.trimEnd().replaceAll(" ", "-").toLowerCase()}`;
|
||||
window.location.href = link;
|
||||
navigator.clipboard.writeText(link);
|
||||
heading.classList.toggle("copied");
|
||||
setTimeout(() => heading.classList.remove("copied"), 1000);
|
||||
};
|
||||
}
|
||||
let spanButton = heading.querySelector("span");
|
||||
if (spanButton) {
|
||||
spanButton.onclick = () => {
|
||||
let link = window.location.href.split("#")[0];
|
||||
link += `#${spanButton.textContent?.trim().replaceAll(" ", "-").toLowerCase()}`;
|
||||
window.location.href = link;
|
||||
navigator.clipboard.writeText(link);
|
||||
spanButton.classList.toggle("copied");
|
||||
setTimeout(() => heading.classList.remove("copied"), 1000);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
import DocsLayout from "@layouts/DocsLayout.astro";
|
||||
import TOC from "@components/navigation/sidebars/TOC.astro";
|
||||
import TOCIntersectionObserver from "@src/components/hooks/TOCIntersectionObserver.astro";
|
||||
import type { ConfigHeading } from "@src/components/navigation/sidebars/types";
|
||||
|
||||
export interface Props {
|
||||
|
|
@ -12,15 +11,20 @@ export interface Props {
|
|||
|
||||
const { title, description, headings } = Astro.props;
|
||||
---
|
||||
|
||||
<DocsLayout title={title} description={description} headings={headings}>
|
||||
<div class="docs">
|
||||
<div class="docs-content">
|
||||
<hr/>
|
||||
<hr>
|
||||
<h1>{title}</h1>
|
||||
<slot/>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
<TOC slot="alongside-content" mobile={false} title={title} headings={headings} data-pagefind-ignore/>
|
||||
<TOC
|
||||
slot="alongside-content"
|
||||
mobile={false}
|
||||
title={title}
|
||||
headings={headings}
|
||||
data-pagefind-ignore
|
||||
/>
|
||||
</DocsLayout>
|
||||
|
||||
<TOCIntersectionObserver/>
|
||||
|
|
|
|||
|
|
@ -7,11 +7,15 @@ export interface Props {
|
|||
frontmatter: {
|
||||
title: string;
|
||||
description?: string;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const { headings, frontmatter: { title, description } } = Astro.props;
|
||||
const {
|
||||
headings,
|
||||
frontmatter: { title, description },
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<GuideLayout title={title} description={description ?? ""} headings={headings}>
|
||||
<slot/>
|
||||
<slot />
|
||||
</GuideLayout>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,14 @@ import { processMarkdown } from "@config/io/markdown";
|
|||
|
||||
const { versions } = await getVersionsData();
|
||||
|
||||
const versionsMd = await Promise.all(versions.filter(version => version.changelog).map(async version => ({
|
||||
version,
|
||||
changelog: await processMarkdown(version.name, version.changelog!)
|
||||
})));
|
||||
const versionsMd = await Promise.all(
|
||||
versions
|
||||
.filter(version => version.changelog)
|
||||
.map(async version => ({
|
||||
version,
|
||||
changelog: await processMarkdown(version.name, version.changelog ?? ""),
|
||||
}))
|
||||
);
|
||||
|
||||
const headings = versionsMd.map(({ version }) => ({
|
||||
text: version.name,
|
||||
|
|
@ -16,6 +20,7 @@ const headings = versionsMd.map(({ version }) => ({
|
|||
depth: 1,
|
||||
}));
|
||||
---
|
||||
|
||||
<GuideLayout title="Changelog" description="" headings={headings}>
|
||||
{versionsMd.map(({ version, changelog }) => (
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
|
|
|
|||
|
|
@ -2,31 +2,39 @@
|
|||
import GuideLayout from "@layouts/GuideLayout.astro";
|
||||
import { getVersionsData } from "@config/io/generateTypeData";
|
||||
import { getGuideCollection } from "@config/io/guides";
|
||||
import { processMarkdown } from "@config/io/markdown";
|
||||
|
||||
import { render } from "astro:content";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const { versions } = await getVersionsData();
|
||||
|
||||
let pages = await Promise.all(versions.map(async version => {
|
||||
const pages = await getGuideCollection(version.name);
|
||||
const pages = await Promise.all(
|
||||
versions.map(async version => {
|
||||
const pages = await getGuideCollection(version.name);
|
||||
|
||||
return pages.map(page => ({
|
||||
params: { version: version.name, id: page.id === "index" ? "/" : page.id },
|
||||
props: { version, page },
|
||||
}));
|
||||
}));
|
||||
return pages.map(page => ({
|
||||
params: {
|
||||
version: version.name,
|
||||
id: page.id === "index" ? "/" : page.id,
|
||||
},
|
||||
props: { version, page },
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
return pages.flat();
|
||||
}
|
||||
|
||||
const { version, page } = Astro.props;
|
||||
const { headings } = await render(page);
|
||||
const { page } = Astro.props;
|
||||
const { headings, Content } = await render(page);
|
||||
|
||||
// xnzf: version is decided before these pages get processed
|
||||
// V
|
||||
// we can't use 'Content' because there isn't a way to pass in a version
|
||||
const html = await processMarkdown(version.name, page.body!);
|
||||
|
||||
// const html = await processMarkdown(version.name, page.body!);
|
||||
---
|
||||
|
||||
<GuideLayout title={page.data.title} description="" headings={headings}>
|
||||
<Fragment set:html={html}/>
|
||||
<Content />
|
||||
</GuideLayout>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export async function getStaticPaths() {
|
|||
|
||||
const { version } = Astro.props;
|
||||
---
|
||||
|
||||
<DocsLayout title="Quickshell Docs" description="Quickshell Documentation">
|
||||
<h2>Docs</h2>
|
||||
<div class="root-nav">
|
||||
|
|
|
|||
|
|
@ -9,12 +9,25 @@ import Functions from "@components/type/Functions.astro";
|
|||
import Signals from "@components/type/Signals.astro";
|
||||
import Variants from "@components/type/Variants.astro";
|
||||
import Badge from "@components/Badge.astro";
|
||||
import type { ModuleData, TypeData } from "@_types";
|
||||
|
||||
interface Props {
|
||||
version: {
|
||||
name: string;
|
||||
};
|
||||
module: ModuleData;
|
||||
type: TypeData;
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return (await getVersionsData()).versions.flatMap(version => {
|
||||
return version.modules.flatMap(module => {
|
||||
return module.types.map(type => ({
|
||||
params: { version: version.name, module: module.name, type: type.name },
|
||||
params: {
|
||||
version: version.name,
|
||||
module: module.name,
|
||||
type: type.name,
|
||||
},
|
||||
props: { version, module, type },
|
||||
}));
|
||||
});
|
||||
|
|
@ -29,13 +42,18 @@ const details = type.details
|
|||
? await processMarkdown(version.name, type.details)
|
||||
: null;
|
||||
---
|
||||
<DocsLayout title={`${module.name} - ${type.name}`} description={type.description ?? ""} type={type}>
|
||||
|
||||
<DocsLayout
|
||||
title={`${module.name} - ${type.name}`}
|
||||
description={type.description ?? ""}
|
||||
type={type}
|
||||
>
|
||||
<div class="docs">
|
||||
<div class="docs-content typedocs-content">
|
||||
<hr />
|
||||
<hr>
|
||||
<section class="typedocs-title">
|
||||
<h2 class="typedocs-title-text" data-pagefind-weight="10">
|
||||
{type.name}:
|
||||
<h2 class="typedocs-title-text" data-pagefind-weight="10">
|
||||
{type.name}:
|
||||
{type.super?.name ? (
|
||||
<a
|
||||
href={superLink!}
|
||||
|
|
@ -45,11 +63,10 @@ const details = type.details
|
|||
</a>
|
||||
):(
|
||||
<span class="type-datatype" data-pagefind-ignore>{type.name}</span>
|
||||
)
|
||||
}
|
||||
</h2>
|
||||
{type.flags && (
|
||||
<div class="type-flags" data-pagefind-ignore>{type.flags.map(flag => (
|
||||
)}
|
||||
</h2>
|
||||
{type.flags && (
|
||||
<div class="type-flags" data-pagefind-ignore>{type.flags.map((flag:string) => (
|
||||
<Badge badgeText={flag}/>
|
||||
))}</div>
|
||||
)}
|
||||
|
|
@ -59,23 +76,23 @@ const details = type.details
|
|||
<subheading class="typedocs-subheading">
|
||||
{details ? <span class="parsedMD" set:html={details}/> : (<span class="toparse">{type.description}</span>)}
|
||||
</subheading>
|
||||
{ Object.keys(type.properties ?? {}).length != 0 && (
|
||||
{Object.keys(type.properties ?? {}).length != 0 && (
|
||||
<h2>Properties <a href={`/docs/${version.name}/guide/qml-language#properties`}>[?]</a></h2>
|
||||
<Properties props={type.properties!}/>
|
||||
)}
|
||||
{ (type.functions?.length ?? 0) != 0 && (
|
||||
<h2>Functions <a href={`/docs/${version.name}guide/qml-language#functions`}>[?]</a></h2>
|
||||
{(type.functions?.length ?? 0) != 0 && (
|
||||
<h2>Functions <a href={`/docs/${version.name}/guide/qml-language#functions`}>[?]</a></h2>
|
||||
<Functions
|
||||
funcData={type.functions!}
|
||||
/>
|
||||
)}
|
||||
{ Object.keys(type.signals ?? {}).length != 0 && (
|
||||
<h2>Signals <a href={`/docs/${version.name}guide/qml-language#signals`}>[?]</a></h2>
|
||||
{Object.keys(type.signals ?? {}).length != 0 && (
|
||||
<h2>Signals <a href={`/docs/${version.name}/guide/qml-language#signals`}>[?]</a></h2>
|
||||
<Signals
|
||||
signals={type.signals!}
|
||||
/>
|
||||
)}
|
||||
{ Object.keys(type.variants ?? {}).length != 0 && (
|
||||
{Object.keys(type.variants ?? {}).length != 0 && (
|
||||
<h2>Variants</h2>
|
||||
<Variants
|
||||
variants={type.variants!}
|
||||
|
|
@ -83,7 +100,6 @@ const details = type.details
|
|||
)}
|
||||
</section>
|
||||
</div>
|
||||
<TOC mobile={false} type={type} data-pagefind-ignore/>
|
||||
<TOC mobile={false} type={type} data-pagefind-ignore />
|
||||
</div>
|
||||
</DocsLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import DocsLayout from "@layouts/DocsLayout.astro";
|
||||
import { getVersionsData } from "@config/io/generateTypeData";
|
||||
import { processMarkdown } from "@src/config/io/markdown";
|
||||
import type { TypeData } from "@_types";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return (await getVersionsData()).versions.flatMap(version => {
|
||||
|
|
@ -23,12 +24,12 @@ const details = module.details
|
|||
description="Quickshell Type Documentation"
|
||||
>
|
||||
<div class="docs-content">
|
||||
<hr />
|
||||
<hr>
|
||||
<h2 class="typedocs-title">{module.name} Definitions</h2>
|
||||
<section>
|
||||
<span>{module.description}</span>
|
||||
<div class="root-nav" data-pagefind-ignore>
|
||||
{module.types.map(type =>
|
||||
{module.types.map((type: TypeData) =>
|
||||
(
|
||||
<div class="root-nav-entry">
|
||||
<a class="root-nav-link" href={`/docs/${version.name}/types/${module.name}/${type.name}`}>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
import DocsLayout from "@layouts/DocsLayout.astro";
|
||||
import { getVersionsData } from "@config/io/generateTypeData";
|
||||
import type { ModuleData } from "@_types";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return (await getVersionsData()).versions.map(version => ({
|
||||
|
|
@ -11,14 +12,18 @@ export async function getStaticPaths() {
|
|||
|
||||
const { version } = Astro.props;
|
||||
---
|
||||
<DocsLayout title="Quickshell Module Listing" description="Quickshell Type Documentation">
|
||||
|
||||
<DocsLayout
|
||||
title="Quickshell Module Listing"
|
||||
description="Quickshell Type Documentation"
|
||||
>
|
||||
<div class="docs-content">
|
||||
<hr/>
|
||||
<hr>
|
||||
<h2>Module Listing</h2>
|
||||
<section>
|
||||
<span>All modules included with Quickshell</span>
|
||||
<div class="root-nav" data-pagefind-ignore>
|
||||
{version.modules.map(module => (
|
||||
{version.modules.map((module: ModuleData) => (
|
||||
<div class="root-nav-entry">
|
||||
<a class="root-nav-link" href={`/docs/${version.name}/types/${module.name}`}>
|
||||
{module.name}
|
||||
|
|
|
|||
|
|
@ -8,42 +8,52 @@ const defaultVersion = (await getVersionsData()).default;
|
|||
|
||||
const title = "Quickshell";
|
||||
---
|
||||
<BaseLayout title={title} description="A fully user customizable desktop shell" image="/quickshell.png">
|
||||
|
||||
<BaseLayout
|
||||
title={title}
|
||||
description="A fully user customizable desktop shell"
|
||||
image="/quickshell.png"
|
||||
>
|
||||
<!--<a class="main-page-banner" href="/changelog">
|
||||
Quickshell 0.2.1 has been released! | 2025-10-11
|
||||
</a>-->
|
||||
<div class="main-page_hero" data-pagefind-ignore>
|
||||
<div class="titlebox">
|
||||
<img src="/favicon.svg" alt="Quickshell"/>
|
||||
<img src="/favicon.svg" alt="Quickshell">
|
||||
<h1 class="gradient-text">Quickshell</h1>
|
||||
</div>
|
||||
<section class="main-page_hero-text">
|
||||
<h2>building blocks for your desktop</h2>
|
||||
</section>
|
||||
<Marquee/>
|
||||
<Marquee />
|
||||
<section class="about">
|
||||
<div class="about-txt">
|
||||
<p>
|
||||
Quickshell is a toolkit for building status bars, widgets, lockscreens,
|
||||
and other desktop components using QtQuick. It can be used alongside your
|
||||
wayland compositor or window manager to build a complete desktop environment.
|
||||
Quickshell is a toolkit for building status bars, widgets,
|
||||
lockscreens, and other desktop components using QtQuick. It can be
|
||||
used alongside your wayland compositor or window manager to build a
|
||||
complete desktop environment.
|
||||
<br class="about-break">
|
||||
<br class="about-break">
|
||||
<a href="/about">More information</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="about-buttons">
|
||||
<a href={`/docs/${defaultVersion}/guide/install-setup`} class="main-page_link-card">
|
||||
<a
|
||||
href={`/docs/${defaultVersion}/guide/install-setup`}
|
||||
class="main-page_link-card"
|
||||
>
|
||||
<h3>Install</h3>
|
||||
</a>
|
||||
<a href={`/docs/${defaultVersion}/types`} class="main-page_link-card main-page_bluecard">
|
||||
<a
|
||||
href={`/docs/${defaultVersion}/types`}
|
||||
class="main-page_link-card main-page_bluecard"
|
||||
>
|
||||
<h3>Documentation</h3>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="featurelist-section">
|
||||
<FeatureList/>
|
||||
</section>
|
||||
<section class="featurelist-section"><FeatureList /></section>
|
||||
</div>
|
||||
<Footer class="frontpage-footer"/>
|
||||
<Footer class="frontpage-footer" />
|
||||
</BaseLayout>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.accordion {
|
||||
& summary {
|
||||
list-style: none;
|
||||
transition: background-color 0.15s ease-out;
|
||||
transition: background-color var(--theme-transition);
|
||||
}
|
||||
|
||||
& .accordion-container {
|
||||
|
|
@ -12,7 +12,9 @@
|
|||
|
||||
& .accordion-container.animate {
|
||||
/* this somehow breaks if both min AND max aren't animated */
|
||||
transition: min-height 0.3s ease, max-height 0.3s ease;
|
||||
transition:
|
||||
min-height 0.3s ease,
|
||||
max-height 0.3s ease;
|
||||
min-height: var(--height);
|
||||
max-height: var(--height);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,18 +12,22 @@
|
|||
.featurelist-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 0.618rem;
|
||||
gap: var(--xs);
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-block: 0.618rem;
|
||||
border-radius: 9px;
|
||||
margin-block: var(--xs);
|
||||
border-radius: var(--radius-md);
|
||||
background-color: hsl(var(--blue) 60% 98%);
|
||||
padding: 0.618rem;
|
||||
border: 1px solid hsl(var(--blue) 9% 75%);
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
border-color var(--theme-transition);
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0.618rem;
|
||||
inset: var(--xs);
|
||||
background-image: radial-gradient(
|
||||
hsl(var(--blue) 9% 75%) 1px,
|
||||
transparent 1px
|
||||
|
|
@ -33,7 +37,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
html.dark .featurelist-item {
|
||||
html.dark .featurelist-item,
|
||||
html:has(input#theme-manual-toggle:checked) .featurelist-item {
|
||||
background-color: hsl(var(--blue) 100% 81% / 0.05);
|
||||
border-color: hsl(0deg 0% 100% / 0.05);
|
||||
|
||||
|
|
@ -46,18 +51,22 @@ html.dark .featurelist-item {
|
|||
}
|
||||
|
||||
.feature-text {
|
||||
margin: 1rem 0;
|
||||
margin: var(--sm) 0;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
font-size: 1.2em;
|
||||
|
||||
& .feature-title {
|
||||
margin-bottom: 0.517rem;
|
||||
}
|
||||
|
||||
& .feature-subtitle {
|
||||
color: #303030;
|
||||
transition: color var(--theme-transition);
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .feature-text {
|
||||
html.dark .feature-text,
|
||||
html:has(input#theme-manual-toggle:checked) .feature-text {
|
||||
& .feature-subtitle {
|
||||
color: #afafaf;
|
||||
}
|
||||
|
|
@ -72,7 +81,8 @@ html.dark .feature-text {
|
|||
& video {
|
||||
width: 100%;
|
||||
aspect-ratio: 16 / 9;
|
||||
border-radius: 0.681rem;
|
||||
border-radius: var(--radius-sm);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
& .shiki {
|
||||
|
|
@ -80,6 +90,7 @@ html.dark .feature-text {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
/*font-size: 0.55rem;*/
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
& .showcase-desktop {
|
||||
|
|
@ -98,8 +109,13 @@ html.dark .feature-text {
|
|||
}
|
||||
}
|
||||
|
||||
html:not(.dark) .feature-showcase .shiki,
|
||||
html:not(.dark) .feature-showcase .shiki span {
|
||||
html:not(.dark):not(:has(input#theme-manual-toggle:checked))
|
||||
.feature-showcase
|
||||
.shiki,
|
||||
html:not(.dark):not(:has(input#theme-manual-toggle:checked))
|
||||
.feature-showcase
|
||||
.shiki
|
||||
span {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +134,7 @@ html:not(.dark) .feature-showcase .shiki span {
|
|||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
& .cloud-center img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
|
|
@ -140,6 +157,7 @@ html:not(.dark) .feature-showcase .shiki span {
|
|||
& > div {
|
||||
transform: rotate(0deg);
|
||||
animation: counter-spin 40s linear infinite;
|
||||
|
||||
& .feature-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
|
|
@ -149,26 +167,34 @@ html:not(.dark) .feature-showcase .shiki span {
|
|||
&.wayland {
|
||||
transform: translate(-50%, 0) rotate(0deg);
|
||||
}
|
||||
|
||||
&.hyprland {
|
||||
transform: translate(-50%, 0) rotate(72deg);
|
||||
|
||||
& .feature-icon {
|
||||
transform: rotate(-72deg);
|
||||
}
|
||||
}
|
||||
|
||||
&.pipewire {
|
||||
transform: translate(-50%, 0) rotate(144deg);
|
||||
|
||||
& .feature-icon {
|
||||
transform: rotate(-144deg);
|
||||
}
|
||||
}
|
||||
|
||||
&.x-org {
|
||||
transform: translate(-50%, 0) rotate(216deg);
|
||||
|
||||
& .feature-icon {
|
||||
transform: rotate(-216deg);
|
||||
}
|
||||
}
|
||||
|
||||
&.sway {
|
||||
transform: translate(-50%, 0) rotate(288deg);
|
||||
|
||||
& .feature-icon {
|
||||
transform: rotate(-288deg);
|
||||
}
|
||||
|
|
@ -180,6 +206,7 @@ html:not(.dark) .feature-showcase .shiki span {
|
|||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
|
|
@ -189,6 +216,7 @@ html:not(.dark) .feature-showcase .shiki span {
|
|||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(-360deg);
|
||||
}
|
||||
|
|
@ -213,33 +241,42 @@ html:not(.dark) .feature-showcase .shiki span {
|
|||
width: auto;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.feature-text {
|
||||
margin: 0 2.218rem;
|
||||
}
|
||||
|
||||
.featurelist-item {
|
||||
width: 100%;
|
||||
padding: 1.217rem;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.featurelist-item.right {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.feature-showcase {
|
||||
height: 22rem;
|
||||
}
|
||||
|
||||
.feature-text {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.feature-showcase {
|
||||
width: auto;
|
||||
aspect-ratio: 16 / 9;
|
||||
|
||||
& video {
|
||||
scale: 1;
|
||||
}
|
||||
|
||||
& .shiki {
|
||||
font-size: 0.93rem;
|
||||
}
|
||||
|
||||
.feature-cloud {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 2.217rem;
|
||||
font-size: 1.874rem;
|
||||
gap: var(--xl);
|
||||
font-size: var(--lg);
|
||||
font-weight: 600;
|
||||
margin-inline: 0.618rem;
|
||||
margin-inline: var(--sm);
|
||||
}
|
||||
|
||||
.marquee-button {
|
||||
|
|
@ -20,36 +20,63 @@
|
|||
left: 2px;
|
||||
right: 2px;
|
||||
height: 3px;
|
||||
background-color: hsl(var(--accent-400) / 0.3);
|
||||
background-color: hsla(var(--accent-400) / 0.3);
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
||||
.marquee {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-block: 1.618rem;
|
||||
justify-content: center;
|
||||
margin-block: var(--xl);
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.6s ease;
|
||||
min-height: 200px; /* placeholder height */
|
||||
|
||||
&.initialized {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.marquee-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
will-change: transform;
|
||||
transform: translateX(0);
|
||||
visibility: hidden;
|
||||
|
||||
.initialized & {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.marquee-item {
|
||||
flex: 1 0 100%;
|
||||
transition: transform 0.3s cubic-bezier(0.46, 0.03, 0.52, 0.96);
|
||||
transform: translateX(var(--scroll));
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--md);
|
||||
padding-inline: 0.5rem;
|
||||
box-sizing: border-box;
|
||||
will-change: opacity;
|
||||
|
||||
& > div {
|
||||
& > * {
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
& video {
|
||||
position: relative;
|
||||
max-width: 75rem;
|
||||
width: 100%;
|
||||
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,34 +85,38 @@
|
|||
}
|
||||
|
||||
.marquee-item-content {
|
||||
border-radius: 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.marquee-scroll {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
max-width: 85rem;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition:
|
||||
background-color 0.3s,
|
||||
opacity 0.3s;
|
||||
z-index: 10;
|
||||
user-select: none;
|
||||
align-items: stretch;
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
opacity var(--theme-transition);
|
||||
z-index: 20;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
padding-inline: 1rem;
|
||||
}
|
||||
|
||||
.marquee-scroll-arrow {
|
||||
max-width: 8rem;
|
||||
width: 8rem;
|
||||
font-size: 2rem;
|
||||
pointer-events: all;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
& > div {
|
||||
width: 2.5rem;
|
||||
|
|
@ -95,10 +126,12 @@
|
|||
justify-content: center;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.3s ease;
|
||||
backdrop-filter: blur(var(--2xs));
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
||||
& > div {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
|
@ -132,14 +165,10 @@
|
|||
@media not (min-width: 83rem) {
|
||||
.marquee-scroll-arrow {
|
||||
height: unset;
|
||||
|
||||
& > div {
|
||||
background-color: #55555580;
|
||||
border-radius: 0.2rem;
|
||||
border-radius: var(--radius-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.marquee-scroll {
|
||||
width: 92%;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,3 +116,61 @@
|
|||
--percent-nav-root_filled: 65%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ping {
|
||||
75%,
|
||||
100% {
|
||||
transform: scale(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0% {
|
||||
transform: none;
|
||||
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(-12%);
|
||||
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
color: hsla(var(--green) 100 69 / 0.75);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: none;
|
||||
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
0% {
|
||||
transform: scale(0.75);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
--animate-spin: spin 1s linear infinite;
|
||||
--animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
--animate-bounce: bounce 0.6s var(--ease-out) forwards;
|
||||
--animate-fade: fade 0.3s cubic-bezier(0.4, 0, 0.6, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,129 +1,18 @@
|
|||
html {
|
||||
font-family: "Rubik Variable", Inter, system-ui, Avenir, Helvetica, Arial,
|
||||
sans-serif;
|
||||
font-family:
|
||||
"Rubik Variable", Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.272;
|
||||
font-weight: 400;
|
||||
|
||||
height: 100svh;
|
||||
/* width: 100svw; causes horizontal overflow due to the scrollbar*/
|
||||
width: 100%;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
color-scheme: light dark;
|
||||
/* accent */
|
||||
--green: 141deg;
|
||||
--accent-400: var(--green) 90% 57%;
|
||||
--accent-500: var(--green) 90% 47%;
|
||||
--accent-600: var(--green) 88% 40%;
|
||||
--accent-700: var(--green) 70% 40%;
|
||||
|
||||
/* secondary */
|
||||
--blue: 224deg;
|
||||
--secondary-400: var(--blue) 100% 68%;
|
||||
--secondary-500: var(--blue) 100% 58%;
|
||||
--secondary-600: var(--blue) 53% 41%;
|
||||
--secondary-700: var(--blue) 43% 31%;
|
||||
--secondary-800: var(--blue) 23% 21%;
|
||||
--secondary-900: var(--blue) 44% 7%;
|
||||
|
||||
/* primary */
|
||||
--white: 194deg;
|
||||
--bg-400: var(--white) 10% 95%;
|
||||
--bg-500: var(--white) 5% 90%;
|
||||
--bg-600: var(--white) 5% 76%;
|
||||
--bg-700: var(--white) 5% 56%;
|
||||
--bg-800: var(--white) 5% 36%;
|
||||
--bg-900: var(--white) 5% 16%;
|
||||
|
||||
/* docs */
|
||||
--background: var(--bg-500);
|
||||
--text: var(--white) 0% 0%;
|
||||
--text-dark: var(--white) 0% 18%;
|
||||
--text-darker: var(--white) 0% 30%;
|
||||
--link: var(--green) 48% 40%;
|
||||
--toc-link: var(--green) 74% 30%;
|
||||
--toc-link-active: var(--green) 80% 38%;
|
||||
--prop-color: 350deg 78% 70%;
|
||||
--prop-link-color: 350deg 78% 60%;
|
||||
--func-color: 50deg 68% 50%;
|
||||
--func-link-color: 50deg 58% 55%;
|
||||
--signal-color: 270deg 78% 70%;
|
||||
--signal-link-color: 270deg 85% 60%;
|
||||
--var-color: 190deg 78% 70%;
|
||||
--var-link-color: 190deg 85% 60%;
|
||||
--inner-param-color: 215deg 80% 27%;
|
||||
--inner-param-border-color: 215deg 50% 50%;
|
||||
--nav-hovered-bkg: var(--blue) 100% 87%;
|
||||
--nav-hovered-weak-bkg: var(--blue) 100% 91%;
|
||||
--nav-selected-bkg: var(--blue) 100% 90%;
|
||||
--nav-selected-hovered-bkg: var(--blue) 100% 85%;
|
||||
--nav-selected-text: var(--blue) 60% 60%;
|
||||
--nav-indicator-bkg: var(--blue) 45% 80%;
|
||||
--toc-hovered-bkg: 0deg 0% 0% / 0.1;
|
||||
--overlay-bkg: var(--blue) 25% 93%;
|
||||
--overlay-bkg-border: var(--blue) 10% 75%;
|
||||
--footer-bkg: var(--blue) 8% 87%;
|
||||
--footer-bkg-border: var(--blue) 32% 84%;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
/* accent */
|
||||
--green: 141deg;
|
||||
--accent-400: var(--green) 100% 67%;
|
||||
--accent-500: var(--green) 95% 55%;
|
||||
--accent-600: var(--green) 90% 40%;
|
||||
--accent-700: var(--green) 80% 30%;
|
||||
|
||||
/* secondary */
|
||||
--white: 194deg;
|
||||
--secondary-400: var(--white) 33% 100%;
|
||||
--secondary-500: var(--white) 33% 96%;
|
||||
--secondary-600: var(--white) 33% 76%;
|
||||
--secondary-700: var(--white) 33% 56%;
|
||||
--secondary-800: var(--white) 35% 36%;
|
||||
--secondary-900: var(--white) 44% 7%;
|
||||
|
||||
/* primary */
|
||||
--blue: 224deg;
|
||||
--bg-400: var(--blue) 90% 65%;
|
||||
--bg-500: var(--blue) 83% 45%;
|
||||
--bg-700: var(--blue) 82% 25%;
|
||||
--bg-800: var(--blue) 82% 15%;
|
||||
--bg-900: var(--blue) 82% 3%;
|
||||
|
||||
/* docs */
|
||||
--background: var(--bg-900);
|
||||
--text: var(--white) 0% 100%;
|
||||
--text-dark: var(--white) 0% 70%;
|
||||
--text-darker: var(--white) 0% 40%;
|
||||
--link: var(--green) 60% 44%;
|
||||
--toc-link: var(--green) 74% 40%;
|
||||
--toc-link-active: var(--green) 80% 60%;
|
||||
--prop-color: 350deg 78% 70%;
|
||||
--prop-link-color: 350deg 78% 60%;
|
||||
--func-color: 50deg 78% 70%;
|
||||
--func-link-color: 50deg 78% 60%;
|
||||
--signal-color: 270deg 78% 70%;
|
||||
--signal-link-color: 270deg 85% 60%;
|
||||
--var-color: 190deg 78% 70%;
|
||||
--var-link-color: 190deg 85% 60%;
|
||||
--inner-param-color: 215deg 60% 70%;
|
||||
--inner-param-border-color: 215deg 26% 46%;
|
||||
--inner-param-color: 215deg 60% 70%;
|
||||
--nav-hovered-bkg: var(--blue) 40% 10%;
|
||||
--nav-hovered-weak-bkg: var(--blue) 35% 8%;
|
||||
--nav-selected-bkg: var(--blue) 40% 13%;
|
||||
--nav-selected-hovered-bkg: var(--blue) 40% 17%;
|
||||
--nav-selected-text: var(--blue) 100% 70%;
|
||||
--nav-indicator-bkg: var(--blue) 30% 30%;
|
||||
--toc-hovered-bkg: 0deg 0% 100% / 0.07;
|
||||
--overlay-bkg: var(--blue) 75% 5%;
|
||||
--overlay-bkg-border: var(--blue) 45% 15%;
|
||||
--footer-bkg: var(--blue) 66% 5%;
|
||||
--footer-bkg-border: var(--blue) 75% 21%;
|
||||
}
|
||||
|
||||
* {
|
||||
|
|
@ -131,6 +20,7 @@ html.dark {
|
|||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
/* transition: all 0.15s var(--ease-in-out); */
|
||||
}
|
||||
|
||||
body {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
pre.shiki {
|
||||
margin-block: 1.618rem;
|
||||
margin-block: var(--lg);
|
||||
}
|
||||
|
||||
:where(p, li):has(> code) code {
|
||||
padding-inline: 0.272rem;
|
||||
border-radius: 0.272rem;
|
||||
color: hsl(var(--blue) 100% 69%);
|
||||
background-color: hsl(var(--blue) 85% 35% / 0.1);
|
||||
padding-inline: var(--sm);
|
||||
border-radius: var(--radius-xs);
|
||||
color: hsl(var(--blue) 100 69);
|
||||
background-color: hsla(var(--blue) 85 35 / 0.1);
|
||||
}
|
||||
|
||||
.shiki,
|
||||
|
|
@ -16,7 +16,9 @@ pre.shiki {
|
|||
}
|
||||
|
||||
html.dark .shiki,
|
||||
html.dark .shiki span {
|
||||
html.dark .shiki span,
|
||||
html:has(input#theme-manual-toggle:checked) .shiki,
|
||||
html:has(input#theme-manual-toggle:checked) .shiki span {
|
||||
color: var(--shiki-dark);
|
||||
background-color: var(--shiki-dark-bg);
|
||||
}
|
||||
|
|
@ -26,8 +28,11 @@ pre {
|
|||
border-radius: 0.618rem;
|
||||
overflow: hidden;
|
||||
text-wrap: wrap;
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
color var(--theme-transition);
|
||||
|
||||
& > button {
|
||||
& .copy-button {
|
||||
all: unset;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
|
@ -41,17 +46,51 @@ pre {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: hsl(var(--blue) 100% 69%);
|
||||
background-color: hsl(var(--blue) 85% 35% / 0.1);
|
||||
color: hsla(var(--blue) 100 69 / 0.33);
|
||||
background-color: hsla(var(--blue) 85 35 / 0.01);
|
||||
cursor: pointer;
|
||||
transition: color 0.25s;
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
color var(--theme-transition);
|
||||
z-index: 10;
|
||||
|
||||
& svg {
|
||||
position: absolute;
|
||||
transition:
|
||||
transform 0.3s var(--ease-in-out),
|
||||
opacity 0.3s var(--ease-in-out);
|
||||
}
|
||||
|
||||
& .check-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
color: hsl(var(--green) 100 69);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: hsl(var(--blue) 100% 75%);
|
||||
color: hsla(var(--blue) 100 75 / 0.75);
|
||||
background-color: hsla(var(--blue) 85 35 / 0.1);
|
||||
}
|
||||
|
||||
&.copied {
|
||||
animation: pulseGreen 0.5s cubic-bezier(0, 1, 0.6, 1);
|
||||
& .copy-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
& .check-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.shiki {
|
||||
box-shadow: var(--shadow-md);
|
||||
|
||||
&:hover .copy-button {
|
||||
transition: background-color var(--theme-transition);
|
||||
background-color: hsla(var(--blue) 85 35 / 0.07);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,118 @@
|
|||
html:not(.dark):not(:has(input#theme-manual-toggle:checked)) {
|
||||
color-scheme: light dark;
|
||||
/* accent */
|
||||
--green: 141deg;
|
||||
--accent-400: var(--green) 90% 57%;
|
||||
--accent-500: var(--green) 90% 47%;
|
||||
--accent-600: var(--green) 88% 40%;
|
||||
--accent-700: var(--green) 70% 35%;
|
||||
|
||||
/* secondary */
|
||||
--blue: 224deg;
|
||||
--secondary-400: var(--blue) 100% 68%;
|
||||
--secondary-500: var(--blue) 100% 58%;
|
||||
--secondary-600: var(--blue) 53% 41%;
|
||||
--secondary-700: var(--blue) 43% 31%;
|
||||
--secondary-800: var(--blue) 23% 21%;
|
||||
--secondary-900: var(--blue) 44% 7%;
|
||||
|
||||
/* primary */
|
||||
--white: 194deg;
|
||||
--bg-400: var(--white) 10% 98%;
|
||||
--bg-500: var(--white) 10% 95%;
|
||||
--bg-600: var(--white) 8% 88%;
|
||||
--bg-700: var(--white) 8% 78%;
|
||||
--bg-800: var(--white) 5% 56%;
|
||||
--bg-900: var(--white) 5% 16%;
|
||||
|
||||
/* docs */
|
||||
--background: var(--bg-400);
|
||||
--text: var(--white) 0% 10%;
|
||||
--text-dark: var(--white) 0% 25%;
|
||||
--text-darker: var(--white) 0% 40%;
|
||||
--link: var(--green) 60% 35%;
|
||||
--toc-link: var(--white) 0% 40%;
|
||||
--toc-link-active: var(--green) 60% 35%;
|
||||
--prop-color: 350deg 78% 65%;
|
||||
--prop-link-color: 350deg 78% 45%;
|
||||
--func-color: 50deg 78% 45%;
|
||||
--func-link-color: 50deg 85% 30%;
|
||||
--signal-color: 270deg 60% 65%;
|
||||
--signal-link-color: 270deg 75% 45%;
|
||||
--var-color: 190deg 78% 65%;
|
||||
--var-link-color: 190deg 85% 40%;
|
||||
--inner-param-color: 215deg 80% 27%;
|
||||
--inner-param-border-color: 215deg 50% 50%;
|
||||
--nav-hovered-bkg: var(--blue) 100% 94%;
|
||||
--nav-hovered-weak-bkg: var(--blue) 100% 96%;
|
||||
--nav-selected-bkg: var(--blue) 100% 92%;
|
||||
--nav-selected-hovered-bkg: var(--blue) 100% 88%;
|
||||
--nav-selected-text: var(--blue) 70% 45%;
|
||||
--nav-indicator-bkg: var(--blue) 45% 80%;
|
||||
--toc-hovered-bkg: 0deg 0% 0% / 0.05;
|
||||
--overlay-bkg: var(--white) 10% 98%;
|
||||
--overlay-bkg-border: var(--white) 10% 85%;
|
||||
--footer-bkg: var(--white) 10% 95%;
|
||||
--footer-bkg-border: var(--white) 10% 88%;
|
||||
}
|
||||
|
||||
html.dark,
|
||||
html:has(input#theme-manual-toggle:checked) {
|
||||
/* accent */
|
||||
--green: 141deg;
|
||||
--accent-400: var(--green) 100% 67%;
|
||||
--accent-500: var(--green) 95% 55%;
|
||||
--accent-600: var(--green) 90% 40%;
|
||||
--accent-700: var(--green) 80% 30%;
|
||||
|
||||
/* secondary */
|
||||
--white: 194deg;
|
||||
--secondary-400: var(--white) 33% 100%;
|
||||
--secondary-500: var(--white) 33% 96%;
|
||||
--secondary-600: var(--white) 33% 76%;
|
||||
--secondary-700: var(--white) 33% 56%;
|
||||
--secondary-800: var(--white) 35% 36%;
|
||||
--secondary-900: var(--white) 44% 7%;
|
||||
|
||||
/* primary */
|
||||
--blue: 224deg;
|
||||
--bg-400: var(--blue) 90% 65%;
|
||||
--bg-500: var(--blue) 83% 45%;
|
||||
--bg-700: var(--blue) 82% 25%;
|
||||
--bg-800: var(--blue) 82% 15%;
|
||||
--bg-900: var(--blue) 82% 3%;
|
||||
|
||||
/* docs */
|
||||
--background: var(--bg-900);
|
||||
--text: var(--white) 0% 100%;
|
||||
--text-dark: var(--white) 0% 70%;
|
||||
--text-darker: var(--white) 0% 40%;
|
||||
--link: var(--green) 60% 44%;
|
||||
--toc-link: var(--green) 74% 40%;
|
||||
--toc-link-active: var(--green) 80% 60%;
|
||||
--prop-color: 350deg 78% 70%;
|
||||
--prop-link-color: 350deg 78% 60%;
|
||||
--func-color: 50deg 78% 70%;
|
||||
--func-link-color: 50deg 78% 60%;
|
||||
--signal-color: 270deg 78% 70%;
|
||||
--signal-link-color: 270deg 85% 60%;
|
||||
--var-color: 190deg 78% 70%;
|
||||
--var-link-color: 190deg 85% 60%;
|
||||
--inner-param-color: 215deg 60% 70%;
|
||||
--inner-param-border-color: 215deg 26% 46%;
|
||||
--nav-hovered-bkg: var(--blue) 40% 10%;
|
||||
--nav-hovered-weak-bkg: var(--blue) 35% 8%;
|
||||
--nav-selected-bkg: var(--blue) 40% 13%;
|
||||
--nav-selected-hovered-bkg: var(--blue) 40% 17%;
|
||||
--nav-selected-text: var(--blue) 100% 70%;
|
||||
--nav-indicator-bkg: var(--blue) 30% 30%;
|
||||
--toc-hovered-bkg: 0deg 0% 100% / 0.07;
|
||||
--overlay-bkg: var(--blue) 75% 5%;
|
||||
--overlay-bkg-border: var(--blue) 45% 15%;
|
||||
--footer-bkg: var(--blue) 66% 5%;
|
||||
--footer-bkg-border: var(--blue) 75% 21%;
|
||||
}
|
||||
|
||||
.typeprop-link {
|
||||
color: hsl(var(--prop-link-color));
|
||||
|
||||
|
|
|
|||
6
src/styles/css-config/entry.css
Normal file
6
src/styles/css-config/entry.css
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
@import "normalize.css";
|
||||
@import "vars.css";
|
||||
@import "animations.css";
|
||||
@import "base.css";
|
||||
@import "code.css";
|
||||
@import "colors.css";
|
||||
475
src/styles/css-config/normalize.css
vendored
Normal file
475
src/styles/css-config/normalize.css
vendored
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||
/**
|
||||
* 1. Set default font family to sans-serif.
|
||||
* 2. Prevent iOS and IE text size adjust after device orientation change,
|
||||
* without disabling user zoom.
|
||||
*/
|
||||
html {
|
||||
font-family: "Inter", sans-serif;
|
||||
/* 1 */
|
||||
-ms-text-size-adjust: 100%;
|
||||
/* 2 */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default margin.
|
||||
*/
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* HTML5 display definitions
|
||||
========================================================================== */
|
||||
/**
|
||||
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
||||
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
||||
* and Firefox.
|
||||
* Correct `block` display not defined for `main` in IE 11.
|
||||
*/
|
||||
/* article, */
|
||||
/* aside, */
|
||||
details,
|
||||
/* figcaption, */
|
||||
/* figure, */
|
||||
/* footer, */
|
||||
/* header, */
|
||||
/* hgroup, */
|
||||
/* main, */
|
||||
/* menu, */
|
||||
/* nav, */
|
||||
/* section, */
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `inline-block` display not defined in IE 8/9.
|
||||
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block;
|
||||
/* 1 */
|
||||
vertical-align: baseline;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `[hidden]` styling not present in IE 8/9/10.
|
||||
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
|
||||
*/
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Links
|
||||
========================================================================== */
|
||||
/**
|
||||
* Remove the gray background color from active links in IE 10.
|
||||
*/
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability of focused elements when they are also in an
|
||||
* active/hover state.
|
||||
*/
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
/**
|
||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
||||
*/
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in Safari and Chrome.
|
||||
*/
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address variable `h1` font-size and margin within `section` and `article`
|
||||
* contexts in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9.
|
||||
*/
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: var(--hl-onbackground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
/**
|
||||
* Remove border when inside `a` element in IE 8/9/10.
|
||||
*/
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct overflow not hidden in IE 9/10/11.
|
||||
*/
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
/**
|
||||
* Address margin not present in IE 8/9 and Safari.
|
||||
*/
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address differences between Firefox and other browsers.
|
||||
*/
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contain overflow in all browsers.
|
||||
*/
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address odd `em`-unit font size rendering in all browsers.
|
||||
*/
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
/**
|
||||
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
||||
* styling of `select`, unless a `border` property is set.
|
||||
*/
|
||||
/**
|
||||
* 1. Correct color not being inherited.
|
||||
* Known issue: affects color of disabled elements.
|
||||
* 2. Correct font properties not being inherited.
|
||||
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
color: inherit;
|
||||
/* 1 */
|
||||
font: inherit;
|
||||
/* 2 */
|
||||
margin: 0;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||
* All other form control elements do not inherit `text-transform` values.
|
||||
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
||||
* Correct `select` style inheritance in Firefox.
|
||||
*/
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Correct inability to style clickable `input` types in iOS.
|
||||
* 3. Improve usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
* 4. CUSTOM FOR WEBFLOW: Removed the input[type="submit"] selector to reduce
|
||||
* specificity and defer to the .w-button selector
|
||||
*/
|
||||
button,
|
||||
html input[type="button"],
|
||||
input[type="reset"] {
|
||||
-webkit-appearance: button;
|
||||
/* 2 */
|
||||
cursor: pointer;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and border in Firefox 4+.
|
||||
*/
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's recommended that you don't attempt to style these elements.
|
||||
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
||||
*
|
||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||
* 2. Remove excess padding in IE 8/9/10.
|
||||
*/
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box;
|
||||
/* 1 */
|
||||
padding: 0;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
||||
* `font-size` values of the `input`, it causes the cursor style of the
|
||||
* decrement button to change from `default` to `text`.
|
||||
*/
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. CUSTOM FOR WEBFLOW: changed from `textfield` to `none` to normalize iOS rounded input
|
||||
* 2. CUSTOM FOR WEBFLOW: box-sizing: content-box rule removed
|
||||
* (similar to normalize.css >=4.0.0)
|
||||
*/
|
||||
input[type="search"] {
|
||||
-webkit-appearance: none;
|
||||
/* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
||||
* Safari (but not Chrome) clips the cancel button when the search input has
|
||||
* padding (and `textfield` appearance).
|
||||
*/
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
legend {
|
||||
border: 0;
|
||||
/* 1 */
|
||||
padding: 0;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default vertical scrollbar in IE 8/9/10/11.
|
||||
*/
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't inherit the `font-weight` (applied by a rule above).
|
||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
||||
*/
|
||||
optgroup {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Tables
|
||||
========================================================================== */
|
||||
/**
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Remove default margins and padding on all basic HTML elements */
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
a,
|
||||
abbr,
|
||||
acronym,
|
||||
address,
|
||||
big,
|
||||
cite,
|
||||
code,
|
||||
del,
|
||||
dfn,
|
||||
em,
|
||||
img,
|
||||
ins,
|
||||
kbd,
|
||||
q,
|
||||
s,
|
||||
samp,
|
||||
small,
|
||||
strike,
|
||||
strong,
|
||||
sub,
|
||||
sup,
|
||||
tt,
|
||||
var,
|
||||
b,
|
||||
u,
|
||||
i,
|
||||
center,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
ol,
|
||||
ul,
|
||||
li,
|
||||
fieldset,
|
||||
form,
|
||||
label,
|
||||
legend,
|
||||
table,
|
||||
caption,
|
||||
tbody,
|
||||
tfoot,
|
||||
thead,
|
||||
tr,
|
||||
th,
|
||||
td,
|
||||
article,
|
||||
aside,
|
||||
canvas,
|
||||
details,
|
||||
embed,
|
||||
figure,
|
||||
figcaption,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
output,
|
||||
ruby,
|
||||
section,
|
||||
summary,
|
||||
time,
|
||||
mark,
|
||||
audio,
|
||||
video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
82
src/styles/css-config/vars.css
Normal file
82
src/styles/css-config/vars.css
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
html {
|
||||
--scaleFactor: 1.618;
|
||||
--wholestep: 1.618;
|
||||
--halfstep: 1.272;
|
||||
--quarterstep: 1.128;
|
||||
--eighthstep: 1.062;
|
||||
|
||||
--wholestep-dec: 0.618;
|
||||
--halfstep-dec: 0.272;
|
||||
--quarterstep-dec: 0.128;
|
||||
--eighthstep-dec: 0.062;
|
||||
|
||||
--md: 1em;
|
||||
--sm: calc(1em / var(--scaleFactor));
|
||||
--xs: calc(var(--sm) / var(--scaleFactor));
|
||||
--2xs: calc(var(--xs) / var(--scaleFactor));
|
||||
--3xs: calc(var(--2xs) / var(--scaleFactor));
|
||||
--lg: calc(1em * var(--scaleFactor));
|
||||
--xl: calc(var(--lg) * var(--scaleFactor));
|
||||
--2xl: calc(var(--xl) * var(--scaleFactor));
|
||||
--3xl: calc(var(--2xl) * var(--scaleFactor));
|
||||
--4xl: calc(var(--3xl) * var(--scaleFactor));
|
||||
|
||||
/* INFO: Unitless sizes;
|
||||
required for adhoc calculations
|
||||
(division and multiplication in calc() require unitless numbers)
|
||||
*/
|
||||
/* NOTE:
|
||||
in calc() with (x*y) or (x/y) the "y" must be a unitless number
|
||||
*/
|
||||
|
||||
--sm-unitless: calc(1 / var(--scaleFactor));
|
||||
--xs-unitless: calc(var(--sm-unitless) / var(--scaleFactor));
|
||||
--2xs-unitless: calc(var(--xs-unitless) / var(--scaleFactor));
|
||||
--lg-unitless: calc(1 * var(--scaleFactor));
|
||||
--xl-unitless: calc(var(--lg-unitless) * var(--scaleFactor));
|
||||
--2xl-unitless: calc(var(--xl-unitless) * var(--scaleFactor));
|
||||
|
||||
--radius-xs: var(--xs);
|
||||
--radius-sm: var(--sm);
|
||||
--radius-md: var(--md);
|
||||
--radius-lg: var(--lg);
|
||||
--radius-xl: var(--xl);
|
||||
|
||||
--shadow-sm-units: 0 0 1px 0;
|
||||
--shadow-md-units-1: 0 4px 6px;
|
||||
--shadow-md-units-2: 0 2px 4px;
|
||||
--shadow-md-units-3: 0 0 1px;
|
||||
--shadow-lg-units-1: 0 11px 15px -3px;
|
||||
--shadow-lg-units-2: 0 2px 6px;
|
||||
--shadow-lg-units-3: 0 0 1px;
|
||||
--shadow-xl-units-1: 0 20px 25px;
|
||||
--shadow-xl-units-2: 0 5px 11px;
|
||||
--shadow-xl-units-3: 0 5px 11px;
|
||||
--shadow-2xl-units-1: 0 25px 50px;
|
||||
--shadow-2xl-units-2: 0 9px 18px;
|
||||
--shadow-2xl-units-3: 0 0 1px;
|
||||
|
||||
--shadow-sm: var(--shadow-sm-units) rgba(0, 0, 0, 0.11);
|
||||
--shadow-md:
|
||||
var(--shadow-md-units-1) rgba(0, 0, 0, 0.08),
|
||||
var(--shadow-md-units-2) rgba(0, 0, 0, 0.11),
|
||||
var(--shadow-md-units-3) rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg:
|
||||
var(--shadow-lg-units-1) rgba(0, 0, 0, 0.11),
|
||||
var(--shadow-lg-units-2) rgba(0, 0, 0, 0.07),
|
||||
var(--shadow-lg-units-3) rgba(0, 0, 0, 0.4);
|
||||
--shadow-xl:
|
||||
var(--shadow-xl-units-1) rgba(0, 0, 0, 0.09),
|
||||
var(--shadow-xl-units-2) rgba(0, 0, 0, 0.12),
|
||||
var(--shadow-xl-units-3) rgba(0, 0, 0, 0.4);
|
||||
--shadow-2xl:
|
||||
var(--shadow-2xl-units-1) rgba(0, 0, 0, 0.23),
|
||||
var(--shadow-2xl-units-2) rgba(0, 0, 0, 0.1),
|
||||
var(--shadow-2xl-units-3) rgba(0, 0, 0, 0.4);
|
||||
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
--theme-transition: 0s var(--ease-in-out);
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
[data-scope="collapsible"][data-part="content"] {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
transition: all 300ms;
|
||||
transition: all var(--theme-transition);
|
||||
}
|
||||
|
||||
[data-scope="collapsible"][data-part="content"][data-state="open"] {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@
|
|||
margin-bottom: 0.618rem;
|
||||
border-radius: 12px;
|
||||
padding: 0.8rem;
|
||||
transition: border 0.3s;
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
border-color var(--theme-transition);
|
||||
}
|
||||
|
||||
& .typedata-details {
|
||||
|
|
@ -164,6 +166,9 @@
|
|||
.typeprops {
|
||||
& .typeprop-root {
|
||||
border: 1px solid hsl(var(--prop-color) / 0.6);
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
border-color var(--theme-transition);
|
||||
|
||||
&:hover {
|
||||
border: 1px solid hsl(var(--prop-color));
|
||||
|
|
@ -175,11 +180,13 @@
|
|||
|
||||
& .typeprop-name {
|
||||
color: hsl(var(--prop-link-color));
|
||||
transition: color var(--theme-transition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .typeprops {
|
||||
html.dark .typeprops,
|
||||
html:has(input#theme-manual-toggle:checked) .typeprops {
|
||||
& .typeprop-root {
|
||||
border: 1px solid hsl(var(--prop-color) / 0.3);
|
||||
|
||||
|
|
@ -193,6 +200,9 @@ html.dark .typeprops {
|
|||
.typefuncs {
|
||||
& .typefunc-root {
|
||||
border: 1px solid hsl(var(--func-color) / 0.6);
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
border-color var(--theme-transition);
|
||||
|
||||
&:hover {
|
||||
border: 1px solid hsl(var(--func-color));
|
||||
|
|
@ -204,6 +214,7 @@ html.dark .typeprops {
|
|||
|
||||
& .typefunc-name {
|
||||
color: hsl(var(--func-link-color));
|
||||
transition: color var(--theme-transition);
|
||||
}
|
||||
|
||||
& .typefunc-params {
|
||||
|
|
@ -222,7 +233,8 @@ html.dark .typeprops {
|
|||
}
|
||||
}
|
||||
|
||||
html.dark .typefuncs {
|
||||
html.dark .typefuncs,
|
||||
html:has(input#theme-manual-toggle:checked) .typefuncs {
|
||||
& .typefunc-root {
|
||||
border: 1px solid hsl(var(--func-color) / 0.3);
|
||||
|
||||
|
|
@ -236,6 +248,9 @@ html.dark .typefuncs {
|
|||
.typesignals {
|
||||
& .typesignal-root {
|
||||
border: 1px solid hsl(var(--signal-color) / 0.6);
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
border-color var(--theme-transition);
|
||||
|
||||
&:hover {
|
||||
border: 1px solid hsl(var(--signal-color));
|
||||
|
|
@ -249,6 +264,7 @@ html.dark .typefuncs {
|
|||
position: relative;
|
||||
width: max-content;
|
||||
color: hsl(var(--signal-link-color));
|
||||
transition: color var(--theme-transition);
|
||||
|
||||
& .typesignal-doclink {
|
||||
top: -12px;
|
||||
|
|
@ -274,7 +290,8 @@ html.dark .typefuncs {
|
|||
}
|
||||
}
|
||||
|
||||
html.dark .typesignals {
|
||||
html.dark .typesignals,
|
||||
html:has(input#theme-manual-toggle:checked) .typesignals {
|
||||
& .typesignal-root {
|
||||
border: 1px solid hsl(var(--signal-color) / 0.3);
|
||||
|
||||
|
|
@ -288,6 +305,9 @@ html.dark .typesignals {
|
|||
.typevariants {
|
||||
& .typevariant-root {
|
||||
border: 1px solid hsl(var(--var-color) / 0.6);
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
border-color var(--theme-transition);
|
||||
|
||||
&:hover {
|
||||
border: 1px solid hsl(var(--var-color));
|
||||
|
|
@ -301,6 +321,7 @@ html.dark .typesignals {
|
|||
position: relative;
|
||||
width: max-content;
|
||||
color: hsl(var(--var-link-color));
|
||||
transition: color var(--theme-transition);
|
||||
|
||||
& .typevariant-doclink {
|
||||
position: absolute;
|
||||
|
|
@ -313,7 +334,8 @@ html.dark .typesignals {
|
|||
}
|
||||
}
|
||||
|
||||
html.dark .typevariants {
|
||||
html.dark .typevariants,
|
||||
html:has(input#theme-manual-toggle:checked) .typevariants {
|
||||
& .typevariant-root {
|
||||
border: 1px solid hsl(var(--var-color) / 0.3);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
@import "./docs-types.css";
|
||||
|
||||
.docslayout {
|
||||
transition: background-color 0.3s;
|
||||
transition: background-color var(--theme-transition);
|
||||
}
|
||||
|
||||
.docslayout-root {
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
justify-content: safe center;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
transition: filter 0.3s;
|
||||
transition: filter var(--theme-transition);
|
||||
}
|
||||
|
||||
.docslayout-inner {
|
||||
|
|
@ -31,8 +31,9 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
:not(html.dark) > .dim-content-toc,
|
||||
:not(html.dark) > .dim-content-nav {
|
||||
html:not(.dark):not(:has(input#theme-manual-toggle:checked)) > .dim-content-toc,
|
||||
html:not(.dark):not(:has(input#theme-manual-toggle:checked))
|
||||
> .dim-content-nav {
|
||||
background-color: #909090;
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +67,7 @@
|
|||
--color-link-breadcrumbs: hsl(var(--link));
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.318rem;
|
||||
max-width: 100svw;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.heading {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@
|
|||
.nav-item {
|
||||
display: block;
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.2s ease;
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
color var(--theme-transition);
|
||||
padding: 0.4em;
|
||||
font-size: 1rem;
|
||||
|
||||
|
|
@ -39,11 +41,8 @@
|
|||
}
|
||||
|
||||
.fade {
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to right,
|
||||
#000 80%,
|
||||
transparent
|
||||
);
|
||||
mask-image: linear-gradient(to right, #000 80%, transparent);
|
||||
-webkit-mask-image: linear-gradient(to right, #000 80%, transparent);
|
||||
}
|
||||
|
||||
.nav-collapsible {
|
||||
|
|
@ -55,7 +54,9 @@
|
|||
& > div {
|
||||
& > .nav-collapse-marker,
|
||||
a {
|
||||
transition: background-color 0.2s ease;
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
color var(--theme-transition);
|
||||
}
|
||||
|
||||
& > .nav-collapse-marker {
|
||||
|
|
|
|||
|
|
@ -7,12 +7,16 @@
|
|||
|
||||
.nav-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
position: absolute;
|
||||
transition: opacity 0.6s;
|
||||
transition:
|
||||
opacity var(--theme-transition),
|
||||
transform var(--theme-transition);
|
||||
}
|
||||
|
||||
.nav-icon.active {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +54,9 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
transition: left 0.3s ease, padding 0.3s ease;
|
||||
transition:
|
||||
left 0.3s ease,
|
||||
padding 0.3s ease;
|
||||
|
||||
&.shown {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@
|
|||
--search-corners: calc(0.3125rem * var(--pagefind-ui-scale));
|
||||
--search-page-icon-size: calc(1.875rem * var(--pagefind-ui-scale));
|
||||
--search-page-icon-inline-start: calc(
|
||||
(var(--search-result-pad-inline-start) - var(--search-page-icon-size)) / 2
|
||||
(var(--search-result-pad-inline-start) - var(--search-page-icon-size)) /
|
||||
2
|
||||
);
|
||||
--search-tree-diagram-size: calc(2.5rem * var(--pagefind-ui-scale));
|
||||
--search-tree-diagram-inline-start: calc(
|
||||
(var(--search-result-pad-inline-start) - var(--search-tree-diagram-size)) /
|
||||
2
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -57,9 +58,11 @@
|
|||
|
||||
#qs_search .pagefind-ui__search-clear::before {
|
||||
content: "";
|
||||
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
-webkit-mask:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
center / 50% no-repeat;
|
||||
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
mask:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
center / 50% no-repeat;
|
||||
background-color: hsl(0deg 25% 45%);
|
||||
display: block;
|
||||
|
|
@ -166,9 +169,11 @@
|
|||
inset-inline-start: var(--search-tree-diagram-inline-start);
|
||||
width: var(--search-tree-diagram-size);
|
||||
background: hsl(var(--blue) 10% 30%);
|
||||
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m6-988H8'/%3E%3C/svg%3E")
|
||||
-webkit-mask:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m6-988H8'/%3E%3C/svg%3E")
|
||||
0% 0% / 100% no-repeat;
|
||||
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m6-988H8'/%3E%3C/svg%3E")
|
||||
mask:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m6-988H8'/%3E%3C/svg%3E")
|
||||
0% 0% / 100% no-repeat;
|
||||
}
|
||||
|
||||
|
|
@ -204,9 +209,11 @@
|
|||
inset-inline-start: var(--search-tree-diagram-inline-start);
|
||||
width: var(--search-tree-diagram-size);
|
||||
background: hsl(var(--blue) 10% 30%);
|
||||
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m'/%3E%3C/svg%3E")
|
||||
-webkit-mask:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m'/%3E%3C/svg%3E")
|
||||
0% 0% / 100% no-repeat;
|
||||
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m'/%3E%3C/svg%3E")
|
||||
mask:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m'/%3E%3C/svg%3E")
|
||||
0% 0% / 100% no-repeat;
|
||||
}
|
||||
}
|
||||
|
|
@ -219,7 +226,8 @@
|
|||
|
||||
/* default styles */
|
||||
site-search {
|
||||
--shadow-lg: 0px 25px 7px hsl(0deg, 0%, 0%, 0.03),
|
||||
--shadow-lg:
|
||||
0px 25px 7px hsl(0deg, 0%, 0%, 0.03),
|
||||
0px 16px 6px hsl(0deg, 0%, 0%, 0.1), 0px 9px 5px hsl(223deg, 13%, 10%, 0.33),
|
||||
0px 4px 4px hsl(0deg, 0%, 0%, 0.75), 0px 4px 2px hsl(0deg, 0%, 0%, 0.25);
|
||||
display: contents;
|
||||
|
|
@ -275,7 +283,8 @@ button > kbd {
|
|||
background-color: hsl(var(--blue) 15% 80%);
|
||||
}
|
||||
|
||||
html.dark button > kbd {
|
||||
html.dark button > kbd,
|
||||
html:has(input#theme-manual-toggle:checked) button > kbd {
|
||||
background-color: hsl(var(--blue) 5% 20% / 0.5);
|
||||
}
|
||||
|
||||
|
|
@ -368,7 +377,8 @@ button[data-close-modal] {
|
|||
}
|
||||
}
|
||||
|
||||
html.dark button[data-open-modal] {
|
||||
html.dark button[data-open-modal],
|
||||
html:has(input#theme-manual-toggle:checked) button[data-open-modal] {
|
||||
background-color: hsla(var(--blue) 15% 15% / 0.5);
|
||||
color: hsl(var(--blue) 40% 65%);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,28 @@
|
|||
font-size: 1.614rem;
|
||||
max-height: 500px;
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
& .toc-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
position: absolute;
|
||||
transition:
|
||||
opacity var(--theme-transition),
|
||||
transform var(--theme-transition);
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
& > svg {
|
||||
height: 100%;
|
||||
width: 24px;
|
||||
|
|
@ -61,7 +83,9 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
transition: width 0.3s ease, padding 0.3s ease;
|
||||
transition:
|
||||
width 0.3s ease,
|
||||
padding 0.3s ease;
|
||||
|
||||
&.shown {
|
||||
& .toc-content {
|
||||
|
|
@ -115,7 +139,7 @@
|
|||
margin-right: 1.272rem;
|
||||
|
||||
& .toc_a {
|
||||
transition: color 0.33s;
|
||||
transition: color var(--theme-transition);
|
||||
color: hsl(var(--toc-link));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
@import "remark-github-blockquote-alert/alert.css";
|
||||
@import "./css-config/base.css";
|
||||
@import "./css-config/animations.css";
|
||||
@import "./css-config/code.css";
|
||||
@import "./css-config/colors.css";
|
||||
|
||||
@import "./css-config/entry.css";
|
||||
@import "./main-page.css";
|
||||
|
||||
@import "./docs/nav/nav.css";
|
||||
|
|
@ -15,42 +12,69 @@
|
|||
@import "./components/featurelist.css";
|
||||
@import "./components/marquee.css";
|
||||
|
||||
.changing-theme * {
|
||||
transition: none !important;
|
||||
.theme-toggle {
|
||||
height: 24px;
|
||||
font-size: 1.614rem;
|
||||
color: hsla(var(--signal-color) / 0.7);
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: hsla(var(--signal-color) / 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* color styling */
|
||||
.header {
|
||||
background-color: hsl(var(--bg-400));
|
||||
box-shadow: 0 1px 1px 1px hsla(var(--white) 100 0 / 0.1);
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
color var(--theme-transition),
|
||||
box-shadow var(--theme-transition);
|
||||
}
|
||||
|
||||
.baselayout,
|
||||
.docslayout {
|
||||
background-color: hsl(var(--background));
|
||||
color: hsl(var(--secondary-900));
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
color var(--theme-transition);
|
||||
}
|
||||
|
||||
a {
|
||||
color: hsl(var(--link));
|
||||
text-decoration: none;
|
||||
transition: color var(--theme-transition);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .baselayout,
|
||||
html.dark .docslayout {
|
||||
html.dark .docslayout,
|
||||
html:has(input#theme-manual-toggle:checked) .baselayout,
|
||||
html:has(input#theme-manual-toggle:checked) .docslayout {
|
||||
background-color: hsl(var(--bg-900));
|
||||
color: hsl(var(--secondary-400));
|
||||
}
|
||||
|
||||
html.dark {
|
||||
html.dark,
|
||||
html:has(input#theme-manual-toggle:checked) {
|
||||
& .header {
|
||||
background-color: hsl(var(--secondary-900));
|
||||
color: hsl(var(--secondary-500));
|
||||
}
|
||||
|
||||
& .theme-toggle {
|
||||
color: hsla(var(--func-color) / 0.7);
|
||||
|
||||
&:hover {
|
||||
color: hsla(var(--func-color) / 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* layout and positioning */
|
||||
|
|
@ -65,6 +89,7 @@ html.dark {
|
|||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
.unset {
|
||||
all: unset;
|
||||
}
|
||||
|
|
@ -133,47 +158,63 @@ body.overflow-toc {
|
|||
display: block;
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
height: 24px;
|
||||
font-size: 1.614rem;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
position: relative;
|
||||
margin-top: var(--2xl);
|
||||
width: 100%;
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 2rem;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
background: hsl(var(--footer-bkg));
|
||||
transition:
|
||||
background-color var(--theme-transition),
|
||||
color var(--theme-transition);
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -1rem;
|
||||
left: 0;
|
||||
right: calc(50% + 1.25rem);
|
||||
height: 1px;
|
||||
width: calc(100% + 1rem);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
hsl(var(--footer-bkg-border)) 50%,
|
||||
hsl(var(--footer-bkg-border)) 100%
|
||||
);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: calc(50% + 1.25rem);
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
hsl(var(--footer-bkg-border)) 0%,
|
||||
transparent 100%
|
||||
);
|
||||
}
|
||||
|
||||
& .theme-toggle {
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
}
|
||||
|
||||
& a {
|
||||
color: hsl(var(--text-dark));
|
||||
transition: color 0.3s ease;
|
||||
transition: color var(--theme-transition);
|
||||
|
||||
& .hint {
|
||||
transition: color 0.3s ease;
|
||||
transition: color var(--theme-transition);
|
||||
}
|
||||
|
||||
&:nth-child(2) .hint {
|
||||
|
|
@ -223,10 +264,11 @@ footer {
|
|||
gap: 0.373rem;
|
||||
align-items: flex-start;
|
||||
font-size: 2.5rem;
|
||||
|
||||
}
|
||||
|
||||
& .changelog {
|
||||
display: flex;
|
||||
|
||||
& a {
|
||||
text-decoration: none;
|
||||
margin-inline: auto;
|
||||
|
|
|
|||
|
|
@ -45,16 +45,15 @@ h1.gradient-text {
|
|||
hsl(var(--green) 80% 42%),
|
||||
hsl(var(--blue) 80% 49%)
|
||||
);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
html.dark h1.gradient-text {
|
||||
background: linear-gradient(
|
||||
30deg,
|
||||
#42b96b,
|
||||
#4281b9
|
||||
);
|
||||
html.dark h1.gradient-text,
|
||||
html:has(input#theme-manual-toggle:checked) h1.gradient-text {
|
||||
background: linear-gradient(30deg, #42b96b, #4281b9);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
|
@ -76,7 +75,8 @@ html.dark h1.gradient-text {
|
|||
}
|
||||
}
|
||||
|
||||
html.dark .main-page_hero-text {
|
||||
html.dark .main-page_hero-text,
|
||||
html:has(input#theme-manual-toggle:checked) .main-page_hero-text {
|
||||
& h2 {
|
||||
color: hsl(var(--blue) 100% 83%);
|
||||
}
|
||||
|
|
@ -95,7 +95,9 @@ html.dark .main-page_hero-text {
|
|||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.about-break { display: none }
|
||||
.about-break {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.about-buttons {
|
||||
display: flex;
|
||||
|
|
@ -130,12 +132,13 @@ html.dark .main-page_hero-text {
|
|||
align-items: center;
|
||||
width: 100%;
|
||||
height: 3.67rem;
|
||||
border-radius: 9px;
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
border: 1px solid hsl(var(--green) 10% 10%);
|
||||
box-shadow: var(--shadow-md);
|
||||
transition:
|
||||
background-color 0.3s,
|
||||
border-color 0.3s;
|
||||
background-color var(--theme-transition),
|
||||
box-shadow var(--theme-transition),
|
||||
border-color var(--theme-transition);
|
||||
|
||||
background-color: hsl(var(--green) 38% 30%);
|
||||
color: hsl(194deg 0% 100%);
|
||||
|
|
@ -143,17 +146,22 @@ html.dark .main-page_hero-text {
|
|||
&:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
border-color: hsl(var(--green) 20% 20%);
|
||||
background-color: hsl(var(--green) 48% 40%);
|
||||
box-shadow:
|
||||
var(--shadow-md-units-1) hsla(var(--green) 48 45 / 0.08),
|
||||
var(--shadow-md-units-2) hsla(var(--green) 48 45 / 0.11),
|
||||
var(--shadow-md-units-3) hsla(var(--green) 48 45 / 0.4);
|
||||
}
|
||||
|
||||
&.main-page_bluecard {
|
||||
border-color: hsl(var(--blue) 10% 10%);
|
||||
background-color: hsl(var(--blue) 38% 30%);
|
||||
|
||||
&:hover {
|
||||
border-color: hsl(var(--blue) 20% 20%);
|
||||
background-color: hsl(var(--blue) 48% 40%);
|
||||
box-shadow:
|
||||
var(--shadow-md-units-1) hsla(var(--blue) 48 45 / 0.08),
|
||||
var(--shadow-md-units-2) hsla(var(--blue) 48 45 / 0.11),
|
||||
var(--shadow-md-units-3) hsla(var(--blue) 48 45 / 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +170,8 @@ html.dark .main-page_hero-text {
|
|||
}
|
||||
}
|
||||
|
||||
html.dark .main-page_link-card {
|
||||
html.dark .main-page_link-card,
|
||||
html:has(input#theme-manual-toggle:checked) .main-page_link-card {
|
||||
background-color: hsl(var(--green) 38% 25%);
|
||||
color: hsl(194deg 0% 100%);
|
||||
|
||||
|
|
@ -226,7 +235,15 @@ html.dark .main-page_link-card {
|
|||
flex-direction: row;
|
||||
}
|
||||
|
||||
.about-txt { max-width: 70% }
|
||||
.about-break { display: unset }
|
||||
.about-buttons { flex-direction: column }
|
||||
.about-txt {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.about-break {
|
||||
display: unset;
|
||||
}
|
||||
|
||||
.about-buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue