Run prettier

This commit is contained in:
venashial 2022-06-04 00:46:23 -07:00
parent 597c071c3d
commit c9ec9f14de
49 changed files with 1515 additions and 1469 deletions

15
.prettierignore Normal file
View File

@ -0,0 +1,15 @@
.DS_Store
node_modules
/.svelte-kit
/package
.mf/
build/
.idea/
.vscode/
.vercel_build_output
.pnpm-debug.log
generated/
.pnpm-store/
locales/
pnpm-lock.yaml
.nuxt/

15
.vscode/settings.json vendored
View File

@ -1,4 +1,19 @@
{ {
"prettier.endOfLine": "lf",
"cSpell.words": ["unplugin"],
"gitlens.showWelcomeOnInstall": false,
"gitlens.showWhatsNewAfterUpgrades": false,
"gitlens.plusFeatures.enabled": false,
"gitlens.currentLine.enabled": false,
"gitlens.currentLine.pullRequests.enabled": false,
"gitlens.currentLine.scrollable": true,
"gitlens.codeLens.enabled": false,
"gitlens.hovers.enabled": false,
"svelte.enable-ts-plugin": true,
"svelte.ask-to-enable-ts-plugin": false,
"yaml.schemas": {
"https://json.schemastore.org/github-workflow.json": "file:///Users/sha/Code/Modrinth/knossos/.github/workflows/deploy.yml"
},
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnPaste": true, "editor.formatOnPaste": true,

View File

@ -10,8 +10,8 @@
"prepare": "svelte-kit sync", "prepare": "svelte-kit sync",
"check": "svelte-check --tsconfig ./tsconfig.json", "check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", "lint": "prettier --ignore-path .prettierignore --check --plugin-search-dir=. . && eslint --ignore-path .prettierignore .",
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ." "format": "prettier --ignore-path .prettierignore --write --plugin-search-dir=. ."
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-static": "^1.0.0-next.29", "@sveltejs/adapter-static": "^1.0.0-next.29",
@ -25,6 +25,7 @@
"mdsvexamples": "^0.3.0", "mdsvexamples": "^0.3.0",
"nodemon": "^2.0.15", "nodemon": "^2.0.15",
"prettier": "^2.6.2", "prettier": "^2.6.2",
"prettier-plugin-svelte": "^2.7.0",
"sveld": "^0.13.4", "sveld": "^0.13.4",
"svelte": "^3.48.0", "svelte": "^3.48.0",
"svelte-check": "^2.2.6", "svelte-check": "^2.2.6",

30
pnpm-lock.yaml generated
View File

@ -36,6 +36,7 @@ specifiers:
postcss-pxtorem: ^6.0.0 postcss-pxtorem: ^6.0.0
postcss-strip-inline-comments: ^0.1.5 postcss-strip-inline-comments: ^0.1.5
prettier: ^2.6.2 prettier: ^2.6.2
prettier-plugin-svelte: ^2.7.0
sanitize.css: ^13.0.0 sanitize.css: ^13.0.0
sveld: ^0.13.4 sveld: ^0.13.4
svelte: ^3.48.0 svelte: ^3.48.0
@ -84,7 +85,7 @@ dependencies:
devDependencies: devDependencies:
'@sveltejs/adapter-static': 1.0.0-next.29 '@sveltejs/adapter-static': 1.0.0-next.29
'@sveltejs/kit': 1.0.0-next.345_svelte@3.48.0 '@sveltejs/kit': 1.0.0-next.348_svelte@3.48.0
'@typescript-eslint/eslint-plugin': 5.14.0_4p27j37cxves4nxlnqogdhp4ta '@typescript-eslint/eslint-plugin': 5.14.0_4p27j37cxves4nxlnqogdhp4ta
'@typescript-eslint/parser': 5.14.0_e6rt7vlgxfprtuallp2t3cvyi4 '@typescript-eslint/parser': 5.14.0_e6rt7vlgxfprtuallp2t3cvyi4
eslint: 7.32.0 eslint: 7.32.0
@ -94,6 +95,7 @@ devDependencies:
mdsvexamples: 0.3.0 mdsvexamples: 0.3.0
nodemon: 2.0.15 nodemon: 2.0.15
prettier: 2.6.2 prettier: 2.6.2
prettier-plugin-svelte: 2.7.0_kkjbqzpydplecjtkxrgomroeru
sveld: 0.13.4_jw3wiphoy34i6ad2hx6ga3jifa sveld: 0.13.4_jw3wiphoy34i6ad2hx6ga3jifa
svelte: 3.48.0 svelte: 3.48.0
svelte-check: 2.4.5_2pvebpkgu3ohgo43qaf5qmcxwm svelte-check: 2.4.5_2pvebpkgu3ohgo43qaf5qmcxwm
@ -758,14 +760,14 @@ packages:
tiny-glob: 0.2.9 tiny-glob: 0.2.9
dev: true dev: true
/@sveltejs/kit/1.0.0-next.345_svelte@3.48.0: /@sveltejs/kit/1.0.0-next.348_svelte@3.48.0:
resolution: {integrity: sha512-2nLZoXZ02uXMSxqRAMRCr/J4aCphqgKLxEhRRyh3c3aWLAjWiDWLDcvSB770eHt3y0MkYrTvp7JrDF7RhfyuBA==} resolution: {integrity: sha512-K9dfgzIbotWmbcdCsQ6ROGs9R+bsGWwmSdN6l6km1QV5esQehqg1UYHGD9q0VJsg4rJg/zmKVBYo0oBquSHPZw==}
engines: {node: '>=16.7'} engines: {node: '>=16.7'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
svelte: ^3.44.0 svelte: ^3.44.0
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte': 1.0.0-next.44_svelte@3.48.0+vite@2.9.9 '@sveltejs/vite-plugin-svelte': 1.0.0-next.47_svelte@3.48.0+vite@2.9.9
chokidar: 3.5.3 chokidar: 3.5.3
sade: 1.8.1 sade: 1.8.1
svelte: 3.48.0 svelte: 3.48.0
@ -778,8 +780,8 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@sveltejs/vite-plugin-svelte/1.0.0-next.44_svelte@3.48.0+vite@2.9.9: /@sveltejs/vite-plugin-svelte/1.0.0-next.47_svelte@3.48.0+vite@2.9.9:
resolution: {integrity: sha512-n+sssEWbzykPS447FmnNyU5GxEhrBPDVd0lxNZnxRGz9P6651LjjwAnISKr3CKgT9v8IybP8VD0n2i5XzbqExg==} resolution: {integrity: sha512-J6n8UN51aq/TEZGQ89/EtdXTtca3cRcTJGzi6fi+xK8LkgsHQLCZhRj+PJ+swktRSWTX9IOmQS55SqVg6bz5fA==}
engines: {node: ^14.13.1 || >= 16} engines: {node: ^14.13.1 || >= 16}
peerDependencies: peerDependencies:
diff-match-patch: ^1.0.5 diff-match-patch: ^1.0.5
@ -795,7 +797,7 @@ packages:
kleur: 4.1.4 kleur: 4.1.4
magic-string: 0.26.2 magic-string: 0.26.2
svelte: 3.48.0 svelte: 3.48.0
svelte-hmr: 0.14.11_svelte@3.48.0 svelte-hmr: 0.14.12_svelte@3.48.0
vite: 2.9.9 vite: 2.9.9
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -3986,6 +3988,16 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/prettier-plugin-svelte/2.7.0_kkjbqzpydplecjtkxrgomroeru:
resolution: {integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==}
peerDependencies:
prettier: ^1.16.4 || ^2.0.0
svelte: ^3.2.0
dependencies:
prettier: 2.6.2
svelte: 3.48.0
dev: true
/prettier/2.6.2: /prettier/2.6.2:
resolution: {integrity: sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==} resolution: {integrity: sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
@ -4519,8 +4531,8 @@ packages:
- sugarss - sugarss
dev: true dev: true
/svelte-hmr/0.14.11_svelte@3.48.0: /svelte-hmr/0.14.12_svelte@3.48.0:
resolution: {integrity: sha512-R9CVfX6DXxW1Kn45Jtmx+yUe+sPhrbYSUp7TkzbW0jI5fVPn6lsNG9NEs5dFg5qRhFNAoVdRw5qQDLALNKhwbQ==} resolution: {integrity: sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==}
engines: {node: ^12.20 || ^14.13.1 || >= 16} engines: {node: ^12.20 || ^14.13.1 || >= 16}
peerDependencies: peerDependencies:
svelte: '>=3.19.0' svelte: '>=3.19.0'

View File

@ -1,73 +1,72 @@
<script lang="ts"> <script lang="ts">
import { Button } from 'omorphia'; import { Button } from 'omorphia'
import IconMoon from 'virtual:icons/heroicons-outline/moon'; import IconMoon from 'virtual:icons/heroicons-outline/moon'
import IconSun from 'virtual:icons/heroicons-outline/sun'; import IconSun from 'virtual:icons/heroicons-outline/sun'
export let meta: { raised: boolean }; export let meta: { raised: boolean }
let theme = 'light'; let theme = 'light'
let background = meta.raised ? 'var(--color-raised-bg)' : 'var(--color-bg)'; let background = meta.raised ? 'var(--color-raised-bg)' : 'var(--color-bg)'
</script> </script>
<div class="example"> <div class="example">
<div class="example__preview theme-{theme} base" style:background> <div class="example__preview theme-{theme} base" style:background>
<slot name="example" /> <slot name="example" />
</div> </div>
<div class="example__source"> <div class="example__source">
<div class="example__source__options"> <div class="example__source__options">
<Button <Button
color="primary-light" color="primary-light"
on:click={() => (theme === 'light' ? (theme = 'dark') : (theme = 'light'))} on:click={() => (theme === 'light' ? (theme = 'dark') : (theme = 'light'))}>
> {#if theme === 'light'}
{#if theme === 'light'} <IconMoon />
<IconMoon /> {:else}
{:else} <IconSun />
<IconSun /> {/if}
{/if} </Button>
</Button> </div>
</div> <pre class="example__source__code language-svelte"><slot name="code" /></pre>
<pre class="example__source__code language-svelte"><slot name="code" /></pre> </div>
</div>
</div> </div>
<style lang="postcss"> <style lang="postcss">
.example { .example {
margin: 15px 0 32px; margin: 15px 0 32px;
&__preview { &__preview {
border-radius: var(--rounded-sm-top); border-radius: var(--rounded-sm-top);
border: solid 2px hsl(0, 0%, 20%); border: solid 2px hsl(0, 0%, 20%);
border-bottom: none; border-bottom: none;
display: flex; display: flex;
grid-gap: 16px; grid-gap: 16px;
flex-wrap: wrap; flex-wrap: wrap;
position: relative; position: relative;
justify-content: flex-start; justify-content: flex-start;
z-index: 1; z-index: 1;
padding: 16px; padding: 16px;
} }
&__source { &__source {
position: relative; position: relative;
&__options { &__options {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
padding: 8px; padding: 8px;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
:global(button) { :global(button) {
color: black; color: black;
} }
} }
&__code { &__code {
margin: 0; margin: 0;
border-radius: var(--rounded-sm-bottom) !important; border-radius: var(--rounded-sm-bottom) !important;
background: hsl(220, 13%, 22%); background: hsl(220, 13%, 22%);
} }
} }
} }
</style> </style>

View File

@ -1,112 +1,111 @@
<script lang="ts"> <script lang="ts">
import OmorphiaLogo from '../assets/omorphia.svg'; import OmorphiaLogo from '../assets/omorphia.svg'
import IconLogoGithub from 'virtual:icons/carbon/logo-github'; import IconLogoGithub from 'virtual:icons/carbon/logo-github'
import IconChat from 'virtual:icons/heroicons-outline/chat-alt-2'; import IconChat from 'virtual:icons/heroicons-outline/chat-alt-2'
import { onMount } from 'svelte'; import { onMount } from 'svelte'
let headerElement; let headerElement
onMount(() => { onMount(() => {
let lastScrollTop: number; let lastScrollTop: number
window.addEventListener('scroll', () => { window.addEventListener('scroll', () => {
let scrollTop = window.pageYOffset || document.documentElement.scrollTop; let scrollTop = window.pageYOffset || document.documentElement.scrollTop
if (scrollTop > lastScrollTop && headerElement) { if (scrollTop > lastScrollTop && headerElement) {
headerElement.style.top = '-100%'; headerElement.style.top = '-100%'
} else if (headerElement) { } else if (headerElement) {
headerElement.style.top = '0'; headerElement.style.top = '0'
} }
lastScrollTop = scrollTop; lastScrollTop = scrollTop
}); })
}); })
</script> </script>
<header class="header" bind:this={headerElement}> <header class="header" bind:this={headerElement}>
<OmorphiaLogo class="header__logo" /> <OmorphiaLogo class="header__logo" />
<div class="header__title">Omorphia</div> <div class="header__title">Omorphia</div>
<div class="header__links"> <div class="header__links">
<a class="hide-sm" href="https://modrinth.com">Modrinth.com</a> <a class="hide-sm" href="https://modrinth.com">Modrinth.com</a>
<span class="spacer-dot hide-sm" /> <span class="spacer-dot hide-sm" />
<a href="https://www.npmjs.com/package/omorphia">NPM</a> <a href="https://www.npmjs.com/package/omorphia">NPM</a>
<span class="spacer-dot" /> <span class="spacer-dot" />
<a href="https://rewrite.modrinth.com/discord"> <a href="https://rewrite.modrinth.com/discord">
<IconChat /> <IconChat />
</a> </a>
<a href="https://github.com/modrinth/omorphia"> <a href="https://github.com/modrinth/omorphia">
<IconLogoGithub /> <IconLogoGithub />
</a> </a>
</div> </div>
</header> </header>
<style lang="postcss"> <style lang="postcss">
.header { .header {
display: flex; display: flex;
grid-gap: 10px; grid-gap: 10px;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
padding: 16px 24px; padding: 16px 24px;
position: fixed; position: fixed;
left: 0; left: 0;
right: 0; right: 0;
top: 0; top: 0;
z-index: 10; z-index: 10;
background-color: hsl(0, 0%, 100%); background-color: hsl(0, 0%, 100%);
box-shadow: hsla(221, 39%, 11%, 0.2) 0 2px 4px 0, box-shadow: hsla(221, 39%, 11%, 0.2) 0 2px 4px 0, hsla(221, 39%, 11%, 0.05) 0 -2px 2px 0 inset;
hsla(221, 39%, 11%, 0.05) 0 -2px 2px 0 inset; transition: top 0.3s ease-in-out;
transition: top 0.3s ease-in-out;
@media not (--sm) { @media not (--sm) {
top: 0 !important; top: 0 !important;
} }
@media (--sm) { @media (--sm) {
padding: 10px 32px; padding: 10px 32px;
} }
:global(&__logo) { :global(&__logo) {
max-width: 32px; max-width: 32px;
min-width: 32px; min-width: 32px;
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
&__title { &__title {
font-size: 20px; font-size: 20px;
font-weight: 600; font-weight: 600;
} }
&__links { &__links {
margin-left: auto; margin-left: auto;
grid-gap: 16px; grid-gap: 16px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
display: flex; display: flex;
:global(svg) { :global(svg) {
height: 22px; height: 22px;
width: auto; width: auto;
} }
.hide-sm { .hide-sm {
display: none; display: none;
@media (--sm) { @media (--sm) {
display: flex; display: flex;
} }
} }
a { a {
text-decoration: none; text-decoration: none;
&:not(:hover) { &:not(:hover) {
color: unset; color: unset;
} }
} }
} }
} }
.spacer-dot { .spacer-dot {
background-color: hsla(0, 0%, 0%, 0.2); background-color: hsla(0, 0%, 0%, 0.2);
border-radius: 999px; border-radius: 999px;
width: 5px; width: 5px;
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
</style> </style>

View File

@ -1,162 +1,157 @@
<script lang="ts"> <script lang="ts">
import { page } from '$app/stores'; import { page } from '$app/stores'
import IconMenu from 'virtual:icons/lucide/menu'; import IconMenu from 'virtual:icons/lucide/menu'
const components = Object.keys(import.meta.glob('../../routes/components/**')) const components = Object.keys(import.meta.glob('../../routes/components/**'))
.map((it) => it.replace('../../routes/components/', '').replace('.md', '')) .map((it) => it.replace('../../routes/components/', '').replace('.md', ''))
.sort(); .sort()
const classes = Object.keys(import.meta.glob('../../routes/classes/**')) const classes = Object.keys(import.meta.glob('../../routes/classes/**'))
.map((it) => it.replace('../../routes/classes/', '').replace('.md', '')) .map((it) => it.replace('../../routes/classes/', '').replace('.md', ''))
.sort(); .sort()
let slideIn = false; let slideIn = false
$: if ($page.url.pathname) { $: if ($page.url.pathname) {
slideIn = false; slideIn = false
} }
</script> </script>
<nav class="sidebar" class:slideIn> <nav class="sidebar" class:slideIn>
<div class="sidebar__content"> <div class="sidebar__content">
<div class="section"> <div class="section">
<span class="section__title">Getting started</span> <span class="section__title">Getting started</span>
<a href="/" class="section__link">Introduction</a> <a href="/" class="section__link">Introduction</a>
<a href="/getting-started/configure" class="section__link">Configure</a> <a href="/getting-started/configure" class="section__link">Configure</a>
<a href="/getting-started/icons" class="section__link">Using Icons</a> <a href="/getting-started/icons" class="section__link">Using Icons</a>
<!-- <a href="/getting-started/css" class="section__link">Writing CSS</a> --> <!-- <a href="/getting-started/css" class="section__link">Writing CSS</a> -->
<a href="/getting-started/illustrations" class="section__link">Illustrations</a> <a href="/getting-started/illustrations" class="section__link">Illustrations</a>
<a href="/getting-started/utils" class="section__link">Built-in utilities</a> <a href="/getting-started/utils" class="section__link">Built-in utilities</a>
<a href="/getting-started/generator" class="section__link">Generator plugin</a> <a href="/getting-started/generator" class="section__link">Generator plugin</a>
</div> </div>
<div class="section"> <div class="section">
<span class="section__title">Components</span> <span class="section__title">Components</span>
{#each components as component} {#each components as component}
<a href="/components/{component}" class="section__link">{component}</a> <a href="/components/{component}" class="section__link">{component}</a>
{/each} {/each}
</div> </div>
<div class="section"> <div class="section">
<span class="section__title">Classes</span> <span class="section__title">Classes</span>
{#each classes as page} {#each classes as page}
<a href="/classes/{page}" class="section__link">{page}</a> <a href="/classes/{page}" class="section__link">{page}</a>
{/each} {/each}
</div> </div>
</div> </div>
<button class="sidebar__toggle" on:click={() => (slideIn = !slideIn)}> <button class="sidebar__toggle" on:click={() => (slideIn = !slideIn)}>
<IconMenu /> <IconMenu />
</button> </button>
</nav> </nav>
<style lang="postcss"> <style lang="postcss">
:root { :root {
--sidebar-color: hsl(220, 15%, 40%); --sidebar-color: hsl(220, 15%, 40%);
--title-color: hsl(216, 10%, 80%); --title-color: hsl(216, 10%, 80%);
--link-color: hsl(216, 10%, 90%); --link-color: hsl(216, 10%, 90%);
--scrollbar-thumb-color: hsl(216, 10%, 70%); --scrollbar-thumb-color: hsl(216, 10%, 70%);
} }
.sidebar { .sidebar {
background-color: var(--sidebar-color); background-color: var(--sidebar-color);
color: var(--title-color); color: var(--title-color);
width: var(--sidebar-width); width: var(--sidebar-width);
max-width: 70vw; max-width: 70vw;
position: fixed; position: fixed;
left: -100%; left: -100%;
top: 0; top: 0;
z-index: 5; z-index: 5;
transition: left 0.2s ease-in-out; transition: left 0.2s ease-in-out;
box-shadow: 2px 0px 4px hsla(221, 39%, 11%, 0.2); box-shadow: 2px 0px 4px hsla(221, 39%, 11%, 0.2);
@media (--md) { @media (--md) {
left: 0; left: 0;
} }
&__content { &__content {
mask-image: linear-gradient( mask-image: linear-gradient(to bottom, transparent, hsla(0, 0%, 0%, 1) 5% 95%, transparent);
to bottom, padding: 88px 32px 32px;
transparent, height: 100vh;
hsla(0, 0%, 0%, 1) 5% 95%, max-height: 100vh;
transparent overflow-y: auto;
); grid-gap: 40px;
padding: 88px 32px 32px; display: flex;
height: 100vh; flex-direction: column;
max-height: 100vh;
overflow-y: auto;
grid-gap: 40px;
display: flex;
flex-direction: column;
.section { .section {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
grid-gap: 0.5rem; grid-gap: 0.5rem;
&__title { &__title {
text-transform: uppercase; text-transform: uppercase;
font-size: 12px; font-size: 12px;
} }
&__link { &__link {
color: var(--link-color); color: var(--link-color);
text-decoration: none; text-decoration: none;
&:hover { &:hover {
color: white; color: white;
text-decoration: underline; text-decoration: underline;
} }
} }
} }
} }
&__toggle { &__toggle {
position: fixed; position: fixed;
left: 16px; left: 16px;
bottom: 16px; bottom: 16px;
padding: 8px; padding: 8px;
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
background-color: var(--accent-color); background-color: var(--accent-color);
z-index: 20; z-index: 20;
border-radius: var(--rounded); border-radius: var(--rounded);
color: white; color: white;
box-shadow: var(--shadow-inset-sm), var(--shadow-floating); box-shadow: var(--shadow-inset-sm), var(--shadow-floating);
transition: left 0.2s cubic-bezier(0.38, 0.52, 0.37, 1.27); transition: left 0.2s cubic-bezier(0.38, 0.52, 0.37, 1.27);
:global(.icon) { :global(.icon) {
width: 32px; width: 32px;
height: auto; height: auto;
} }
@media (--md) { @media (--md) {
visibility: hidden; visibility: hidden;
} }
} }
&.slideIn { &.slideIn {
left: 0; left: 0;
.sidebar__toggle { .sidebar__toggle {
left: calc(32px + min(70vw, var(--sidebar-width))); left: calc(32px + min(70vw, var(--sidebar-width)));
} }
} }
scrollbar-color: var(--scrollbar-thumb-color) var(--sidebar-color); scrollbar-color: var(--scrollbar-thumb-color) var(--sidebar-color);
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 14px; width: 14px;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background-color: var(--sidebar-color); background-color: var(--sidebar-color);
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: var(--scrollbar-thumb-color); background-color: var(--scrollbar-thumb-color);
border-radius: 999px; border-radius: 999px;
border: 3px solid var(--sidebar-color); border: 3px solid var(--sidebar-color);
} }
} }
</style> </style>

View File

@ -1,147 +1,143 @@
<script lang="ts"> <script lang="ts">
import IconPencil from 'virtual:icons/heroicons-outline/pencil'; import IconPencil from 'virtual:icons/heroicons-outline/pencil'
import { page } from '$app/stores'; import { page } from '$app/stores'
import COMPONENT_API from '../../generated/COMPONENT_API.json'; import COMPONENT_API from '../../generated/COMPONENT_API.json'
export let fileName = $page.url.pathname export let fileName = $page.url.pathname
.substring($page.url.pathname.lastIndexOf('/') + 1) .substring($page.url.pathname.lastIndexOf('/') + 1)
.replace('.html', ''); .replace('.html', '')
export let title = fileName; export let title = fileName
export let description = 'Learn about Omorphia, the component & style library'; export let description = 'Learn about Omorphia, the component & style library'
let editUrl = `https://github.com/modrinth/omorphia/edit/main/src/routes/${ let editUrl = `https://github.com/modrinth/omorphia/edit/main/src/routes/${
$page.url.pathname.replace('/', '') || 'index' $page.url.pathname.replace('/', '') || 'index'
}.md`; }.md`
let api; let api
if ($page.url.pathname.includes('components')) { if ($page.url.pathname.includes('components')) {
if (import.meta.env.DEV) { if (import.meta.env.DEV) {
import(`../../../package/components/${title}.svelte?raw&sveld`).then( import(`../../../package/components/${title}.svelte?raw&sveld`).then(
(output) => (api = output.default) (output) => (api = output.default)
); )
} else { } else {
api = COMPONENT_API[`${title}.svelte`]; api = COMPONENT_API[`${title}.svelte`]
} }
} }
</script> </script>
<svelte:head> <svelte:head>
<title>{title ? `${title} Omorphia` : 'Omorphia'}</title> <title>{title ? `${title} Omorphia` : 'Omorphia'}</title>
<meta name="description" content={description} /> <meta name="description" content={description} />
</svelte:head> </svelte:head>
{#if title}<h1>{title}</h1>{/if} {#if title}<h1>{title}</h1>{/if}
<a class="edit-link" href={editUrl}> <a class="edit-link" href={editUrl}>
<IconPencil /> <IconPencil />
Edit this page on GitHub</a Edit this page on GitHub</a>
>
<slot /> <slot />
{#if api} {#if api}
<div class="extra-info"> <div class="extra-info">
{#if api.props.length > 0} {#if api.props.length > 0}
<h2>Properties</h2> <h2>Properties</h2>
<table class="api-table"> <table class="api-table">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Type</th> <th>Type</th>
<th>Default</th> <th>Default</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each api.props as prop} {#each api.props as prop}
<tr> <tr>
<td><code>{prop.name}</code></td> <td><code>{prop.name}</code></td>
<td><code>{prop.type ?? ''}</code></td> <td><code>{prop.type ?? ''}</code></td>
<td><code>{prop.value ?? ''}</code></td> <td><code>{prop.value ?? ''}</code></td>
<td <td
>{prop.constant ? '[Read only] ' : ''}{prop.description?.replace( >{prop.constant ? '[Read only] ' : ''}{prop.description?.replace('null', '') ||
'null', ''}</td>
'' </tr>
) || ''}</td {/each}
> </tbody>
</tr> </table>
{/each} {/if}
</tbody> {#if api.events.length > 0}
</table> <h2>Events</h2>
{/if} <table class="api-table">
{#if api.events.length > 0} <thead>
<h2>Events</h2> <tr>
<table class="api-table"> <th>Name</th>
<thead> <th>Forwarded</th>
<tr> <th>Description</th>
<th>Name</th> </tr>
<th>Forwarded</th> </thead>
<th>Description</th> <tbody>
</tr> {#each api.events as event}
</thead> <tr>
<tbody> <td><code>{event.name}</code></td>
{#each api.events as event} <td>{!!event.parent}</td>
<tr> <td>{event.description?.replace('null', '') || ''}</td>
<td><code>{event.name}</code></td> </tr>
<td>{!!event.parent}</td> {/each}
<td>{event.description?.replace('null', '') || ''}</td> </tbody>
</tr> </table>
{/each} {/if}
</tbody> {#if api.slots.length > 0}
</table> <h2>Slots</h2>
{/if} <table class="api-table">
{#if api.slots.length > 0} <thead>
<h2>Slots</h2> <tr>
<table class="api-table"> <th>Name</th>
<thead> <th>Fallback</th>
<tr> </tr>
<th>Name</th> </thead>
<th>Fallback</th> <tbody>
</tr> {#each api.slots as slot}
</thead> <tr>
<tbody> <td><code>{slot.name}</code></td>
{#each api.slots as slot} <td>{slot.fallback ?? 'None'}</td>
<tr> </tr>
<td><code>{slot.name}</code></td> {/each}
<td>{slot.fallback ?? 'None'}</td> </tbody>
</tr> </table>
{/each} {/if}
</tbody> </div>
</table>
{/if}
</div>
{/if} {/if}
<style lang="postcss"> <style lang="postcss">
.edit-link { .edit-link {
display: flex; display: flex;
align-items: center; align-items: center;
grid-gap: 8px; grid-gap: 8px;
margin-bottom: 54px; margin-bottom: 54px;
color: var(--accent-color); color: var(--accent-color);
} }
.extra-info { .extra-info {
margin-top: 64px; margin-top: 64px;
} }
.api-table { .api-table {
border-collapse: collapse; border-collapse: collapse;
margin-top: -6px; margin-top: -6px;
} }
.api-table tr { .api-table tr {
background-color: transparent; background-color: transparent;
border: none; border: none;
} }
.api-table tbody { .api-table tbody {
border: 2px solid grey; border: 2px solid grey;
} }
.api-table th { .api-table th {
text-transform: uppercase; text-transform: uppercase;
font-size: 12.5px; font-size: 12.5px;
border: none; border: none;
} }
</style> </style>

View File

@ -1,102 +1,100 @@
<script lang="ts"> <script lang="ts">
// TODO: Make square icon `md` more rounded // TODO: Make square icon `md` more rounded
import { onMount } from 'svelte'; import { onMount } from 'svelte'
import { classCombine } from '../utils/classCombine'; import { classCombine } from '../utils/classCombine'
/** Optional, as a default icon will be substituted if no image was specified */ /** Optional, as a default icon will be substituted if no image was specified */
export let src: string | undefined; export let src: string | undefined
export let size: 'xs' | 'sm' | 'md' | 'lg'; export let size: 'xs' | 'sm' | 'md' | 'lg'
export let circle = false; export let circle = false
export let floatUp = false; export let floatUp = false
let className: string; let className: string
$: className = classCombine([ $: className = classCombine([
'avatar', 'avatar',
circle && 'avatar--circle', circle && 'avatar--circle',
`avatar--size-${size}`, `avatar--size-${size}`,
floatUp && 'avatar--float-up', floatUp && 'avatar--float-up',
]); ])
let img; let img
onMount(() => { onMount(() => {
if (img && img.naturalWidth) { if (img && img.naturalWidth) {
const isPixelated = () => { const isPixelated = () => {
if (img.naturalWidth < 96 && img.naturalWidth > 0) { if (img.naturalWidth < 96 && img.naturalWidth > 0) {
img.style = 'image-rendering: pixelated;'; img.style = 'image-rendering: pixelated;'
} }
}; }
if (img.naturalWidth) { if (img.naturalWidth) {
isPixelated(); isPixelated()
} else { } else {
img.onload = isPixelated; img.onload = isPixelated
} }
} }
}); })
</script> </script>
{#if src} {#if src}
<img {src} bind:this={img} class={className} alt="" /> <img {src} bind:this={img} class={className} alt="" />
{:else} {:else}
<svg <svg
class={className} class={className}
xml:space="preserve" xml:space="preserve"
fill-rule="evenodd" fill-rule="evenodd"
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
stroke-miterlimit="1.5" stroke-miterlimit="1.5"
clip-rule="evenodd" clip-rule="evenodd"
viewBox="0 0 104 104" viewBox="0 0 104 104">
> <path fill="none" d="M0 0h103.4v103.4H0z" />
<path fill="none" d="M0 0h103.4v103.4H0z" /> <path
<path fill="none"
fill="none" stroke="#9a9a9a"
stroke="#9a9a9a" stroke-width="5"
stroke-width="5" d="M51.7 92.5V51.7L16.4 31.3l35.3 20.4L87 31.3 51.7 11 16.4 31.3v40.8l35.3 20.4L87 72V31.3L51.7 11" />
d="M51.7 92.5V51.7L16.4 31.3l35.3 20.4L87 31.3 51.7 11 16.4 31.3v40.8l35.3 20.4L87 72V31.3L51.7 11" </svg>
/>
</svg>
{/if} {/if}
<style lang="postcss"> <style lang="postcss">
.avatar { .avatar {
border-radius: var(--rounded); border-radius: var(--rounded);
box-shadow: var(--shadow-inset-lg), var(--shadow-raised-lg); box-shadow: var(--shadow-inset-lg), var(--shadow-raised-lg);
height: var(--size); height: var(--size);
width: var(--size); width: var(--size);
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
&--size { &--size {
&-xs { &-xs {
--size: 2.25rem; --size: 2.25rem;
box-shadow: var(--shadow-inset), var(--shadow-raised); box-shadow: var(--shadow-inset), var(--shadow-raised);
} }
&-sm { &-sm {
--size: 3rem; --size: 3rem;
box-shadow: var(--shadow-inset), var(--shadow-raised); box-shadow: var(--shadow-inset), var(--shadow-raised);
} }
&-md { &-md {
--size: 6rem; --size: 6rem;
border-radius: var(--rounded-lg); border-radius: var(--rounded-lg);
} }
&-lg { &-lg {
--size: 9rem; --size: 9rem;
border-radius: var(--rounded-lg); border-radius: var(--rounded-lg);
} }
} }
&--float-up { &--float-up {
margin-top: calc(var(--size) * (-2 / 3)); margin-top: calc(var(--size) * (-2 / 3));
z-index: 1; z-index: 1;
} }
&--circle { &--circle {
border-radius: 50%; border-radius: 50%;
} }
} }
</style> </style>

View File

@ -1,51 +1,51 @@
<script lang="ts"> <script lang="ts">
export let label = '' export let label = ''
/** Supports `green`, `yellow`, `red`, & `gray` */ /** Supports `green`, `yellow`, `red`, & `gray` */
export let color = 'gray' export let color = 'gray'
</script> </script>
<div class="badge badge--color-{color}"> <div class="badge badge--color-{color}">
{label} {label}
</div> </div>
<style lang="postcss"> <style lang="postcss">
.badge { .badge {
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
display: inline; display: inline;
position: relative; position: relative;
padding-left: 0.9rem; padding-left: 0.9rem;
line-height: 1rem; line-height: 1rem;
&--color-green { &--color-green {
color: var(--color-badge-green-text); color: var(--color-badge-green-text);
--color-dot: var(--color-badge-green-dot); --color-dot: var(--color-badge-green-dot);
} }
&--color-yellow { &--color-yellow {
color: var(--color-badge-yellow-text); color: var(--color-badge-yellow-text);
--color-dot: var(--color-badge-yellow-dot); --color-dot: var(--color-badge-yellow-dot);
} }
&--color-red { &--color-red {
color: var(--color-badge-red-text); color: var(--color-badge-red-text);
--color-dot: var(--color-badge-red-dot); --color-dot: var(--color-badge-red-dot);
} }
&--color-gray { &--color-gray {
color: var(--color-badge-gray-text); color: var(--color-badge-gray-text);
--color-dot: var(--color-badge-gray-dot); --color-dot: var(--color-badge-gray-dot);
} }
&::before { &::before {
content: ''; content: '';
display: inline-block; display: inline-block;
width: 0.5rem; width: 0.5rem;
height: 0.5rem; height: 0.5rem;
border-radius: 50%; border-radius: 50%;
background-color: var(--color-dot); background-color: var(--color-dot);
position: absolute; position: absolute;
left: 0; left: 0;
bottom: 25%; bottom: 25%;
} }
} }
</style> </style>

View File

@ -1,156 +1,155 @@
<script lang="ts"> <script lang="ts">
// TODO: sizes // TODO: sizes
// TODO: icon only buttons should have uniform padding // TODO: icon only buttons should have uniform padding
// TODO: Could be a class
import { classCombine } from '../utils/classCombine'; import { classCombine } from '../utils/classCombine'
/** The element to be styled as a button */ /** The element to be styled as a button */
export let as: 'button' | 'a' | 'summary' | 'input' = 'button'; export let as: 'button' | 'a' | 'summary' | 'input' = 'button'
export let href = ''; export let href = ''
if (href) as = 'a'; if (href) as = 'a'
/** Use `value` if the button is an `<input`> */ /** Use `value` if the button is an `<input`> */
export let value = ''; export let value = ''
export let size: 'sm' | 'md' | 'lg' = 'md'; export let size: 'sm' | 'md' | 'lg' = 'md'
export let color: export let color:
| '' | ''
| 'raised' | 'raised'
| 'primary' | 'primary'
| 'primary-light' | 'primary-light'
| 'secondary' | 'secondary'
| 'tertiary' | 'tertiary'
| 'danger' | 'danger'
| 'danger-light' | 'danger-light'
| 'transparent' = ''; | 'transparent' = ''
/** Show notification badge in the upper right of button */ /** Show notification badge in the upper right of button */
export let badge = false; export let badge = false
export let disabled = false; export let disabled = false
/** Hover title for accessibility */ /** Hover title for accessibility */
export let title = ''; export let title = ''
/** Link target */ /** Link target */
export let target = ''; export let target = ''
let className: string; let className: string
$: className = classCombine([ $: className = classCombine([
'button', 'button',
`button--size-${size}`, `button--size-${size}`,
`button--color-${color}`, `button--color-${color}`,
badge && 'has-badge', badge && 'has-badge',
]); ])
</script> </script>
{#if as === 'a'} {#if as === 'a'}
<a class={className} {href} {disabled} {title} {target} on:click> <a class={className} {href} {disabled} {title} {target} on:click>
<slot /> <slot />
</a> </a>
{:else if as === 'input'} {:else if as === 'input'}
<input class={className} {value} {disabled} {title} on:click /> <input class={className} {value} {disabled} {title} on:click />
{:else} {:else}
<svelte:element this={as} class={className} {disabled} {title} on:click> <svelte:element this={as} class={className} {disabled} {title} on:click>
<slot /> <slot />
</svelte:element> </svelte:element>
{/if} {/if}
<style lang="postcss"> <style lang="postcss">
.button { .button {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
padding: 0.25rem 1rem; padding: 0.25rem 1rem;
grid-gap: 14px; grid-gap: 14px;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
white-space: nowrap; white-space: nowrap;
color: var(--color-bg-contrast); color: var(--color-bg-contrast);
box-shadow: var(--shadow-inset-sm); box-shadow: var(--shadow-inset-sm);
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
border-radius: var(--rounded); border-radius: var(--rounded);
transition: opacity 0.5s ease-in-out, filter 0.05s ease-in-out; transition: opacity 0.5s ease-in-out, filter 0.2s ease-in-out;
&:hover { &:hover {
filter: brightness(0.9); filter: brightness(0.85);
} }
&--color { &--color {
&-raised { &-raised {
background-color: var(--color-raised-bg); background-color: var(--color-raised-bg);
} }
&-primary { &-primary {
background-color: var(--color-brand); background-color: var(--color-brand);
color: var(--color-brand-contrast); color: var(--color-brand-contrast);
} }
&-primary-light { &-primary-light {
background-color: var(--color-brand-light); background-color: var(--color-brand-light);
} }
&-secondary { &-secondary {
background-color: var(--color-secondary); background-color: var(--color-secondary);
color: var(--color-brand-contrast); color: var(--color-brand-contrast);
} }
&-tertiary { &-tertiary {
background-color: var(--color-tertiary); background-color: var(--color-tertiary);
} }
&-transparent { &-transparent {
background-color: transparent; background-color: transparent;
box-shadow: none; box-shadow: none;
} }
&-danger { &-danger {
background-color: var(--color-badge-red-dot); background-color: var(--color-badge-red-dot);
color: var(--color-brand-contrast); color: var(--color-brand-contrast);
} }
&-danger-light { &-danger-light {
background-color: var(--color-popup-danger-bg); background-color: var(--color-popup-danger-bg);
color: var(--color-popup-danger-text); color: var(--color-popup-danger-text);
} }
} }
&:disabled { &:disabled {
opacity: 50%; opacity: 50%;
cursor: not-allowed; cursor: not-allowed;
filter: grayscale(50%); filter: grayscale(50%);
/* Not ideal, but preventing events being fired needs to be implemented */ /* Not ideal, but preventing events being fired needs to be implemented */
pointer-events: none; pointer-events: none;
} }
&--pad-even { &--pad-even {
padding: 0.5rem; padding: 0.5rem;
font-size: 1rem; font-size: 1rem;
line-height: 0; line-height: 0;
min-width: 2rem; min-width: 2rem;
min-height: 2rem; min-height: 2rem;
justify-content: center; justify-content: center;
} }
&.has-badge::after { &.has-badge::after {
content: ''; content: '';
width: 0.5rem; width: 0.5rem;
height: 0.5rem; height: 0.5rem;
border-radius: var(--rounded-max); border-radius: var(--rounded-max);
background-color: var(--color-brand); background-color: var(--color-brand);
position: absolute; position: absolute;
top: 0.5rem; top: 0.5rem;
right: 0.5rem; right: 0.5rem;
} }
/* Only child doesn't work as intended because text is passed through as `innerText` */ /* Only child doesn't work as intended because text is passed through as `innerText` */
:global(.icon:only-child) { :global(.icon:only-child) {
margin: 4px -7px; margin: 4px -7px;
} }
} }
</style> </style>

View File

@ -1,66 +1,66 @@
<script lang="ts"> <script lang="ts">
import { uniqueId } from '../utils/uniqueId' import { uniqueId } from '../utils/uniqueId'
import IconCheck from 'virtual:icons/heroicons-outline/check' import IconCheck from 'virtual:icons/heroicons-outline/check'
export let checked = false; export let checked = false
const id = `checkbox-${uniqueId()}` const id = `checkbox-${uniqueId()}`
</script> </script>
<div class="checkbox"> <div class="checkbox">
<input type="checkbox" bind:checked={checked} on:change id={id} name={id}> <input type="checkbox" bind:checked on:change {id} name={id} />
<label for={id} class="checkbox__label"> <label for={id} class="checkbox__label">
<span class="checkbox__label__box"> <span class="checkbox__label__box">
<IconCheck /> <IconCheck />
</span> </span>
<slot/> <slot />
</label> </label>
</div> </div>
<style lang="postcss"> <style lang="postcss">
.checkbox { .checkbox {
input { input {
display: none; display: none;
} }
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
grid-gap: 0.5rem; grid-gap: 0.5rem;
&__label { &__label {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
> :global(.icon) { > :global(.icon) {
width: 1.1rem; width: 1.1rem;
margin-right: -0.1rem; margin-right: -0.1rem;
} }
&__box { &__box {
height: 1rem; height: 1rem;
width: 1rem; width: 1rem;
display: flex; display: flex;
border-radius: 0.25rem; border-radius: 0.25rem;
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
justify-content: center; justify-content: center;
align-items: center; align-items: center;
> :global(.icon) { > :global(.icon) {
display: none; display: none;
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
color: var(--color-raised-bg) color: var(--color-raised-bg);
} }
} }
} }
[type=checkbox]:checked + label span { [type='checkbox']:checked + label span {
background-color: var(--color-brand); background-color: var(--color-brand);
:global(.icon) { :global(.icon) {
display: unset; display: unset;
} }
} }
} }
</style> </style>

View File

@ -1,46 +1,46 @@
<script lang="ts"> <script lang="ts">
import Checkbox from './Checkbox.svelte'; import Checkbox from './Checkbox.svelte'
import type { Option } from './types'; import type { Option } from './types'
export let value = []; export let value = []
export let options: Option[] = []; export let options: Option[] = []
/** Wrap the options horizontally */ /** Wrap the options horizontally */
export let wrap = false; export let wrap = false
const handleChange = (e, key) => { const handleChange = (e, key) => {
if (e.target.checked) { if (e.target.checked) {
if (!value) value = []; if (!value) value = []
value = [key, ...value]; value = [key, ...value]
} else { } else {
value = value.filter((it) => key !== it); value = value.filter((it) => key !== it)
} }
}; }
</script> </script>
<div class="checkbox-list" class:wrap> <div class="checkbox-list" class:wrap>
{#each options as option} {#each options as option}
<Checkbox on:change={(e) => handleChange(e, option.value)}> <Checkbox on:change={(e) => handleChange(e, option.value)}>
{#if option.icon && typeof option.icon === 'string'} {#if option.icon && typeof option.icon === 'string'}
{@html option.icon} {@html option.icon}
{:else if option.icon} {:else if option.icon}
<svelte:component this={option.icon} /> <svelte:component this={option.icon} />
{/if} {/if}
{option.label} {option.label}
</Checkbox> </Checkbox>
{/each} {/each}
</div> </div>
<style lang="postcss"> <style lang="postcss">
.checkbox-list { .checkbox-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 2px; gap: 2px;
&.wrap { &.wrap {
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
grid-gap: 2rem; grid-gap: 2rem;
} }
} }
</style> </style>

View File

@ -1,45 +1,43 @@
<script lang="ts"> <script lang="ts">
// TODO: Add fade out styling on top and bottom // TODO: Add fade out styling on top and bottom
import Checkbox from './Checkbox.svelte'; import Checkbox from './Checkbox.svelte'
import VirtualList from 'svelte-tiny-virtual-list'; import VirtualList from 'svelte-tiny-virtual-list'
import type { Option } from './types'; import type { Option } from './types'
/** Height in pixels of list */ /** Height in pixels of list */
export let height = 200; export let height = 200
export let value = []; export let value = []
export let options: Option[] = []; export let options: Option[] = []
const handleChange = (e, key) => { const handleChange = (e, key) => {
if (e.target.checked) { if (e.target.checked) {
if (!value) value = []; if (!value) value = []
value = [key, ...value]; value = [key, ...value]
} else { } else {
value = value.filter((it) => key !== it); value = value.filter((it) => key !== it)
} }
}; }
</script> </script>
<VirtualList width="100%" {height} itemCount={options.length} itemSize={26}> <VirtualList width="100%" {height} itemCount={options.length} itemSize={26}>
<div <div
slot="item" slot="item"
let:index let:index
let:style let:style
{style} {style}
style:padding-bottom={options.length - 1 === index ? '2.5rem' : ''} style:padding-bottom={options.length - 1 === index ? '2.5rem' : ''}>
> {@const option = options[index]}
{@const option = options[index]} <Checkbox
<Checkbox checked={value && value.includes(option.value)}
checked={value && value.includes(option.value)} on:change={(e) => handleChange(e, option.value)}>
on:change={(e) => handleChange(e, option.value)} {#if option.icon && typeof option.icon === 'string'}
> {@html option.icon}
{#if option.icon && typeof option.icon === 'string'} {:else if option.icon}
{@html option.icon} <svelte:component this={option.icon} />
{:else if option.icon} {/if}
<svelte:component this={option.icon} /> {option.label}
{/if} </Checkbox>
{option.label} </div>
</Checkbox>
</div>
</VirtualList> </VirtualList>

View File

@ -1,48 +1,45 @@
<script lang="ts"> <script lang="ts">
import Button from "./Button.svelte"; import Button from './Button.svelte'
import IconCheck from 'virtual:icons/heroicons-outline/check' import IconCheck from 'virtual:icons/heroicons-outline/check'
interface Option { interface Option {
label: string; label: string
value: string | number; value: string | number
} }
export let options: Option[] = []; export let options: Option[] = []
export let value: string | number; export let value: string | number
// If set to true, one chip is always selected // If set to true, one chip is always selected
export let neverEmpty = false; export let neverEmpty = false
let selected: Option | null = options.find((option) => option.value === (value || '')); let selected: Option | null = options.find((option) => option.value === (value || ''))
$: if (selected) { $: if (selected) {
value = selected.value; value = selected.value
} else { } else {
value = '' value = ''
} }
</script> </script>
<div class="chips"> <div class="chips">
{#each options as option} {#each options as option}
{@const isSelected = selected?.value === option.value} {@const isSelected = selected?.value === option.value}
<Button <Button
color={isSelected ? 'primary-light' : undefined} color={isSelected ? 'primary-light' : undefined}
on:click={() => { on:click={() => {
isSelected && !neverEmpty isSelected && !neverEmpty ? (selected = null) : (selected = option)
? selected = null }}>
: selected = option {#if isSelected}
}} <IconCheck />
> {/if}
{#if isSelected} {option.label}
<IconCheck /> </Button>
{/if} {/each}
{option.label}
</Button>
{/each}
</div> </div>
<style lang="postcss"> <style lang="postcss">
.chips { .chips {
display: flex; display: flex;
grid-gap: 0.5rem; grid-gap: 0.5rem;
} }
</style> </style>

View File

@ -1,24 +1,23 @@
<script lang="ts"> <script lang="ts">
import { uniqueId } from '../utils/uniqueId' import { uniqueId } from '../utils/uniqueId'
export let required = false; export let required = false
export let label: string; export let label: string
const id = `form-field-${uniqueId()}` const id = `form-field-${uniqueId()}`
</script> </script>
<div class="form-field"> <div class="form-field">
<label for={id} class="text-input__label" class:required> <label for={id} class="text-input__label" class:required>
{label} {label}
</label> </label>
<slot {id} /> <slot {id} />
</div> </div>
<style lang="postcss"> <style lang="postcss">
.form-field { .form-field {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
} }
</style> </style>

View File

@ -1,80 +1,79 @@
<script lang="ts"> <script lang="ts">
import { page } from '$app/stores'; import { page } from '$app/stores'
interface Link { interface Link {
href: string; href: string
label: string; label: string
} }
export let links: Link[]; export let links: Link[]
export let query = ''; export let query = ''
export let resetScroll = false; export let resetScroll = false
/** Path level in URL, zero-indexed */ /** Path level in URL, zero-indexed */
export let level = 0; export let level = 0
let path: string[]; let path: string[]
$: path = [ $: path = [
...$page.url.pathname ...$page.url.pathname
.substring(1) .substring(1)
.split('/') .split('/')
.map((route) => '/' + route), .map((route) => '/' + route),
'/', '/',
]; ]
$: basePath = path.slice(0, level).join(''); $: basePath = path.slice(0, level).join('')
</script> </script>
<nav class="navigation"> <nav class="navigation">
{#each links as link} {#each links as link}
<a <a
href={query href={query
? link.href ? link.href
? `?${query}=${link.href}` ? `?${query}=${link.href}`
: '?' : '?'
: level === 0 : level === 0
? link.href ? link.href
: basePath + link.href} : basePath + link.href}
on:click={() => { on:click={() => {
if (resetScroll) document.body.scrollTo(0, 0); if (resetScroll) document.body.scrollTo(0, 0)
}} }}
class="navigation__link" class="navigation__link"
class:is-active={query class:is-active={query
? ($page.url.searchParams.get(query) || '') === link.href ? ($page.url.searchParams.get(query) || '') === link.href
: path[level] === link.href || path[level] === link.href.slice(0, -1)} : path[level] === link.href || path[level] === link.href.slice(0, -1)}
sveltekit:noscroll={!resetScroll}>{link.label}</a sveltekit:noscroll={!resetScroll}>{link.label}</a>
> {/each}
{/each}
</nav> </nav>
<style lang="postcss"> <style lang="postcss">
.navigation { .navigation {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
grid-gap: 1rem; grid-gap: 1rem;
flex-wrap: wrap; flex-wrap: wrap;
&__link { &__link {
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
color: var(--color-text-light); color: var(--color-text-light);
&.is-active { &.is-active {
color: var(--color-text); color: var(--color-text);
position: relative; position: relative;
&::after { &::after {
content: ''; content: '';
display: block; display: block;
position: absolute; position: absolute;
bottom: -0.1rem; bottom: -0.1rem;
width: 100%; width: 100%;
border-radius: var(--rounded-max); border-radius: var(--rounded-max);
height: 0.2rem; height: 0.2rem;
background-color: var(--color-brand); background-color: var(--color-brand);
} }
} }
} }
} }
</style> </style>

View File

@ -1,77 +1,75 @@
<script lang="ts"> <script lang="ts">
// TODO: Fix mobile support, currently just cuts off buttons // TODO: Fix mobile support, currently just cuts off buttons
import IconArrowRight from 'virtual:icons/heroicons-outline/arrow-right'; import IconArrowRight from 'virtual:icons/heroicons-outline/arrow-right'
import IconArrowLeft from 'virtual:icons/heroicons-outline/arrow-left'; import IconArrowLeft from 'virtual:icons/heroicons-outline/arrow-left'
import IconMinus from 'virtual:icons/heroicons-outline/minus'; import IconMinus from 'virtual:icons/heroicons-outline/minus'
import Button from './Button.svelte'; import Button from './Button.svelte'
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte'
export let page: number; export let page: number
export let count: number; export let count: number
$: options = $: options =
count > 4 count > 4
? page + 3 >= count ? page + 3 >= count
? [1, '-', count - 4, count - 3, count - 2, count - 1, count] ? [1, '-', count - 4, count - 3, count - 2, count - 1, count]
: page > 4 : page > 4
? [1, '-', page - 1, page, page + 1, '-', count] ? [1, '-', page - 1, page, page + 1, '-', count]
: [1, 2, 3, 4, 5, '-', count] : [1, 2, 3, 4, 5, '-', count]
: Array.from({ length: count }, (_, i) => i + 1); : Array.from({ length: count }, (_, i) => i + 1)
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher()
</script> </script>
{#if count > 1} {#if count > 1}
<div class="pagination"> <div class="pagination">
<Button <Button
color="raised" color="raised"
on:click={() => dispatch('change', page - 1)} on:click={() => dispatch('change', page - 1)}
disabled={page <= 1} disabled={page <= 1}
title="Last page" title="Last page"
><IconArrowLeft height="20px" /> ><IconArrowLeft height="20px" />
</Button> </Button>
{#each options as option} {#each options as option}
{#if option === '-'} {#if option === '-'}
<IconMinus class="pagination__dash" /> <IconMinus class="pagination__dash" />
{:else} {:else}
<Button <Button
color={option === page ? 'primary' : 'raised'} color={option === page ? 'primary' : 'raised'}
on:click={() => dispatch('change', option)}>{option}</Button on:click={() => dispatch('change', option)}>{option}</Button>
> {/if}
{/if} {/each}
{/each} <Button
<Button color="raised"
color="raised" on:click={() => dispatch('change', page + 1)}
on:click={() => dispatch('change', page + 1)} disabled={page >= count}
disabled={page >= count} title="Next page">
title="Next page" <IconArrowRight height="20px" />
> </Button>
<IconArrowRight height="20px" /> </div>
</Button>
</div>
{/if} {/if}
<style lang="postcss"> <style lang="postcss">
.pagination { .pagination {
align-self: center; align-self: center;
display: flex; display: flex;
grid-gap: 0.5rem; grid-gap: 0.5rem;
align-items: center; align-items: center;
:global(&__dash) { :global(&__dash) {
margin: 0 0.5rem; margin: 0 0.5rem;
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
} }
@media (width <= 500px) { @media (width <= 500px) {
grid-gap: 0.25rem; grid-gap: 0.25rem;
:global(> *:nth-child(4)), :global(> *:nth-child(4)),
:global(> *:nth-child(6)) { :global(> *:nth-child(6)) {
display: none; display: none;
} }
} }
} }
</style> </style>

View File

@ -1,204 +1,220 @@
<script lang="ts"> <script lang="ts">
import IconChevronDown from 'virtual:icons/lucide/chevron-down' import IconChevronDown from 'virtual:icons/lucide/chevron-down'
import { debounce } from 'throttle-debounce' import { debounce } from 'throttle-debounce'
import { clickOutside } from 'svelte-use-click-outside' import { clickOutside } from 'svelte-use-click-outside'
import { onMount } from 'svelte' import { onMount } from 'svelte'
interface Option { interface Option {
label: string; label: string
value: string | number; value: string | number
} }
export let options: Option[] = [] export let options: Option[] = []
export let value: string | number export let value: string | number
export let selected: Option = options.find((option) => option.value === (value || '')) export let selected: Option = options.find((option) => option.value === (value || ''))
export let color = '' export let color = ''
export let label = '' export let label = ''
export let icon = null export let icon = null
let open = false let open = false
$: if (selected) { $: if (selected) {
value = selected.value value = selected.value
} }
const minWidth = options // Returns the width of a string based on the font size and family
.map(it => it.label || it.value) const getTextWidth = Object.assign(
.reduce((it, acc) => String(it).length > acc ? it : acc, '') (text: string, font: string) => {
.length * 9 if (typeof document !== 'undefined') {
const canvas =
getTextWidth.canvas || (getTextWidth.canvas = document.createElement('canvas'))
const context = canvas.getContext('2d')
context.font = font
const metrics = context.measureText(text)
return metrics.width
} else {
// Return estimate if SSR
return text.length * 7.75
}
},
// Reuses the same canvas object
{ canvas: null }
)
let shouldOpenUp = false const minWidth = Math.max(
let element: HTMLElement ...options.map((it) => getTextWidth(String(it.label || it.value), '16px Inter'))
)
const checkShouldOpenUp = debounce(100, false, () => { let shouldOpenUp = false
if (element) { let element: HTMLElement
const bounding = element.getBoundingClientRect()
shouldOpenUp = const checkShouldOpenUp = debounce(100, false, () => {
bounding.bottom + 32 * options.length + 16 > if (element) {
(window.innerHeight || document.documentElement.clientHeight) const bounding = element.getBoundingClientRect()
}
})
onMount(() => { shouldOpenUp =
checkShouldOpenUp() bounding.bottom + 32 * options.length + 16 >
window.addEventListener('resize', checkShouldOpenUp) (window.innerHeight || document.documentElement.clientHeight)
}) }
})
function keydown(event: KeyboardEvent) { onMount(() => {
if ((event.key === ' ' || event.key === 'Enter') && !open) { checkShouldOpenUp()
open = true window.addEventListener('resize', checkShouldOpenUp)
} else if (event.key === 'ArrowUp') { })
if (selected) {
const index = options.findIndex((option) => option.value === selected.value) function keydown(event: KeyboardEvent) {
if (index > 0) { if ((event.key === ' ' || event.key === 'Enter') && !open) {
selected = options[index - 1] open = true
} } else if (event.key === 'ArrowUp') {
} if (selected) {
} else if (event.key === 'ArrowDown') { const index = options.findIndex((option) => option.value === selected.value)
if (selected) { if (index > 0) {
const index = options.findIndex((option) => option.value === selected.value) selected = options[index - 1]
if (index < options.length - 1) { }
selected = options[index + 1] }
} } else if (event.key === 'ArrowDown') {
} if (selected) {
} else if ((event.key === 'Escape' || event.key === 'Enter') && open) { const index = options.findIndex((option) => option.value === selected.value)
open = false if (index < options.length - 1) {
} selected = options[index + 1]
} }
}
} else if ((event.key === 'Escape' || event.key === 'Enter') && open) {
open = false
}
}
</script> </script>
<div <div
class="select select--color-{color}" class="select select--color-{color}"
class:is-open={open} class:is-open={open}
class:select--opens-up={shouldOpenUp} class:select--opens-up={shouldOpenUp}
use:clickOutside={() => { use:clickOutside={() => {
open = false; open = false
}} }}
bind:this={element} bind:this={element}
tabindex="0" tabindex="0"
on:keydown={keydown} on:keydown={keydown}>
> <div
<div class="select__input"
class="select__input" on:click={() => {
on:click={() => { open = !open
open = !open; }}>
}} {#if icon}
> <svelte:component this={icon} />
{#if icon} {/if}
<svelte:component this={icon}/> <span class="select__input__value" style:min-width="{minWidth}px"
{/if} >{label || selected?.label || value || 'Choose...'}</span>
<span class="select__input__value" style:min-width="{minWidth}px">{label || selected?.label || value || 'Choose...'}</span> {#if !icon}
{#if !icon} <div class="select__input__arrow">
<div class="select__input__arrow"> <slot name="expandIcon">
<slot name="expandIcon"> <IconChevronDown />
<IconChevronDown/> </slot>
</slot> </div>
</div> {/if}
{/if} </div>
</div> {#if open}
{#if open} <ul class="select__options">
<ul class="select__options"> {#each options as option (option.value)}
{#each options as option (option.value)} <li
<li on:click={() => {
on:click={() => { selected = option
selected = option; open = false
open = false;
}} }}
class:is-selected={selected?.value === option.value} class:is-selected={selected?.value === option.value}>
> {option.label || option.value}
{option.label || option.value} </li>
</li> {/each}
{/each} </ul>
</ul> {/if}
{/if}
</div> </div>
<style lang="postcss"> <style lang="postcss">
.select { .select {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
color: var(--color-button-text); color: var(--color-button-text);
cursor: pointer; cursor: pointer;
border-radius: var(--rounded); border-radius: var(--rounded);
align-self: flex-start; align-self: flex-start;
&__input { &__input {
display: flex; display: flex;
width: 100%; width: 100%;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0.25rem 0.9rem; padding: 0.25rem 0.9rem;
grid-gap: 0.4rem; grid-gap: 0.4rem;
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
box-shadow: var(--shadow-inset-sm); box-shadow: var(--shadow-inset-sm);
border-radius: var(--rounded); border-radius: var(--rounded);
} }
&__options { &__options {
list-style-type: none; list-style-type: none;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
padding: 0; padding: 0;
margin: 0; margin: 0;
position: absolute; position: absolute;
top: 100%; top: 100%;
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
border-radius: var(--rounded-bottom); border-radius: var(--rounded-bottom);
box-shadow: var(--shadow-inset-sm), var(--shadow-floating); box-shadow: var(--shadow-inset-sm), var(--shadow-floating);
overflow: hidden; overflow: hidden;
border-top: 0.1rem solid var(--color-divider); border-top: 0.1rem solid var(--color-divider);
z-index: 5; z-index: 5;
li { li {
padding: 0.25rem 1rem; padding: 0.25rem 1rem;
&:hover { &:hover {
background-color: var(--color-button-bg-hover); background-color: var(--color-button-bg-hover);
} }
&.is-selected { &.is-selected {
background-color: var(--color-brand-dark); background-color: var(--color-brand-dark);
color: var(--color-brand-contrast); color: var(--color-brand-contrast);
cursor: default; cursor: default;
} }
} }
} }
&.is-open { &.is-open {
z-index: 10; z-index: 10;
.select__input { .select__input {
border-radius: var(--rounded-top); border-radius: var(--rounded-top);
box-shadow: none; box-shadow: none;
&__arrow { &__arrow {
transform: rotate(180deg); transform: rotate(180deg);
} }
} }
} }
&--color-raised { &--color-raised {
> * { > * {
background-color: var(--color-raised-bg); background-color: var(--color-raised-bg);
} }
} }
&--opens-up { &--opens-up {
.select__options { .select__options {
bottom: 100%; bottom: 100%;
top: auto; top: auto;
border-radius: var(--rounded-top); border-radius: var(--rounded-top);
box-shadow: none; box-shadow: none;
border-top: none; border-top: none;
border-bottom: 0.1rem solid var(--color-divider); border-bottom: 0.1rem solid var(--color-divider);
} }
&.is-open .select__input { &.is-open .select__input {
border-radius: var(--rounded-bottom); border-radius: var(--rounded-bottom);
} }
} }
} }
</style> </style>

View File

@ -1,48 +1,48 @@
<script lang="ts"> <script lang="ts">
export let value: number; export let value: number
export let min: number; export let min: number
export let max: number; export let max: number
export let id: string = undefined; export let id: string = undefined
</script> </script>
<div class="slider"> <div class="slider">
<input class="slider-input" type="range" name={id} {min} {max} bind:value /> <input class="slider-input" type="range" name={id} {min} {max} bind:value />
<span>{value}</span> <span>{value}</span>
</div> </div>
<style lang="postcss"> <style lang="postcss">
.slider { .slider {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
.slider-input { .slider-input {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
border-radius: var(--rounded-sm); border-radius: var(--rounded-sm);
box-shadow: var(--shadow-inset-sm); box-shadow: var(--shadow-inset-sm);
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
border: none; border: none;
padding: 0.25rem 0; padding: 0.25rem 0;
width: 20rem; width: 20rem;
height: 0.5rem; height: 0.5rem;
max-width: 100%; max-width: 100%;
cursor: pointer; cursor: pointer;
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
cursor: ew-resize; cursor: ew-resize;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
width: 0.5rem; width: 0.5rem;
height: 1.25rem; height: 1.25rem;
border-radius: var(--rounded-sm); border-radius: var(--rounded-sm);
background-color: var(--color-brand); background-color: var(--color-brand);
&:hover { &:hover {
background-color: var(--color-brand-dark); background-color: var(--color-brand-dark);
} }
} }
} }
} }
</style> </style>

View File

@ -1,56 +1,56 @@
<script lang="ts"> <script lang="ts">
import type { SvelteComponent } from 'svelte'; import type { SvelteComponent } from 'svelte'
export let placeholder = ''; export let placeholder = ''
export let icon: SvelteComponent = undefined; export let icon: SvelteComponent = undefined
export let value = ''; export let value = ''
export let multiline = false; export let multiline = false
export let id: string = undefined; export let id: string = undefined
</script> </script>
<div class="text-input"> <div class="text-input">
{#if multiline} {#if multiline}
<textarea name={id} {placeholder} bind:value /> <textarea name={id} {placeholder} bind:value />
{:else} {:else}
<input type="text" name={id} {placeholder} bind:value class:has-icon={icon} /> <input type="text" name={id} {placeholder} bind:value class:has-icon={icon} />
{#if icon} {#if icon}
<svelte:component this={icon} /> <svelte:component this={icon} />
{/if} {/if}
{/if} {/if}
</div> </div>
<style lang="postcss"> <style lang="postcss">
.text-input { .text-input {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
position: relative; position: relative;
input, input,
textarea { textarea {
border-radius: var(--rounded-sm); border-radius: var(--rounded-sm);
box-shadow: var(--shadow-inset-sm); box-shadow: var(--shadow-inset-sm);
background-color: var(--color-button-bg); background-color: var(--color-button-bg);
border: none; border: none;
padding: 6px 14px; padding: 6px 14px;
width: 20rem; width: 20rem;
max-width: 100%; max-width: 100%;
} }
textarea { textarea {
min-height: 2.5rem; min-height: 2.5rem;
} }
:global(.icon) { :global(.icon) {
position: absolute; position: absolute;
display: flex; display: flex;
height: 100%; height: 100%;
left: 14px; left: 14px;
opacity: 0.75; opacity: 0.75;
} }
input.has-icon { input.has-icon {
padding-left: 40px; padding-left: 40px;
} }
} }
</style> </style>

View File

@ -43,7 +43,15 @@ export async function tags(API_URL) {
// Write JSON file // Write JSON file
await fs.writeFile( await fs.writeFile(
'./generated/tags.json', './generated/tags.json',
JSON.stringify({ categories, loaders, projectTypes, licenses, donationPlatforms, reportTypes, tagIcons }) JSON.stringify({
categories,
loaders,
projectTypes,
licenses,
donationPlatforms,
reportTypes,
tagIcons,
})
) )
progressBar.increment() progressBar.increment()

View File

@ -1,63 +1,63 @@
<script lang="ts"> <script lang="ts">
import '$package/styles.postcss'; import '$package/styles.postcss'
import '../docs/styles/prism-one-dark.css'; import '../docs/styles/prism-one-dark.css'
import '../docs/styles/gh-markdown.postcss'; import '../docs/styles/gh-markdown.postcss'
import Sidebar from '../docs/components/Sidebar.svelte'; import Sidebar from '../docs/components/Sidebar.svelte'
import Header from '../docs/components/Header.svelte'; import Header from '../docs/components/Header.svelte'
</script> </script>
<div class="app theme-light"> <div class="app theme-light">
<Header /> <Header />
<Sidebar /> <Sidebar />
<main class="app__content"> <main class="app__content">
<article> <article>
<slot /> <slot />
</article> </article>
</main> </main>
</div> </div>
<style lang="postcss"> <style lang="postcss">
:global { :global {
html { html {
overflow-y: scroll; overflow-y: scroll;
} }
body { body {
margin: 0; margin: 0;
font-size: var(--font-size); font-size: var(--font-size);
font-family: var(--body-font); font-family: var(--body-font);
--accent-color: hsl(331, 80%, 45%); --accent-color: hsl(331, 80%, 45%);
--accent-color-transparent: hsla(331, 80%, 45%, 0.15); --accent-color-transparent: hsla(331, 80%, 45%, 0.15);
} }
} }
.app { .app {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
overflow: hidden; overflow: hidden;
background-color: var(--color-bg); background-color: var(--color-bg);
--sidebar-width: 275px; --sidebar-width: 275px;
&__content { &__content {
@media (--md) { @media (--md) {
padding-left: var(--sidebar-width); padding-left: var(--sidebar-width);
} }
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
article { article {
max-width: 800px; max-width: 800px;
padding-block: 140px 64px; padding-block: 140px 64px;
padding-inline: 24px; padding-inline: 24px;
@media (--sm) { @media (--sm) {
padding-inline: 48px; padding-inline: 48px;
padding-block: 140px 24px; padding-block: 140px 24px;
} }
} }
} }
} }
</style> </style>

View File

@ -1,15 +1,15 @@
```svelte example raised ```svelte example raised
<script> <script>
import { Button } from 'omorphia' import { Button } from 'omorphia'
import IconHeartSolid from 'virtual:icons/heroicons-solid/heart' import IconHeartSolid from 'virtual:icons/heroicons-solid/heart'
import IconCalendar from 'virtual:icons/lucide/calendar' import IconCalendar from 'virtual:icons/lucide/calendar'
</script> </script>
<div class="actions"> <div class="actions">
<Button><IconHeartSolid /> Unfollow </Button> <Button><IconHeartSolid /> Unfollow</Button>
<span class="stat"> <span class="stat">
<IconCalendar/> <IconCalendar />
Updated 12 days ago Updated 12 days ago
</span> </span>
</div> </div>
``` ```

View File

@ -1,7 +1,5 @@
Base should be applied to a "root" element, like `<body>`, to provide base styles for common things like text. The theme mode, `light-theme`, `dark-theme`, or `oled-theme`, should also be added to this element. Base should be applied to a "root" element, like `<body>`, to provide base styles for common things like text. The theme mode, `light-theme`, `dark-theme`, or `oled-theme`, should also be added to this element.
```svelte example ```svelte example
<div class="base theme-light"> <div class="base theme-light">...</div>
...
</div>
``` ```

View File

@ -2,11 +2,13 @@
```svelte example ```svelte example
<div class="card"> <div class="card">
<h3>Moon/Distance to Earth</h3> <h3>Moon/Distance to Earth</h3>
<h2>238,900 mi</h2> <h2>238,900 mi</h2>
<p> <p>
The moon's distance from Earth affects the strength of ocean tides and the appearance of solar eclipses in our skies. The average distance between the blue planet and its only natural satellite is about 238,855 miles (384,400 kilometers), according to NASA. The moon's distance from Earth affects the strength of ocean tides and the appearance of solar
</p> eclipses in our skies. The average distance between the blue planet and its only natural
satellite is about 238,855 miles (384,400 kilometers), according to NASA.
</p>
</div> </div>
``` ```
@ -14,18 +16,18 @@
```svelte example ```svelte example
<script lang="ts"> <script lang="ts">
import { Button } from "omorphia"; import { Button } from 'omorphia'
import IconPencil from 'virtual:icons/heroicons-outline/pencil' import IconPencil from 'virtual:icons/heroicons-outline/pencil'
import { Avatar } from "omorphia"; import { Avatar } from 'omorphia'
</script> </script>
<div class="card"> <div class="card">
<div class="card__overlay"> <div class="card__overlay">
<Button color="raised"><IconPencil /> Edit</Button> <Button color="raised"><IconPencil /> Edit</Button>
</div> </div>
<div class="card__banner card__banner--short card__banner--dark" ></div> <div class="card__banner card__banner--short card__banner--dark" />
<Avatar size="md" floatUp/> <Avatar size="md" floatUp />
<h1 class="title">Project</h1> <h1 class="title">Project</h1>
<p class="summary">A project that has a description right here.</p> <p class="summary">A project that has a description right here.</p>
</div> </div>
``` ```

View File

@ -6,8 +6,8 @@ Some words could go here.
And some other words could go here. And some other words could go here.
<style> <style>
.example__source__code { .example__source__code {
flex-direction: column; flex-direction: column;
} }
</style> </style>
``` ```

View File

@ -1,10 +1,10 @@
```svelte example raised ```svelte example raised
<div class="info-table"> <div class="info-table">
<span class="info-table__label">License</span> <span class="info-table__label">License</span>
<a href="#mit" class="link">MIT</a> <a href="#mit" class="link">MIT</a>
<span class="info-table__label">Project ID</span> <span class="info-table__label">Project ID</span>
<span>11223344</span> <span>11223344</span>
<span class="info-table__label">Visibilty</span> <span class="info-table__label">Visibilty</span>
<span>Approved</span> <span>Approved</span>
</div> </div>
``` ```

View File

@ -8,15 +8,15 @@
```svelte example raised ```svelte example raised
<script> <script>
import IconIssues from 'virtual:icons/heroicons-outline/exclamation' import IconIssues from 'virtual:icons/heroicons-outline/exclamation'
import IconCode from 'virtual:icons/heroicons-outline/code' import IconCode from 'virtual:icons/heroicons-outline/code'
import IconClock from 'virtual:icons/lucide/flag-triangle-right' import IconClock from 'virtual:icons/lucide/flag-triangle-right'
import IconWiki from 'virtual:icons/heroicons-outline/book-open' import IconWiki from 'virtual:icons/heroicons-outline/book-open'
</script> </script>
<div class="link-group"> <div class="link-group">
<a class="link" href="#issues"><IconIssues /> Issues</a> <a class="link" href="#issues"><IconIssues /> Issues</a>
<a class="link" href="#source"><IconCode /> Source</a> <a class="link" href="#source"><IconCode /> Source</a>
<a class="link" href="#wiki"><IconWiki /> Wiki</a> <a class="link" href="#wiki"><IconWiki /> Wiki</a>
</div> </div>
``` ```

View File

@ -1,13 +1,13 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Avatar } from "omorphia"; import { Avatar } from 'omorphia'
</script> </script>
<a class="member" href="#user"> <a class="member" href="#user">
<Avatar src="https://avatars1.githubusercontent.com/u/6166773" size="sm" circle/> <Avatar src="https://avatars1.githubusercontent.com/u/6166773" size="sm" circle />
<div class="member__info"> <div class="member__info">
<span class="member__info__link">Prospector</span> <span class="member__info__link">Prospector</span>
<span>Owner</span> <span>Owner</span>
</div> </div>
</a> </a>
``` ```

View File

@ -2,12 +2,12 @@
```svelte example raised ```svelte example raised
<script> <script>
import IconStar from 'virtual:icons/heroicons-outline/star' import IconStar from 'virtual:icons/heroicons-outline/star'
</script> </script>
<div class="stat"> <div class="stat">
<IconStar/> <IconStar />
123K stars 123K stars
</div> </div>
``` ```
@ -15,18 +15,18 @@
```svelte example raised ```svelte example raised
<script> <script>
import IconDownload from 'virtual:icons/heroicons-outline/download' import IconDownload from 'virtual:icons/heroicons-outline/download'
import IconHeart from 'virtual:icons/heroicons-outline/heart' import IconHeart from 'virtual:icons/heroicons-outline/heart'
</script> </script>
<div class="stat-group"> <div class="stat-group">
<div class="stat"> <div class="stat">
<IconDownload/> <IconDownload />
4.1B downloads 4.1B downloads
</div> </div>
<div class="stat stat--light"> <div class="stat stat--light">
<IconHeart/> <IconHeart />
3 followers 3 followers
</div> </div>
</div> </div>
``` ```

View File

@ -1,15 +1,15 @@
```svelte example raised ```svelte example raised
<script> <script>
import IconCarrot from 'virtual:icons/lucide/carrot' import IconCarrot from 'virtual:icons/lucide/carrot'
import IconGlobe from 'virtual:icons/heroicons-outline/globe' import IconGlobe from 'virtual:icons/heroicons-outline/globe'
</script> </script>
<div class="tag-group"> <div class="tag-group">
<div class="tag"> <div class="tag">
<IconCarrot/> Food <IconCarrot /> Food
</div> </div>
<div class="tag"> <div class="tag">
<IconGlobe/> World generation <IconGlobe /> World generation
</div> </div>
</div> </div>
``` ```

View File

@ -2,12 +2,14 @@ Avatars are used for project icons and user profile pictures. Low resolution ima
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Avatar } from "omorphia"; import { Avatar } from 'omorphia'
</script> </script>
<Avatar size="lg" circle src="https://avatars3.githubusercontent.com/u/44736536?v=4" /> <Avatar size="lg" circle src="https://avatars3.githubusercontent.com/u/44736536?v=4" />
<Avatar size="md" src="https://cdn.modrinth.com/data/AANobbMI/icon.png" /> <Avatar size="md" src="https://cdn.modrinth.com/data/AANobbMI/icon.png" />
<Avatar size="md" src="https://staging-cdn.modrinth.com/data/d1SqMrzw/9a39b0c80a49976b0c04053682708374e18105fe.png" /> <Avatar
size="md"
src="https://staging-cdn.modrinth.com/data/d1SqMrzw/9a39b0c80a49976b0c04053682708374e18105fe.png" />
<Avatar size="sm" /> <Avatar size="sm" />
<Avatar size="xs" circle src="https://avatars1.githubusercontent.com/u/6166773?v=4" /> <Avatar size="xs" circle src="https://avatars1.githubusercontent.com/u/6166773?v=4" />
``` ```

View File

@ -1,6 +1,6 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Badge } from "omorphia"; import { Badge } from 'omorphia'
</script> </script>
<Badge color="red" label="Tomato" /> <Badge color="red" label="Tomato" />

View File

@ -2,8 +2,8 @@
```svelte example ```svelte example
<script lang="ts"> <script lang="ts">
import { Button } from "omorphia"; import { Button } from 'omorphia'
import IconDownload from 'virtual:icons/heroicons-outline/download' import IconDownload from 'virtual:icons/heroicons-outline/download'
</script> </script>
<Button color="raised"><IconDownload /> Download</Button> <Button color="raised"><IconDownload /> Download</Button>
@ -13,21 +13,21 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Button } from "omorphia"; import { Button } from 'omorphia'
import IconDownload from 'virtual:icons/heroicons-outline/download' import IconDownload from 'virtual:icons/heroicons-outline/download'
</script> </script>
<div class="button-group"> <div class="button-group">
<Button>Default</Button> <Button>Default</Button>
<Button color="raised">Raised</Button> <Button color="raised">Raised</Button>
<Button color="primary">Primary</Button> <Button color="primary">Primary</Button>
<Button color="primary-light">Light primary</Button> <Button color="primary-light">Light primary</Button>
<Button color="secondary">Secondary</Button> <Button color="secondary">Secondary</Button>
<Button color="tertiary">Tertiary</Button> <Button color="tertiary">Tertiary</Button>
<Button color="danger">Danger</Button> <Button color="danger">Danger</Button>
<Button color="danger-light">Light danger</Button> <Button color="danger-light">Light danger</Button>
<Button color="transparent">Transparent</Button> <Button color="transparent">Transparent</Button>
<Button disabled>Disabled</Button> <Button disabled>Disabled</Button>
</div> </div>
``` ```
@ -35,13 +35,13 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Button } from "omorphia"; import { Button } from 'omorphia'
import IconDownload from 'virtual:icons/heroicons-outline/download' import IconDownload from 'virtual:icons/heroicons-outline/download'
import IconHeart from 'virtual:icons/heroicons-outline/heart' import IconHeart from 'virtual:icons/heroicons-outline/heart'
</script> </script>
<div class="button-group"> <div class="button-group">
<Button color="primary"><IconDownload /></Button> <Button color="primary"><IconDownload /></Button>
<Button><IconHeart /> Follow mod </Button> <Button><IconHeart /> Follow mod</Button>
</div> </div>
``` ```

View File

@ -2,7 +2,7 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Checkbox } from "omorphia"; import { Checkbox } from 'omorphia'
</script> </script>
<Checkbox>Extra components</Checkbox> <Checkbox>Extra components</Checkbox>
@ -12,9 +12,9 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Checkbox } from "omorphia"; import { Checkbox } from 'omorphia'
import IconCarrot from 'virtual:icons/lucide/carrot' import IconCarrot from 'virtual:icons/lucide/carrot'
</script> </script>
<Checkbox><IconCarrot /> Food </Checkbox> <Checkbox><IconCarrot /> Food</Checkbox>
``` ```

View File

@ -1,37 +1,36 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { CheckboxList } from "omorphia"; import { CheckboxList } from 'omorphia'
import IconSquare from 'virtual:icons/lucide/square' import IconSquare from 'virtual:icons/lucide/square'
import IconCircle from 'virtual:icons/lucide/circle' import IconCircle from 'virtual:icons/lucide/circle'
import IconTriangle from 'virtual:icons/lucide/triangle' import IconTriangle from 'virtual:icons/lucide/triangle'
let selected = [] let selected = []
</script> </script>
<CheckboxList <CheckboxList
bind:value={selected} bind:value={selected}
options={[ options={[
{ {
label: 'Circle', label: 'Circle',
icon: IconCircle, icon: IconCircle,
value: 'CIR', value: 'CIR',
}, },
{ {
label: 'Triangle', label: 'Triangle',
icon: IconTriangle, icon: IconTriangle,
value: 'TRI', value: 'TRI',
}, },
{ {
label: 'Square', label: 'Square',
icon: IconSquare, icon: IconSquare,
value: 'SQU', value: 'SQU',
}, },
{ {
label: 'Blank', label: 'Blank',
value: 'BLA', value: 'BLA',
}, },
]} ]} />
/>
Selected: {selected} Selected: {selected}
``` ```

View File

@ -1,23 +1,21 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { CheckboxVirtualList } from "omorphia"; import { CheckboxVirtualList } from 'omorphia'
import IconStar from 'virtual:icons/heroicons-outline/star' import IconStar from 'virtual:icons/heroicons-outline/star'
import { uniqueId } from 'omorphia/utils/uniqueId' import { uniqueId } from 'omorphia/utils/uniqueId'
let options = Array(100).fill({}) let options = Array(100)
.map(option => ({ .fill({})
label: 'Star-' + uniqueId(), .map((option) => ({
icon: IconStar, label: 'Star-' + uniqueId(),
value: uniqueId(), icon: IconStar,
})) value: uniqueId(),
}))
let selected = ['2', '6'] let selected = ['2', '6']
</script> </script>
<CheckboxVirtualList <CheckboxVirtualList bind:value={selected} {options} />
bind:value={selected}
{options}
/>
Selected: {selected} Selected: {selected}
``` ```

View File

@ -2,42 +2,46 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Chips } from "omorphia"; import { Chips } from 'omorphia'
</script> </script>
<Chips options={[ <Chips
{ options={[
label: 'One', {
value: 'one' label: 'One',
}, value: 'one',
{ },
label: 'Two', {
value: 'two' label: 'Two',
}]} value: 'two',
/> },
]} />
``` ```
### Force an option to be selected with `neverEmpty` ### Force an option to be selected with `neverEmpty`
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Chips } from "omorphia"; import { Chips } from 'omorphia'
let foo = 'modpack' let foo = 'modpack'
</script> </script>
<Chips neverEmpty bind:value={foo} options={[ <Chips
{ neverEmpty
label: 'Mod', bind:value={foo}
value: 'mod' options={[
}, {
{ label: 'Mod',
label: 'Modpack', value: 'mod',
value: 'modpack' },
}, {
{ label: 'Modpack',
label: 'World', value: 'modpack',
value: 'world' },
}]} {
/> label: 'World',
value: 'world',
},
]} />
``` ```

View File

@ -1,14 +1,14 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { FormField } from "omorphia"; import { FormField } from 'omorphia'
import { Slider } from "omorphia"; import { Slider } from 'omorphia'
import { TextInput } from "omorphia"; import { TextInput } from 'omorphia'
</script> </script>
<FormField label="Favorite number"> <FormField label="Favorite number">
<Slider min=0 max=100 value=69 /> <Slider min="0" max="100" value="69" />
</FormField> </FormField>
<FormField label="Favorite color"> <FormField label="Favorite color">
<TextInput placeholder="Enter another color..." /> <TextInput placeholder="Enter another color..." />
</FormField> </FormField>
``` ```

View File

@ -2,25 +2,25 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { NavRow } from "omorphia"; import { NavRow } from 'omorphia'
</script> </script>
<NavRow <NavRow
level={1} level={1}
links={[ links={[
{ {
href: '/Button', href: '/Button',
label: 'Button' label: 'Button',
}, },
{ {
href: '/Chips', href: '/Chips',
label: 'Chips' label: 'Chips',
}, },
{ {
href: '/NavRow', href: '/NavRow',
label: 'NavRow' label: 'NavRow',
} },
]}> ]}>
Click for fun Click for fun
</NavRow> </NavRow>
``` ```

View File

@ -2,7 +2,7 @@ Use pagination to show a set of page numbers and navigation directions to move t
```svelte example ```svelte example
<script lang="ts"> <script lang="ts">
import { Pagination } from "omorphia" import { Pagination } from 'omorphia'
</script> </script>
<Pagination page={20} count={50} /> <Pagination page={20} count={50} />

View File

@ -1,19 +1,17 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Select } from "omorphia"; import { Select } from 'omorphia'
let sortMethod = "downloads" let sortMethod = 'downloads'
</script> </script>
<Select <Select
color="raised" options={[
options={[ { value: '', label: 'Relevance' },
{ value: "", label: "Relevance" }, { value: 'downloads', label: 'Downloads' },
{ value: "downloads", label: "Downloads" }, { value: 'follows', label: 'Followers' },
{ value: "follows", label: "Followers" }, { value: 'newest', label: 'Recently' },
{ value: "newest", label: "Recently created" }, { value: 'updated', label: 'Recently updated really fast whoot' },
{ value: "updated", label: "Recently updated" }, ]}
]} bind:value={sortMethod} />
bind:value={sortMethod}
/>
``` ```

View File

@ -1,7 +1,7 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Slider } from "omorphia"; import { Slider } from 'omorphia'
</script> </script>
<Slider min=0 max=10 value=4 /> <Slider min="0" max="10" value="4" />
``` ```

View File

@ -1,7 +1,7 @@
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { TextInput } from "omorphia"; import { TextInput } from 'omorphia'
import IconSearch from 'virtual:icons/heroicons-outline/search' import IconSearch from 'virtual:icons/heroicons-outline/search'
</script> </script>
<TextInput placeholder="Enter another color..." /> <TextInput placeholder="Enter another color..." />

View File

@ -20,8 +20,8 @@ Then use the icon as if it were a Svelte component:
```svelte example ```svelte example
<script lang="ts"> <script lang="ts">
import IconHeart from 'virtual:icons/heroicons-outline/heart' import IconHeart from 'virtual:icons/heroicons-outline/heart'
</script> </script>
<p> That's lovely <IconHeart height="14px" />! </p> <p>That's lovely <IconHeart height="14px" />!</p>
``` ```

View File

@ -14,7 +14,7 @@ Import the SVG in the `<script>` of your svelte file, and treat the illustration
```svelte ```svelte
<script> <script>
import NoData from '$assets/images/illustrations/undraw_no_data.svg' import NoData from '$assets/images/illustrations/undraw_no_data.svg'
</script> </script>
<NoData /> <NoData />

View File

@ -14,16 +14,17 @@ The `markdown` parser is designed for bodies of markdown text and supports image
```svelte example ```svelte example
<script lang="ts"> <script lang="ts">
import { markdown } from "omorphia/utils" import { markdown } from 'omorphia/utils'
const source = '## Example markdown \n\ const source =
'## Example markdown \n\
This is **some** *text*! \n\ This is **some** *text*! \n\
#### An image \n\ #### An image \n\
<img src="https://cdn.modrinth.com/data/YL57xq9U/images/d382106b9a2b943d06107c31c139c77849f1a0e8.png" />' <img src="https://cdn.modrinth.com/data/YL57xq9U/images/d382106b9a2b943d06107c31c139c77849f1a0e8.png" />'
</script> </script>
<div class="card markdown"> <div class="card markdown">
{@html markdown(source)} {@html markdown(source)}
</div> </div>
``` ```
@ -33,9 +34,9 @@ The `markdownInline` parser is perfect for translations and short bios. It doesn
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { markdownInline } from "omorphia/utils" import { markdownInline } from 'omorphia/utils'
const source = "This is some **bolded** and *italicized* text." const source = 'This is some **bolded** and *italicized* text.'
</script> </script>
<p>{@html markdownInline(source)}</p> <p>{@html markdownInline(source)}</p>
@ -45,7 +46,7 @@ The `markdownInline` parser is perfect for translations and short bios. It doesn
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { ago } from 'omorphia/utils'; import { ago } from 'omorphia/utils'
</script> </script>
<p>Something happened {ago(Date.now())}.</p> <p>Something happened {ago(Date.now())}.</p>
@ -60,19 +61,19 @@ The `Permissions` class provides an easy way to manage user permissions.
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Permissions } from 'omorphia/utils' import { Permissions } from 'omorphia/utils'
const permissions = new Permissions(128) // Can be integer or 'ALL' const permissions = new Permissions(128) // Can be integer or 'ALL'
</script> </script>
<p> <p>
<input type="checkbox" bind:checked={permissions.uploadVersions} id="ex-1"/> <input type="checkbox" bind:checked={permissions.uploadVersions} id="ex-1" />
<label for="ex-1">Can edit versions</label><br> <label for="ex-1">Can edit versions</label><br />
<input type="checkbox" bind:checked={permissions.deleteProject} id="ex-2"/> <input type="checkbox" bind:checked={permissions.deleteProject} id="ex-2" />
<label for="ex-2">Can delete project</label><br><br> <label for="ex-2">Can delete project</label><br /><br />
Integer: {permissions.toInteger()}<br> Integer: {permissions.toInteger()}<br />
Can access settings page: {permissions.settingsPage} Can access settings page: {permissions.settingsPage}
</p> </p>
``` ```
@ -82,8 +83,8 @@ The `formatVersions` function provides an easy way to parse a project's versions
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { formatVersions } from 'omorphia/utils'; import { formatVersions } from 'omorphia/utils'
</script> </script>
<p>{formatVersions(["1.18", "1.18.1", "1.18.2", "1.17.1"])}</p> <p>{formatVersions(['1.18', '1.18.1', '1.18.2', '1.17.1'])}</p>
``` ```

View File

@ -22,7 +22,7 @@ Use a component by importing from `omorphia`. For example, use the [Button compo
```svelte example raised ```svelte example raised
<script lang="ts"> <script lang="ts">
import { Button } from "omorphia" import { Button } from 'omorphia'
</script> </script>
<Button color="primary">I'm a button!</Button> <Button color="primary">I'm a button!</Button>