port docs to sveltekit (very broken)
31
docs/.gitignore
vendored
|
|
@ -1,12 +1,23 @@
|
|||
pids
|
||||
logs
|
||||
node_modules
|
||||
npm-debug.log
|
||||
coverage/
|
||||
run
|
||||
dist
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
.nyc_output
|
||||
.basement
|
||||
config.local.js
|
||||
basement_dist
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
|
|
|||
1
docs/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
engine-strict=true
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# PluralKit docs
|
||||
The documentation is built using [Vuepress](https://vuepress.vuejs.org/). All website content is located in the `content/` subdirectory.
|
||||
|
||||
Most site parameters, including the sidebar layout, are defined in `content/.vuepress/config.js`. Some additional CSS is defined in `content/.vuepress/styles`.
|
||||
|
||||
## Building
|
||||
First, install [Node.js](https://nodejs.org/en/download/) and [Yarn](https://classic.yarnpkg.com/en/). Then, run the `dev` command:
|
||||
|
||||
```sh
|
||||
$ yarn
|
||||
$ yarn dev
|
||||
```
|
||||
|
||||
This will start a development server on http://localhost:8080/. Note that changes to the sidebar or similar generally need a full restart (Ctrl-C) to take effect, while content-only changes will hot-reload.
|
||||
|
||||
For a full HTML build, run `yarn build`. Files will be output in `content/.vuepress/dist` by default.
|
||||
|
||||
## Deployment
|
||||
The docs are deployed using [Netlify](https://www.netlify.com/) with CI.
|
||||
|
|
@ -467,7 +467,7 @@ Features:
|
|||
|
||||
Bugfixes:
|
||||
- fixed importing pronouns and message count
|
||||
- fixed looking up messages with a discord canary link (and then fixed looking up normal links >.<)
|
||||
- fixed looking up messages with a discord canary link (and then fixed looking up normal links >.\<)
|
||||
- fixed a few "internal error" messages and other miscellaneous bugs
|
||||
(also, `pk;member <name> soulscream` is a semi-secret command for the time being, if you know what this means, have fun :3 🍬)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
app = "pluralkit-docs"
|
||||
primary_region = "arn"
|
||||
primary_region = "sjc"
|
||||
http_service.internal_port = 8000
|
||||
|
|
|
|||
|
|
@ -1,20 +1,38 @@
|
|||
{
|
||||
"name": "pluralkit-docs",
|
||||
"private": true,
|
||||
"description": "Documentation for PluralKit",
|
||||
"scripts": {
|
||||
"dev": "vuepress dev content",
|
||||
"build": "vuepress build content"
|
||||
},
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@vuepress/plugin-back-to-top": "1.8.2",
|
||||
"markdown-it-custom-header-link": "^1.0.5",
|
||||
"vuepress": "1.8.2",
|
||||
"vuepress-plugin-clean-urls": "1.1.2",
|
||||
"vuepress-plugin-dehydrate": "1.1.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"vuepress-theme-default-prefers-color-scheme": "2.0.0"
|
||||
}
|
||||
"name": "docs",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "^5.4.0",
|
||||
"@sveltejs/kit": "^2.49.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||
"@tabler/icons-svelte": "^3.36.0",
|
||||
"@tailwindcss/postcss": "^4.1.18",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@types/node": "^25.0.3",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"daisyui": "^4.12.24",
|
||||
"nprogress": "^0.2.0",
|
||||
"postcss": "^8.5.3",
|
||||
"sass": "^1.77.8",
|
||||
"svelte": "^5.45.6",
|
||||
"svelte-check": "^4.3.4",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.2.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"mdsvex": "^0.12.6"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2356
docs/pnpm-lock.yaml
generated
Normal file
6
docs/postcss.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
13
docs/src/app.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
11
docs/src/app.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
27
docs/src/components/Footer.svelte
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<script lang="ts">
|
||||
import { env } from "$env/dynamic/public"
|
||||
|
||||
// @ts-ignore
|
||||
const version = __COMMIT_HASH__.slice(1, __COMMIT_HASH__.length - 1)
|
||||
</script>
|
||||
|
||||
<footer class="footer items-center p-4">
|
||||
<nav class="grid-flow-col gap-4">
|
||||
<span
|
||||
>Commit: <a
|
||||
aria-label="View commit on github"
|
||||
class="underline"
|
||||
href={`${
|
||||
env.PUBLIC_REPOSITORY_URL
|
||||
? env.PUBLIC_REPOSITORY_URL
|
||||
: "https://github.com/Draconizations/pk-dashboard-sveltekit"
|
||||
}/commit/${version}`}>{version}</a
|
||||
>
|
||||
</span>
|
||||
</nav>
|
||||
<nav class="grid-flow-col gap-4 md:place-self-center md:justify-self-end">
|
||||
<a class="link-hover" href="/about">About</a>
|
||||
<a class="link-hover" href="/privacy">Privacy</a>
|
||||
<a class="link-hover" href="/changelog">Changelog</a>
|
||||
</nav>
|
||||
</footer>
|
||||
139
docs/src/components/NavBar.svelte
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<script lang="ts">
|
||||
import {
|
||||
IconMenu2,
|
||||
IconBook,
|
||||
IconBrandDiscord,
|
||||
IconShare3,
|
||||
IconUsers,
|
||||
IconBoxMultiple,
|
||||
IconAdjustments,
|
||||
IconPaint,
|
||||
IconLogout,
|
||||
IconAddressBook,
|
||||
IconHome,
|
||||
IconSettings,
|
||||
IconStatusChange,
|
||||
IconInfoCircle,
|
||||
IconDashboard,
|
||||
IconLayoutDashboard,
|
||||
} from "@tabler/icons-svelte"
|
||||
|
||||
let userMenu: HTMLDetailsElement
|
||||
let navbarMenu: HTMLDetailsElement
|
||||
</script>
|
||||
|
||||
<div class="navbar bg-base-100">
|
||||
<div class="navbar-start flex-1">
|
||||
<details class="dropdown" bind:this={navbarMenu}>
|
||||
<summary class="btn btn-ghost md:hidden">
|
||||
<IconMenu2 />
|
||||
</summary>
|
||||
<ul class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52">
|
||||
<li>
|
||||
<a href="/" onclick={() => (navbarMenu.open = false)}>
|
||||
<IconHome /> Homepage
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://discord.com/oauth2/authorize?client_id=466378653216014359&scope=bot%20applications.commands&permissions=536995904"
|
||||
onclick={() => (navbarMenu.open = false)}
|
||||
>
|
||||
<IconShare3 /> Invite bot
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://pluralkit.me/" onclick={() => (navbarMenu.open = false)}
|
||||
><IconBook /> Documentation</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discord.gg/PczBt78" onclick={() => (navbarMenu.open = false)}
|
||||
><IconBrandDiscord /> Support server</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
<a href="/" class="hidden text-xl btn btn-ghost md:inline-flex">PluralKit</a>
|
||||
</div>
|
||||
<div class="hidden navbar-center md:flex">
|
||||
<ul class="px-1 menu menu-horizontal">
|
||||
<li><a href="https://dash.pluralkit.me/"><IconLayoutDashboard /> Web dashboard</a></li>
|
||||
<li><a href="https://discord.gg/PczBt78"><IconBrandDiscord /> Support server</a></li>
|
||||
<li>
|
||||
<a
|
||||
href="https://discord.com/oauth2/authorize?client_id=466378653216014359&scope=bot%20applications.commands&permissions=536995904"
|
||||
>
|
||||
<IconShare3 /> Invite bot
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="https://status.pluralkit.me"><IconInfoCircle /> Status</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end w-auto">
|
||||
<a href="/settings#theme" class="mr-4 tooltip tooltip-bottom" data-tip="Change theme"
|
||||
><IconPaint /></a
|
||||
>
|
||||
{#if false /*dash.user*/}
|
||||
<details class="dropdown dropdown-left" bind:this={userMenu}>
|
||||
<summary class="mr-2 list-none">
|
||||
{#if false /*dash.user.avatar_url*/}
|
||||
<div class="avatar">
|
||||
<div class="w-12 rounded-full">
|
||||
<!-- <img alt="your system avatar" src={dash.user.avatar_url} /> -->
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="avatar">
|
||||
<div class="w-12 rounded-full">
|
||||
<img alt="An icon of myriad" src="/myriad_write.png" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</summary>
|
||||
<ul
|
||||
data-sveltekit-preload-data="tap"
|
||||
class="menu menu-sm menu-dropdown dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-36"
|
||||
>
|
||||
<!-- <li>
|
||||
<a href={`/dash/${dash.user?.id}?tab=overview`} onclick={() => (userMenu.open = false)}
|
||||
><IconAdjustments /> Overview</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/dash/${dash.user?.id}?tab=system`} onclick={() => (userMenu.open = false)}
|
||||
><IconAddressBook /> System</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/dash/${dash.user?.id}?tab=members`} onclick={() => (userMenu.open = false)}
|
||||
><IconUsers /> Members</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href={`/dash/${dash.user?.id}?tab=groups`} onclick={() => (userMenu.open = false)}
|
||||
><IconBoxMultiple /> Groups</a
|
||||
>
|
||||
</li> -->
|
||||
<hr class="my-2" />
|
||||
<li>
|
||||
<a href="/settings/general" onclick={() => (userMenu.open = false)}
|
||||
><IconSettings /> Settings</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<form method="post" action="/?/logout">
|
||||
<IconLogout />
|
||||
<input
|
||||
onclick={() => (userMenu.open = false)}
|
||||
class="text-error w-min"
|
||||
type="submit"
|
||||
value="Logout"
|
||||
/>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
107
docs/src/components/Sidebar.svelte
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/stores";
|
||||
|
||||
const mdModules = import.meta.glob('/content/**/*.md', { eager: true }) as Record<string, { metadata?: { title?: string; permalink?: string } }>;
|
||||
|
||||
const pathToTitle: Record<string, string> = {};
|
||||
for (const [filePath, mod] of Object.entries(mdModules)) {
|
||||
const urlPath = filePath
|
||||
.replace('/content', '')
|
||||
.replace(/\/index\.md$/, '')
|
||||
.replace(/\.md$/, '');
|
||||
|
||||
if (mod.metadata?.title) {
|
||||
pathToTitle[urlPath || '/'] = mod.metadata.title;
|
||||
}
|
||||
}
|
||||
|
||||
function getTitle(path: string): string {
|
||||
return pathToTitle[path] || path.split('/').pop() || path;
|
||||
}
|
||||
|
||||
const sidebar = [
|
||||
{
|
||||
title: "Home",
|
||||
href: "/",
|
||||
},
|
||||
{
|
||||
title: "Add to your server",
|
||||
href: "https://discord.com/oauth2/authorize?client_id=466378653216014359&scope=bot%20applications.commands&permissions=536995904",
|
||||
},
|
||||
{
|
||||
title: "Updates",
|
||||
sidebarDepth: 1,
|
||||
children: [
|
||||
"/posts",
|
||||
"/changelog",
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Documentation",
|
||||
sidebarDepth: 2,
|
||||
children: [
|
||||
"/getting-started",
|
||||
"/user-guide",
|
||||
"/command-list",
|
||||
"/privacy-policy",
|
||||
"/terms-of-service",
|
||||
"/faq",
|
||||
"/tips-and-tricks"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "For server staff",
|
||||
children: [
|
||||
"/staff/permissions",
|
||||
"/staff/moderation",
|
||||
"/staff/disabling",
|
||||
"/staff/logging",
|
||||
"/staff/compatibility",
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "API Documentation",
|
||||
children: [
|
||||
"/api/changelog",
|
||||
"/api/reference",
|
||||
"/api/endpoints",
|
||||
"/api/models",
|
||||
"/api/errors",
|
||||
"/api/dispatch"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Join the support server",
|
||||
href: "https://discord.gg/PczBt78",
|
||||
},
|
||||
];
|
||||
|
||||
function isActive(href: string): boolean {
|
||||
return $page.url.pathname === href;
|
||||
}
|
||||
</script>
|
||||
|
||||
<aside class="w-80 bg-base-200 p-4 overflow-y-auto shrink-0 min-h-0">
|
||||
<ul class="menu w-full">
|
||||
{#each sidebar as item}
|
||||
{#if item.children}
|
||||
<li class="menu-title flex flex-row items-center gap-2 mt-4">
|
||||
{item.title}
|
||||
</li>
|
||||
{#each item.children as child}
|
||||
<li>
|
||||
<a href={child} class:active={isActive(child)}>
|
||||
{getTitle(child)}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
{:else}
|
||||
<li>
|
||||
<a href={item.href} class:active={isActive(item.href)}>
|
||||
{item.title}
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
{/each}
|
||||
</ul>
|
||||
</aside>
|
||||
212
docs/src/lib/app.scss
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@layer components {
|
||||
hr {
|
||||
@apply border-muted/50;
|
||||
}
|
||||
|
||||
.btn-menu {
|
||||
@apply px-4 py-2 h-auto min-h-0 justify-start;
|
||||
}
|
||||
|
||||
.box {
|
||||
@apply rounded-xl bg-base-200 p-4;
|
||||
}
|
||||
|
||||
.menu :where(li:not(.menu-title) > :not(ul):not(details):not(.menu-title)),
|
||||
.menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
|
||||
@apply select-text;
|
||||
}
|
||||
|
||||
.tabs-lifted.tabs-box > .tab.tab-active:not(.tab-disabled):not([disabled]) {
|
||||
@apply bg-base-200;
|
||||
}
|
||||
|
||||
.tabs-lifted.tabs-box .tab.tab-active:not(.tab-disabled):not([disabled])::before,
|
||||
.tabs-lifted.tabs-box .tab.tab-active:not(.tab-disabled):not([disabled]):first-child::before,
|
||||
.tabs-lifted.tabs-box .tab.tab-active:not(.tab-disabled):not([disabled]):last-child::before {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* start of discord markdown styling */
|
||||
.discord-markdown {
|
||||
blockquote {
|
||||
@apply pl-3 border-l-4 border-muted/50;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-disc pl-4;
|
||||
}
|
||||
|
||||
ol {
|
||||
@apply list-decimal pl-4;
|
||||
}
|
||||
|
||||
.d-emoji {
|
||||
@apply h-4 w-auto inline;
|
||||
}
|
||||
|
||||
.d-spoiler {
|
||||
@apply bg-base-content text-base-content;
|
||||
border-radius: 4px;
|
||||
transition-delay: 6000s;
|
||||
|
||||
&::selection {
|
||||
@apply text-base-content;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply bg-base-300;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
@apply px-1 text-sm rounded-sm bg-base-200;
|
||||
}
|
||||
|
||||
pre > code {
|
||||
@apply py-1 px-2 md:px-3 md:py-2 rounded-xl;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply link-primary;
|
||||
}
|
||||
|
||||
small {
|
||||
@apply block text-muted;
|
||||
}
|
||||
}
|
||||
|
||||
/* end of discord markdown styling */
|
||||
|
||||
/* button styling! */
|
||||
.btn {
|
||||
@apply font-normal;
|
||||
}
|
||||
|
||||
/* daisyUI applies some styling to lists in .menu that we don't want */
|
||||
/* so we reset them here */
|
||||
:where(.menu li),
|
||||
:where(.menu ul) {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.discord-markdown ul {
|
||||
position: static;
|
||||
white-space: normal;
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
.discord-markdown li {
|
||||
position: static;
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
.menu .discord-markdown :where(li:not(.menu-title) > :not(ul, details, .menu-title, .btn)),
|
||||
.menu .discord-markdown :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
|
||||
display: unset;
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
/* end of the .menu reset */
|
||||
}
|
||||
|
||||
[data-theme="dark"],
|
||||
[data-theme="light"],
|
||||
[data-theme="acid"],
|
||||
[data-theme="cotton"],
|
||||
[data-theme="autumn"],
|
||||
[data-theme="coffee"] {
|
||||
--sv-min-height: 40px;
|
||||
--sv-bg: var(--fallback-b1, oklch(var(--b1) / var(--tw-bg-opacity)));
|
||||
--sv-disabled-bg: var(--fallback-b3, oklch(var(--b3) / var(--tw-bg-opacity)));
|
||||
--sv-border: 1px solid oklch(var(--muted) / 0.5);
|
||||
--sv-border-radius: 6px;
|
||||
--sv-general-padding: 0.25rem;
|
||||
--sv-control-bg: var(--sv-bg);
|
||||
--sv-item-wrap-padding: 3px 3px 3px 6px;
|
||||
--sv-item-selected-bg: var(--fallback-b3, oklch(var(--b3) / var(--tw-bg-opacity)));
|
||||
--sv-item-btn-color: var(--fallback-bc, oklch(var(--bc) / 1));
|
||||
--sv-item-btn-color-hover: var(
|
||||
--fallback-bc,
|
||||
oklch(var(--bc) / 0.6)
|
||||
); /* same as icon-color-hover in default theme */
|
||||
--sv-item-btn-bg: transparent;
|
||||
--sv-item-btn-bg-hover: transparent;
|
||||
--sv-icon-color: var(--sv-item-btn-color);
|
||||
--sv-icon-color-hover: var(--sv-item-btn-color-hover);
|
||||
--sv-icon-bg: transparent;
|
||||
--sv-icon-size: 20px;
|
||||
--sv-separator-bg: transparent;
|
||||
--sv-btn-border: 0;
|
||||
--sv-placeholder-color: transparent;
|
||||
--sv-dropdown-bg: var(--sv-bg);
|
||||
--sv-dropdown-offset: 1px;
|
||||
--sv-dropdown-border: 1px solid oklch(var(--muted) / 0.5);
|
||||
--sv-dropdown-width: auto;
|
||||
--sv-dropdown-shadow: none;
|
||||
--sv-dropdown-height: 320px;
|
||||
--sv-dropdown-active-bg: var(--fallback-b3, oklch(var(--b3) / var(--tw-bg-opacity)));
|
||||
--sv-dropdown-selected-bg: oklch(var(--p) / 0.2);
|
||||
--sv-create-kbd-border: none;
|
||||
--sv-create-kbd-bg: transparent;
|
||||
--sv-create-disabled-bg: transparent;
|
||||
--sv-loader-border: none;
|
||||
--sv-item-wrap-padding: 0.375rem 0.25rem;
|
||||
}
|
||||
|
||||
.join-item.svelecte-control-pk {
|
||||
--sv-min-height: 2rem;
|
||||
|
||||
.sv-control {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.group-control {
|
||||
--sv-dropdown-active-bg: transparent;
|
||||
--sv-item-wrap-padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.group-control .option {
|
||||
width: calc(100% + 0.5rem);
|
||||
}
|
||||
|
||||
.sv-item--wrap {
|
||||
border-radius: 4px;
|
||||
padding: 0.25rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sv-item--wrap.in-dropdown {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sv-item--wrap.in-dropdown:not(:last-child)::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
border-bottom: 1px solid oklch(var(--muted) / 0.5);
|
||||
}
|
||||
|
||||
.sv-dropdown-scroll {
|
||||
padding: 0 0.75rem !important;
|
||||
}
|
||||
|
||||
.svelecte {
|
||||
flex: auto !important;
|
||||
}
|
||||
1
docs/src/lib/assets/favicon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
docs/src/lib/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
// place files you want to import through the `$lib` alias in this folder.
|
||||
77
docs/src/lib/nprogress.scss
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#themed-container {
|
||||
--nprogress-color: var(--fallback-p, oklch(var(--p) / 1));
|
||||
}
|
||||
|
||||
/* Make clicks pass-through */
|
||||
#nprogress {
|
||||
pointer-events: none;
|
||||
|
||||
.bar {
|
||||
background: var(--nprogress-color);
|
||||
|
||||
position: fixed;
|
||||
z-index: 1031;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fancy blur effect */
|
||||
/* #nprogress .peg {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 10px var(--nprogress-color), 0 0 5px var(--nprogress-color);
|
||||
opacity: 1.0;
|
||||
|
||||
-webkit-transform: rotate(3deg) translate(0px, -4px);
|
||||
-ms-transform: rotate(3deg) translate(0px, -4px);
|
||||
transform: rotate(3deg) translate(0px, -4px);
|
||||
} */
|
||||
|
||||
/* Remove these to get rid of the spinner */
|
||||
/* #nprogress .spinner {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 1031;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
#nprogress .spinner-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
box-sizing: border-box;
|
||||
|
||||
border: solid 2px transparent;
|
||||
border-top-color: var(--nprogress-color);
|
||||
border-left-color: var(--nprogress-color);
|
||||
border-radius: 50%;
|
||||
|
||||
-webkit-animation: nprogress-spinner 400ms linear infinite;
|
||||
animation: nprogress-spinner 400ms linear infinite;
|
||||
}
|
||||
|
||||
.nprogress-custom-parent {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nprogress-custom-parent #nprogress .spinner,
|
||||
.nprogress-custom-parent #nprogress .bar {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@-webkit-keyframes nprogress-spinner {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
@keyframes nprogress-spinner {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
} */
|
||||
64
docs/src/routes/+layout.svelte
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<script lang="ts">
|
||||
import { browser } from "$app/environment"
|
||||
import NavBar from "$components/NavBar.svelte"
|
||||
import Sidebar from "$components/Sidebar.svelte"
|
||||
import "$lib/app.scss"
|
||||
import "$lib/nprogress.scss"
|
||||
import type { LayoutData } from "./$types"
|
||||
import Footer from "$components/Footer.svelte"
|
||||
import { page } from "$app/stores"
|
||||
import { navigating } from "$app/stores"
|
||||
import nprogress from "nprogress"
|
||||
// import apiClient from "$api"
|
||||
|
||||
export let data: LayoutData
|
||||
|
||||
// if (browser) {
|
||||
// window.api = apiClient(fetch, data.apiBaseUrl)
|
||||
// }
|
||||
|
||||
if (data.token && browser) {
|
||||
localStorage.setItem("pk-token", data.token)
|
||||
} else if (browser) {
|
||||
localStorage.removeItem("pk-token")
|
||||
}
|
||||
|
||||
nprogress.configure({
|
||||
parent: "#themed-container",
|
||||
})
|
||||
|
||||
$: {
|
||||
if ($navigating) nprogress.start()
|
||||
else if (!$navigating) nprogress.done()
|
||||
}
|
||||
|
||||
// dash.initUser(data.system)
|
||||
</script>
|
||||
|
||||
<div
|
||||
id="themed-container"
|
||||
class="max-w-screen h-screen bg-base-100 flex flex-col"
|
||||
data-theme="coffee"
|
||||
>
|
||||
<NavBar />
|
||||
<div class="flex flex-row flex-1 min-h-0">
|
||||
<Sidebar />
|
||||
<main class="flex-1 overflow-y-auto min-h-0">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
<svelte:head>
|
||||
<title>PluralKit | {$page.data?.meta?.title ?? "Home"}</title>
|
||||
<meta
|
||||
property="og:title"
|
||||
content={`PluralKit | ${$page.data?.meta?.ogTitle ?? "Web Dashboard"}`}
|
||||
/>
|
||||
<meta property="theme-color" content={`#${$page.data?.meta?.color ?? "da9317"}`} />
|
||||
<meta
|
||||
property="og:description"
|
||||
content={$page.data?.meta?.ogDescription ?? "PluralKit's official dashboard."}
|
||||
/>
|
||||
</svelte:head>
|
||||
7
docs/src/routes/[...slug]/+page.svelte
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<script>
|
||||
let { data } = $props();
|
||||
</script>
|
||||
|
||||
<div class="max-w-full bg-base-200 prose">
|
||||
<div class="m-5" style="max-width: 900px"><data.PageContent /></div>
|
||||
</div>
|
||||
16
docs/src/routes/[...slug]/+page.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
|
||||
const pages = import.meta.glob('/content/**/*.md', { eager: true }) as Record<string, { default: unknown }>;
|
||||
|
||||
export async function load({ params }) {
|
||||
const slug = params.slug || 'index';
|
||||
|
||||
const page = pages[`/content/${slug}.md`] || pages[`/content/${slug}/index.md`];
|
||||
if (!page) {
|
||||
throw error(404, `Page not found: ${slug}`);
|
||||
}
|
||||
|
||||
return {
|
||||
PageContent: page.default
|
||||
};
|
||||
}
|
||||
1
docs/src/routes/layout.css
Normal file
|
|
@ -0,0 +1 @@
|
|||
@import 'tailwindcss';
|
||||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 664 KiB After Width: | Height: | Size: 664 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
26
docs/svelte.config.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import adapter from '@sveltejs/adapter-node';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
import { mdsvex } from 'mdsvex';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://svelte.dev/docs/kit/integrations
|
||||
// for more information about preprocessors
|
||||
preprocess: [
|
||||
mdsvex({
|
||||
extensions: [".md"]
|
||||
}),
|
||||
vitePreprocess(),
|
||||
],
|
||||
extensions: [".svelte", ".md"],
|
||||
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
alias: {
|
||||
$components: "src/components",
|
||||
$lib: "src/lib",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
113
docs/tailwind.config.js
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import daisyui from "daisyui"
|
||||
import typography from "@tailwindcss/typography"
|
||||
import { light, dark, night, autumn, coffee, halloween, pastel } from "daisyui/src/theming/themes"
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
plugins: [typography, daisyui],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
muted: "oklch(var(--muted) / <alpha-value>)",
|
||||
},
|
||||
},
|
||||
},
|
||||
daisyui: {
|
||||
themes: [
|
||||
{
|
||||
// cool light
|
||||
light: {
|
||||
...light,
|
||||
primary: "#da9317",
|
||||
secondary: "#9e66ff",
|
||||
accent: "#22ded8",
|
||||
// DARK BUTTONS
|
||||
/*
|
||||
"--muted": "69.38% 0.01 252.85",
|
||||
"base-200": "#ededed",
|
||||
"base-300": "#e1e3e3",
|
||||
"primary-content": "#090101",
|
||||
"neutral-content": "#f9fcff",
|
||||
"base-content": "10161e",
|
||||
"secondary-content": "fafafa"
|
||||
*/
|
||||
// LIGHT BUTTONS
|
||||
"--muted": "59.37% 0.01 252.85",
|
||||
"base-200": "#ededed",
|
||||
"base-300": "#e5e7e7",
|
||||
"primary-content": "#090101",
|
||||
neutral: "#f8f8f8",
|
||||
"neutral-content": "#040507",
|
||||
"base-content": "10161e",
|
||||
"secondary-content": "#090101",
|
||||
},
|
||||
// cool dark
|
||||
dark: {
|
||||
...dark,
|
||||
primary: "#da9317",
|
||||
secondary: "#ae81fc",
|
||||
accent: "#6df1fc",
|
||||
"--muted": "59.37% 0.0117 254.07",
|
||||
"base-100": "#22262b",
|
||||
"base-200": "#191c1f",
|
||||
"base-300": "#17191b",
|
||||
"base-content": "#ced3dc",
|
||||
neutral: "#33383e",
|
||||
"neutral-content": "#e1e2e3",
|
||||
},
|
||||
// bright dark
|
||||
acid: {
|
||||
...night,
|
||||
primary: "#49c701",
|
||||
secondary: "#00c6cf",
|
||||
accent: "#f29838",
|
||||
"base-100": "#1a2433",
|
||||
"base-200": "#101a27",
|
||||
"base-300": "#111724",
|
||||
neutral: "#242e41",
|
||||
"--muted": "60.8% 0.05 272",
|
||||
},
|
||||
// bright light (trans rights!)
|
||||
cotton: {
|
||||
...pastel,
|
||||
primary: "#ff69a8",
|
||||
secondary: "#63a7f9",
|
||||
accent: "#f8b939",
|
||||
neutral: "#f8f8f8",
|
||||
"base-200": "#eeecf1",
|
||||
"base-300": "#e2e1e7",
|
||||
"--muted": "59% 0.01 252.85",
|
||||
"--rounded-btn": "0.5rem",
|
||||
},
|
||||
// warm light
|
||||
autumn: {
|
||||
...autumn,
|
||||
primary: "#e38010",
|
||||
success: "#2c7866",
|
||||
"success-content": "#eeeeee",
|
||||
error: "#97071a",
|
||||
"error-content": "#eeeeee",
|
||||
neutral: "#ebebeb",
|
||||
"neutral-content": "#141414",
|
||||
"base-100": "#fcfcfc",
|
||||
"--muted": "67.94% 0.01 39.18",
|
||||
},
|
||||
// warm dark
|
||||
coffee: {
|
||||
...halloween,
|
||||
secondary: "#bc4b2b",
|
||||
accent: coffee.accent,
|
||||
primary: coffee.primary,
|
||||
info: "#3499c0",
|
||||
neutral: "#120f12",
|
||||
"neutral-content": "#dfe0de",
|
||||
"base-200": "#1a1a1a",
|
||||
"base-300": "#181818",
|
||||
"base-content": "#d9dbd8",
|
||||
"--muted": "57.65% 0 54",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
20
docs/tsconfig.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rewriteRelativeImportExtensions": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
// To make changes to top-level options such as include and exclude, we recommend extending
|
||||
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
||||
}
|
||||
18
docs/vite.config.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { mdsvex } from 'mdsvex';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
import { execSync } from "node:child_process"
|
||||
const hash = execSync("git rev-parse --short HEAD").toString().trim()
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit(), mdsvex({ extension: ".md" })],
|
||||
server: {
|
||||
fs: {
|
||||
allow: ["."]
|
||||
}
|
||||
},
|
||||
define: {
|
||||
__COMMIT_HASH__: JSON.stringify("_" + hash),
|
||||
},
|
||||
})
|
||||