squash and nuke dev
This commit is contained in:
parent
1f1444eb65
commit
e42985d6e6
93 changed files with 33825 additions and 7830 deletions
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue