fix: theme switching causing constant color transitions, too much shadow on codeblocks in light theme

This commit is contained in:
Oleksandr 2026-02-17 19:02:00 +02:00
parent 8848037c63
commit 5d43f69d69
Signed by: Xanazf
GPG key ID: 821EEC32761AC17C
52 changed files with 8088 additions and 3601 deletions

View file

@ -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;

View file

@ -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>}

View file

@ -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>

View file

@ -7,9 +7,10 @@ interface Props {
}
const { title } = Astro.props;
---
<Accordion class="docs-collapsible">
<div slot="header">
<Fragment set:html={collapsibleMarker}/>
<Fragment set :html={collapsibleMarker} />
{title}
</div>
<slot />

View file

@ -10,6 +10,7 @@ interface Props {
const props = Astro.props;
---
<footer class=`${props.class ?? ""}`>
<div class="credits">
<p class="hint">Brought to you by:</p>

View file

@ -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/>
<Search />
<ThemeToggle />
<TOC title={title} headings={headings} type={type} mobile={true}/>
<TOC title={title} headings={headings} type={type} mobile={true} />
</div>
</div>

View file

@ -55,17 +55,19 @@ FloatingWindow {
\`\`\``
);
---
<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>
@ -73,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>

View file

@ -2,16 +2,17 @@
import { Icon } from "astro-icon/components";
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>
<MarqueeContent/>
<MarqueeContent />
</div>
<script src="@config/styling/marquee.ts"/>
<script src="@config/styling/marquee.ts" />

View file

@ -34,7 +34,13 @@ const videos = [
},
];
---
<div id="marquee-content" class="marquee-content" data-scroll="0" data-media-index="0">
<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`>

View file

@ -2,6 +2,7 @@
import "@pagefind/default-ui/css/ui.css";
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>

View file

@ -21,12 +21,13 @@ const { title, headings, type, mobile } = Astro.props;
const types: TypeTOC | null = type
? {
properties: Object.keys(type.properties ?? {}),
functions: (type.functions ?? []).map((f:QuickshellFunction) => f.name),
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
@ -36,5 +37,4 @@ const types: TypeTOC | null = type
mobile={mobile}
client:idle
/>
</div>
}
</div>}

View file

@ -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>

View file

@ -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>

View file

@ -17,9 +17,7 @@ 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 ?? "");
@ -40,18 +38,14 @@ function mkTree(
title,
link,
current: currentPath[pathIdx] === slug,
entries: entries?.map(entry =>
mkTree(link, pathIdx + 1, entry)
),
entries: entries?.map(entry => mkTree(link, pathIdx + 1, entry)),
};
}
function genGuideNav(base: string): NavTree[] | undefined {
const pages = guidePages
.filter(
page =>
page.id.match(`^${base}[^/]*$`) !== null &&
page.id !== "index"
page => page.id.match(`^${base}[^/]*$`) !== null && page.id !== "index"
)
.sort((a, b) => a.data.index - b.data.index)
.map(page => ({
@ -98,6 +92,7 @@ if (versionName) {
};
}
---
<nav class="navtree">
<Link
title="About"
@ -109,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
@ -125,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`}

View file

@ -32,7 +32,7 @@ const NavComponent: Component<SidebarContent> = props => {
if (
isLink ||
!isInBody ||
//@ts-expect-error
//@ts-expect-error
(isInBody && !navRef.contains(event.target as Node))
) {
setOpen(false);

View file

@ -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}/>

View file

@ -8,6 +8,7 @@ export interface Props {
const { mobile } = Astro.props;
---
<aside class=`nav-wrapper${mobile ? "-mobile" : ""} id="nav"`>
{ mobile ? (
<SidebarWrapper client:load>

View file

@ -40,7 +40,7 @@ const TableOfContents: Component<TOCProps> = props => {
if (
isLink ||
!isInBody ||
//@ts-expect-error
//@ts-expect-error
(isInBody && !tocRef.contains(event.target as Node))
) {
setOpen(false);

View file

@ -1,8 +1,5 @@
---
import type {
QMLTypeLinkObject,
QuickshellFunction,
} from "@config/_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>

View file

@ -3,6 +3,7 @@ import { getQMLTypeLink } from "@config/io/helpers";
import type {
QMLTypeLinkObject,
QuickshellProps,
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>

View file

@ -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">:&nbsp;<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">:&nbsp;<a
href={getQMLTypeLink(version!, param.type)}
>{param.type.name}</a></span>
</span>
)
})
}
</p>
) : null
}
<TypeDetails markdown={signalData.details} />
</li>
)
})}
</ul>

View file

@ -8,10 +8,9 @@ export interface Props {
const { markdown } = Astro.props;
const { version } = Astro.params;
const html = markdown
? await processMarkdown(version!, markdown)
: null;
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>

View file

@ -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" &&":"}&nbsp;
<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">&lt;</span><a href={typelink_generic}>{typename_generic}</a><span class="type-datatype">&gt;</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>

View file

@ -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>

View file

@ -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 />

View file

@ -35,79 +35,86 @@ const remarkParseAtTypes: RemarkPlugin<[]> =
(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;
};
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;
}
}
);
return root;
};
const rehypeRewriteVersionedDoclinks: RehypePlugin<[]> =
() =>

View file

@ -21,13 +21,23 @@ export const getCurrentTheme = (): ThemeProps => {
return { theme: systemTheme, system: systemTheme };
};
export const updateTheme = () => {
export const updateTheme = (transition = true) => {
const theme = getCurrentTheme();
const toggle = document.getElementById(
"theme-manual-toggle"
) as HTMLInputElement;
document.documentElement.classList.add("changing-theme");
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");
@ -37,11 +47,15 @@ export const updateTheme = () => {
if (toggle) toggle.checked = false;
}
requestAnimationFrame(() => {
if (transition) {
requestAnimationFrame(() => {
document.documentElement.classList.remove("changing-theme");
requestAnimationFrame(() => {
document.documentElement.classList.remove(
"changing-theme"
);
});
});
});
}
};
export const initTheme = () => {
@ -58,11 +72,11 @@ export const initTheme = () => {
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", updateTheme);
window.addEventListener("storage", updateTheme);
.addEventListener("change", () => updateTheme());
window.addEventListener("storage", () => updateTheme());
// initial sync
updateTheme();
updateTheme(false);
};
// auto-init on client

39
src/env.d.ts vendored
View file

@ -1,13 +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;
readonly PRODUCTION: string | undefined;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
export type { ImportMeta };
// 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;
}

View file

@ -21,7 +21,7 @@ const { title, description } = Astro.props;
class="theme-toggle-input"
style="display: none;"
aria-label="Toggle theme (light/dark)"
/>
>
<!--<Header />-->
<slot />
<script>
@ -30,4 +30,3 @@ const { title, description } = Astro.props;
</script>
</body>
</html>

View file

@ -17,7 +17,7 @@ interface Props {
}
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 = [
{
@ -57,13 +57,19 @@ for (const segment of url) {
class="theme-toggle-input"
aria-label="Toggle theme (light/dark)"
style="display: none;"
/>
<Header title={title} headings={headings} type={type}/>
>
<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"
@ -74,25 +80,27 @@ 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";
@ -101,32 +109,32 @@ for (const segment of url) {
</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 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);
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>

View file

@ -11,13 +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>

View file

@ -15,6 +15,7 @@ const {
frontmatter: { title, description },
} = Astro.props;
---
<GuideLayout title={title} description={description ?? ""} headings={headings}>
<slot/>
<slot />
</GuideLayout>

View file

@ -10,10 +10,7 @@ const versionsMd = await Promise.all(
.filter(version => version.changelog)
.map(async version => ({
version,
changelog: await processMarkdown(
version.name,
version.changelog ?? ""
),
changelog: await processMarkdown(version.name, version.changelog ?? ""),
}))
);
@ -23,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">

View file

@ -34,6 +34,7 @@ const { headings, Content } = await render(page);
// const html = await processMarkdown(version.name, page.body!);
---
<GuideLayout title={page.data.title} description="" headings={headings}>
<Content/>
<Content />
</GuideLayout>

View file

@ -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">

View file

@ -9,6 +9,15 @@ 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 => {
@ -27,21 +36,24 @@ export async function getStaticPaths() {
const { version, module, type } = Astro.props;
const superLink = type.super
? getQMLTypeLink(version.name, type.super)
: null;
const superLink = type.super ? getQMLTypeLink(version.name, type.super) : null;
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!}
@ -51,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>
)}
@ -65,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 && (
{(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 && (
{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!}
@ -89,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>

View file

@ -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}`}>

View file

@ -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}

View file

@ -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>

View file

@ -1,7 +1,6 @@
html {
font-family:
"Rubik Variable", Inter, system-ui, Avenir, Helvetica, Arial,
sans-serif;
"Rubik Variable", Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.272;
font-weight: 400;

View file

@ -86,9 +86,10 @@ pre {
}
&.shiki {
box-shadow: var(--shadow-xl);
box-shadow: var(--shadow-md);
&:hover .copy-button {
transition: background-color var(--theme-transition);
background-color: hsla(var(--blue) 85 35 / 0.07);
}
}

View file

@ -78,5 +78,5 @@ html {
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--theme-transition: 0.3s var(--ease-in-out);
--theme-transition: 0s var(--ease-in-out);
}

View file

@ -32,11 +32,9 @@
}
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 {
html:not(.dark):not(:has(input#theme-manual-toggle:checked))
> .dim-content-nav {
background-color: #909090;
}
.docs-content {

View file

@ -42,11 +42,7 @@
.fade {
mask-image: linear-gradient(to right, #000 80%, transparent);
-webkit-mask-image: linear-gradient(
to right,
#000 80%,
transparent
);
-webkit-mask-image: linear-gradient(to right, #000 80%, transparent);
}
.nav-collapsible {

View file

@ -4,47 +4,20 @@
}
#qs_search {
--search-result-spacing: calc(
1.25rem *
var(--pagefind-ui-scale)
);
--search-result-pad-inline-start: calc(
3.75rem *
var(--pagefind-ui-scale)
);
--search-result-pad-inline-end: calc(
1.25rem *
var(--pagefind-ui-scale)
);
--search-result-pad-block: calc(
0.9375rem *
var(--pagefind-ui-scale)
);
--search-result-nested-pad-block: calc(
0.625rem *
var(--pagefind-ui-scale)
);
--search-result-spacing: calc(1.25rem * var(--pagefind-ui-scale));
--search-result-pad-inline-start: calc(3.75rem * var(--pagefind-ui-scale));
--search-result-pad-inline-end: calc(1.25rem * var(--pagefind-ui-scale));
--search-result-pad-block: calc(0.9375rem * var(--pagefind-ui-scale));
--search-result-nested-pad-block: calc(0.625rem * var(--pagefind-ui-scale));
--search-corners: calc(0.3125rem * var(--pagefind-ui-scale));
--search-page-icon-size: calc(
1.875rem *
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)
) /
(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-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)
) /
(var(--search-result-pad-inline-start) - var(--search-tree-diagram-size)) /
2
);
}
@ -57,12 +30,7 @@
#qs_search
.pagefind-ui--reset
*:where(
:not(html, iframe, canvas, img, svg, video):not(
svg *,
symbol *
)
) {
*:where(:not(html, iframe, canvas, img, svg, video):not(svg *, symbol *)) {
outline: unset;
}
@ -119,18 +87,14 @@
}
#qs_search
.pagefind-ui__result-title:not(
:where(.pagefind-ui__result-nested *)
),
.pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)),
#qs_search .pagefind-ui__result-nested {
position: relative;
background-color: hsl(0deg 0% 10%);
}
#qs_search
.pagefind-ui__result-title:not(
:where(.pagefind-ui__result-nested *)
):hover,
.pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)):hover,
#qs_search
.pagefind-ui__result-title:not(
:where(.pagefind-ui__result-nested *)
@ -161,17 +125,12 @@
border-radius: 0 0 var(--search-corners) var(--search-corners);
}
#qs_search
.pagefind-ui__result-inner
> .pagefind-ui__result-title {
padding: var(--search-result-pad-block)
var(--search-result-pad-inline-end);
#qs_search .pagefind-ui__result-inner > .pagefind-ui__result-title {
padding: var(--search-result-pad-block) var(--search-result-pad-inline-end);
padding-inline-start: var(--search-result-pad-inline-start);
}
#qs_search
.pagefind-ui__result-inner
> .pagefind-ui__result-title::before {
#qs_search .pagefind-ui__result-inner > .pagefind-ui__result-title::before {
content: "";
position: absolute;
inset-block: 0;
@ -199,9 +158,7 @@
text-decoration: none;
}
#qs_search
.pagefind-ui__result-nested
.pagefind-ui__result-link::before {
#qs_search .pagefind-ui__result-nested .pagefind-ui__result-link::before {
content: unset;
}
@ -236,9 +193,7 @@
overflow-wrap: anywhere;
}
#qs_search
.pagefind-ui__result-inner
> .pagefind-ui__result-excerpt {
#qs_search .pagefind-ui__result-inner > .pagefind-ui__result-excerpt {
display: inline-block;
position: relative;
background: hsl(0deg 0% 10%);
@ -273,18 +228,8 @@
site-search {
--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
);
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;
}
@ -433,8 +378,7 @@ button[data-close-modal] {
}
html.dark button[data-open-modal],
html:has(input#theme-manual-toggle:checked)
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%);