Fix CheckBoxList SVG icons + Move docs source

This commit is contained in:
venashial
2022-05-25 17:22:54 -07:00
parent 8da6572074
commit 4ffc90f963
21 changed files with 284 additions and 250 deletions

View File

@@ -1,5 +1,6 @@
import { defineMDSveXConfig as defineConfig } from 'mdsvex'; import { defineMDSveXConfig as defineConfig } from 'mdsvex';
import examples from 'mdsvexamples'; import examples from 'mdsvexamples';
import path from 'path';
const config = defineConfig({ const config = defineConfig({
extensions: ['.svelte.md', '.md', '.svx'], extensions: ['.svelte.md', '.md', '.svx'],
@@ -13,7 +14,7 @@ const config = defineConfig({
examples, examples,
{ {
defaults: { defaults: {
Wrapper: '$routes/_internal/components/Example.svelte', Wrapper: path.resolve('./src/docs/components/Example.svelte'),
}, },
}, },
], ],
@@ -21,7 +22,7 @@ const config = defineConfig({
rehypePlugins: [], rehypePlugins: [],
layout: { layout: {
_: './src/routes/_internal/layout/page.svelte', _: './src/docs/layout/page.svelte',
}, },
}); });

View File

@@ -25,7 +25,7 @@ export default function sveld() {
const componentFiles = await fs.readdir(path.resolve('./src/package/components')); const componentFiles = await fs.readdir(path.resolve('./src/package/components'));
for (const fileName of componentFiles) { for (const fileName of componentFiles.filter((name) => name.endsWith('.svelte'))) {
const filePath = path.resolve('./src/package/components', fileName); const filePath = path.resolve('./src/package/components', fileName);
const raw = (await fs.readFile(filePath)).toString(); const raw = (await fs.readFile(filePath)).toString();
output[fileName] = await parseRaw(raw, filePath); output[fileName] = await parseRaw(raw, filePath);

View File

Before

Width:  |  Height:  |  Size: 728 B

After

Width:  |  Height:  |  Size: 728 B

View File

@@ -1,43 +1,42 @@
<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> <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> <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;
@@ -51,7 +50,8 @@
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, hsla(221, 39%, 11%, 0.05) 0 -2px 2px 0 inset; box-shadow: hsla(221, 39%, 11%, 0.2) 0 2px 4px 0,
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) {
@@ -109,4 +109,4 @@
width: 5px; width: 5px;
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
} }
</style> </style>

View File

@@ -3,12 +3,12 @@
import IconMenu from 'virtual:icons/lucide/menu'; import IconMenu from 'virtual:icons/lucide/menu';
const components = Object.keys(import.meta.glob('../../components/**')) const components = Object.keys(import.meta.glob('../../routes/components/**'))
.map((it) => it.replace('../../components/', '').replace('.md', '')) .map((it) => it.replace('../../routes/components/', '').replace('.md', ''))
.sort(); .sort();
const classes = Object.keys(import.meta.glob('../../classes/**')) const classes = Object.keys(import.meta.glob('../../routes/classes/**'))
.map((it) => it.replace('../../classes/', '').replace('.md', '')) .map((it) => it.replace('../../routes/classes/', '').replace('.md', ''))
.sort(); .sort();
let slideIn = false; let slideIn = false;

147
src/docs/layout/page.svelte Normal file
View File

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

7
src/global.d.ts vendored
View File

@@ -1 +1,8 @@
/// <reference types="vite-plugin-sveld" /> /// <reference types="vite-plugin-sveld" />
declare module '$assets/images/*';
declare module '$locales/*';
declare module '*.svg' {
export { SvelteComponentDev as default } from 'svelte/internal';
}

View File

@@ -1,58 +1,63 @@
<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(['avatar', circle && 'avatar--circle', `avatar--size-${size}`, floatUp && 'avatar--float-up']) $: className = classCombine([
'avatar',
circle && 'avatar--circle',
`avatar--size-${size}`,
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">
@@ -67,21 +72,21 @@
&-xs { &-xs {
--size: 2.25rem; --size: 2.25rem;
box-shadow: var(--shadow-inset), var(--shadow-raised); box-shadow: var(--shadow-inset), var(--shadow-raised);
border-radius: var(--rounded-sm);
} }
&-sm { &-sm {
--size: 3rem; --size: 3rem;
box-shadow: var(--shadow-inset), var(--shadow-raised); box-shadow: var(--shadow-inset), var(--shadow-raised);
border-radius: var(--rounded-sm);
} }
&-md { &-md {
--size: 6rem; --size: 6rem;
border-radius: var(--rounded-lg);
} }
&-lg { &-lg {
--size: 9rem; --size: 9rem;
border-radius: var(--rounded-lg);
} }
} }

View File

@@ -1,32 +1,30 @@
<script lang="ts"> <script lang="ts">
import Checkbox from './Checkbox.svelte' import Checkbox from './Checkbox.svelte';
import type { SvelteComponent } from 'svelte' import type { Option } from './types';
interface Option { export let value = [];
label: string; export let options: Option[] = [];
/** The element that will be in the `value` array while the option is checked */
value: string | number;
icon: SvelteComponent;
}
export let value = [] /** Wrap the options horizontally */
export let options: Option[] = [] 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"> <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} {#if option.icon && typeof option.icon === 'string'}
<svelte:component this={option.icon}/> {@html option.icon}
{:else if option.icon}
<svelte:component this={option.icon} />
{/if} {/if}
{option.label} {option.label}
</Checkbox> </Checkbox>
@@ -45,4 +43,4 @@
grid-gap: 2rem; grid-gap: 2rem;
} }
} }
</style> </style>

View File

@@ -1,43 +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 type { SvelteComponent } from 'svelte' import VirtualList from 'svelte-tiny-virtual-list';
import VirtualList from 'svelte-tiny-virtual-list' import type { Option } from './types';
interface Option {
label: string;
/** The element that will be in the `value` array while the option is checked */
value: string | number;
icon: SvelteComponent;
}
/** 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 <VirtualList width="100%" {height} itemCount={options.length} itemSize={26}>
width="100%" <div
{height} slot="item"
itemCount={options.length} let:index
itemSize={26}> let:style
<div slot="item" let:index let:style {style} style:padding-bottom={(options.length) - 1 === index ? '2.5rem' : ''}> {style}
style:padding-bottom={options.length - 1 === index ? '2.5rem' : ''}
>
{@const option = options[index]} {@const option = options[index]}
<Checkbox checked={value.includes(option.value)} on:change={(e) => handleChange(e, option.value)}> <Checkbox
{#if option.icon} checked={value.includes(option.value)}
<svelte:component this={option.icon}/> on:change={(e) => handleChange(e, option.value)}
>
{#if option.icon && typeof option.icon === 'string'}
{@html option.icon}
{:else if option.icon}
<svelte:component this={option.icon} />
{/if} {/if}
{option.label} {option.label}
</Checkbox> </Checkbox>

View File

@@ -2,7 +2,7 @@
import type { SvelteComponent } from 'svelte'; import type { SvelteComponent } from 'svelte';
export let placeholder = ''; export let placeholder = '';
export let icon: SvelteComponent; 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;
@@ -50,7 +50,7 @@
} }
input.has-icon { input.has-icon {
padding-left: 40px; padding-left: 40px;
} }
} }
</style> </style>

8
src/package/components/types.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
import type { SvelteComponentDev } from 'svelte/internal';
export interface Option {
label: string;
/** The element that will be in the `value` array while the option is checked */
value: string | number;
icon?: SvelteComponentDev | string;
}

View File

@@ -6,7 +6,7 @@
position: relative; position: relative;
background-color: var(--color-raised-bg); background-color: var(--color-raised-bg);
border-radius: var(--rounded); border-radius: var(--rounded-lg);
overflow: hidden; overflow: hidden;
box-shadow: var(--shadow-raised), var(--shadow-inset); box-shadow: var(--shadow-raised), var(--shadow-inset);

View File

@@ -31,7 +31,7 @@
--color-bg-contrast: hsl(0, 0%, 100%); --color-bg-contrast: hsl(0, 0%, 100%);
--color-raised-bg: hsl(220, 13%, 25%); --color-raised-bg: hsl(220, 13%, 25%);
--color-divider: hsl(220, 13%, 50%); --color-divider: hsl(220, 13%, 50%);
--color-button-bg: hsl(220, 5%, 32%); --color-button-bg: hsl(222, 13%, 35%);
/* Label colors */ /* Label colors */
--color-badge-gray-text: hsl(0, 2%, 69%); --color-badge-gray-text: hsl(0, 2%, 69%);

View File

@@ -7,7 +7,7 @@
/* Rounded radii */ /* Rounded radii */
--rounded-sm: 8px; --rounded-sm: 8px;
--rounded: 10px; --rounded: 10px;
--rounded-lg: 12px; --rounded-lg: 14px;
--rounded-max: 100px; --rounded-max: 100px;
--rounded-top: var(--rounded) var(--rounded) 0 0; --rounded-top: var(--rounded) var(--rounded) 0 0;
--rounded-bottom: 0 0 var(--rounded) var(--rounded); --rounded-bottom: 0 0 var(--rounded) var(--rounded);

View File

@@ -1,14 +1,14 @@
<script lang="ts"> <script lang="ts">
import '$package/styles.postcss' import '$package/styles.postcss';
import './_internal/styles/prism-one-dark.css' import '../docs/styles/prism-one-dark.css';
import './_internal/styles/gh-markdown.postcss' import '../docs/styles/gh-markdown.postcss';
import Sidebar from './_internal/components/Sidebar.svelte' import Sidebar from '../docs/components/Sidebar.svelte';
import Header from './_internal/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 />
@@ -60,4 +60,4 @@
} }
} }
} }
</style> </style>

View File

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

View File

@@ -26,6 +26,10 @@
icon: IconSquare, icon: IconSquare,
value: 'SQU', value: 'SQU',
}, },
{
label: 'Blank',
value: 'BLA',
},
]} ]}
/> />