You've already forked AstralRinth
forked from didirus/AstralRinth
Add Field
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 25 25">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 25 25" aria-hidden="true">
|
||||||
<path stroke="var(--accent-color)" stroke-width="2" d="M15.933 18.394c-3.261-.286-11.074-1.466-14.644-8.469m22.422 0c-2.114 4.291-10.8 11.927-16.017 13.026m6.18-21.87C10.268 3.06 5.496 9.72 5.633 14.388m17.732-5.664c-2.232-1.888-9.562-5.15-16.943 1.716m8.652-3.947c1.888 1.087 5.492 3.288 4.806 8.369m-9.956 2.787c-.286-1.888-.103-6.213 2.918-8.41m4.12 4.977a2.43 2.43 0 0 0-.075-.4m0 0c-.528-1.965-2.354-5.652-6.963-5.908m6.963 5.908c-2.856 2.601-6.11 3.11-7.65 2.975m7.65-2.975c.752-.685 1.702-2.374 2.36-3.376m-8.98 2.575c.687.744 3.468 2.369 4.978 2.231M24 12.5C24 18.851 18.851 24 12.5 24S1 18.851 1 12.5 6.149 1 12.5 1 24 6.149 24 12.5Z"/>
|
<path stroke="var(--accent-color)" stroke-width="2" d="M15.933 18.394c-3.261-.286-11.074-1.466-14.644-8.469m22.422 0c-2.114 4.291-10.8 11.927-16.017 13.026m6.18-21.87C10.268 3.06 5.496 9.72 5.633 14.388m17.732-5.664c-2.232-1.888-9.562-5.15-16.943 1.716m8.652-3.947c1.888 1.087 5.492 3.288 4.806 8.369m-9.956 2.787c-.286-1.888-.103-6.213 2.918-8.41m4.12 4.977a2.43 2.43 0 0 0-.075-.4m0 0c-.528-1.965-2.354-5.652-6.963-5.908m6.963 5.908c-2.856 2.601-6.11 3.11-7.65 2.975m7.65-2.975c.752-.685 1.702-2.374 2.36-3.376m-8.98 2.575c.687.744 3.468 2.369 4.978 2.231M24 12.5C24 18.851 18.851 24 12.5 24S1 18.851 1 12.5 6.149 1 12.5 1 24 6.149 24 12.5Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 728 B After Width: | Height: | Size: 747 B |
@@ -48,7 +48,8 @@
|
|||||||
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"
|
||||||
|
aria-hidden="true">
|
||||||
<path fill="none" d="M0 0h103.4v103.4H0z" />
|
<path fill="none" d="M0 0h103.4v103.4H0z" />
|
||||||
<path
|
<path
|
||||||
fill="none"
|
fill="none"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<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
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
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 */
|
||||||
@@ -42,16 +42,22 @@
|
|||||||
`button--color-${color}`,
|
`button--color-${color}`,
|
||||||
badge && 'has-badge',
|
badge && 'has-badge',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
function dispatchClick() {
|
||||||
|
if (!disabled) dispatch('click')
|
||||||
|
}
|
||||||
</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={dispatchClick}>
|
||||||
<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={dispatchClick} />
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:element this={as} class={className} {disabled} {title} on:click>
|
<svelte:element this={as} class={className} {disabled} {title} on:click={dispatchClick}>
|
||||||
<slot />
|
<slot />
|
||||||
</svelte:element>
|
</svelte:element>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -76,13 +82,14 @@
|
|||||||
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.2s ease-in-out, transform 0.05s ease-in-out;
|
transition: opacity 0.5s ease-in-out, filter 0.2s ease-in-out, transform 0.05s ease-in-out,
|
||||||
|
outline 0.2s ease-in-out;
|
||||||
|
|
||||||
&:hover:not(&--color-transparent) {
|
&:hover:not(&--color-transparent, &:disabled) {
|
||||||
filter: brightness(0.85);
|
filter: brightness(0.85);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active:not(&--color-transparent) {
|
&:active:not(&--color-transparent, &:disabled) {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
filter: brightness(0.8);
|
filter: brightness(0.8);
|
||||||
}
|
}
|
||||||
@@ -140,9 +147,6 @@
|
|||||||
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 */
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&--pad-even {
|
&--pad-even {
|
||||||
|
|||||||
46
src/package/components/Field.svelte
Normal file
46
src/package/components/Field.svelte
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { uniqueId } from '../utils/uniqueId'
|
||||||
|
|
||||||
|
export let required = false
|
||||||
|
export let label: string
|
||||||
|
export let helper = ''
|
||||||
|
|
||||||
|
const id = `field-${uniqueId()}`
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for={id} class="field__label" class:required>
|
||||||
|
<span class="field__label__title">{@html label}</span>
|
||||||
|
{#if helper}
|
||||||
|
<span class="field__label__helper">{helper}</span>
|
||||||
|
{/if}
|
||||||
|
</label>
|
||||||
|
<slot {id} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
|
||||||
|
:global(i) {
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__helper {
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
color: var(--color-text-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { uniqueId } from '../utils/uniqueId'
|
|
||||||
|
|
||||||
export let required = false
|
|
||||||
export let label: string
|
|
||||||
|
|
||||||
const id = `form-field-${uniqueId()}`
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="form-field">
|
|
||||||
<label for={id} class="text-input__label" class:required>
|
|
||||||
{label}
|
|
||||||
</label>
|
|
||||||
<slot {id} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="postcss">
|
|
||||||
.form-field {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
import IconExclamation from 'virtual:icons/heroicons-outline/exclamation'
|
import IconExclamation from 'virtual:icons/heroicons-outline/exclamation'
|
||||||
import IconTrash from 'virtual:icons/heroicons-outline/trash'
|
import IconTrash from 'virtual:icons/heroicons-outline/trash'
|
||||||
import { markdown } from '../utils'
|
import { markdown } from '../utils'
|
||||||
|
import Field from './Field.svelte'
|
||||||
|
|
||||||
export let key: string
|
export let key: string
|
||||||
export let type: 'project' | 'version' | 'account' | 'image'
|
export let type: 'project' | 'version' | 'account' | 'image'
|
||||||
@@ -22,10 +23,12 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{@html markdown($t(`modal.deletion.${type}.description`))}
|
{@html markdown($t(`modal.deletion.${type}.description`))}
|
||||||
<span class="verify-label">{@html $t('modal.deletion.generic.verify', { values: { key } })}</span>
|
<Field label={$t('modal.deletion.generic.verify', { values: { key } })} let:id>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder={$t('modal.deletion.generic.placeholder', { values: { key } })}
|
placeholder={$t('modal.deletion.generic.placeholder', { values: { key } })}
|
||||||
bind:value={keyInput} />
|
bind:value={keyInput}
|
||||||
|
{id} />
|
||||||
|
</Field>
|
||||||
<Button color="danger" slot="button" disabled={key !== keyInput}>
|
<Button color="danger" slot="button" disabled={key !== keyInput}>
|
||||||
<IconTrash />
|
<IconTrash />
|
||||||
{$t(`modal.deletion.${type}.action`)}
|
{$t(`modal.deletion.${type}.action`)}
|
||||||
@@ -50,12 +53,4 @@
|
|||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.verify-label {
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(i) {
|
|
||||||
font-weight: var(--font-weight-normal);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
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 || null}>{link.label}</a>
|
||||||
{/each}
|
{/each}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
if (!open) {
|
if (!open) {
|
||||||
open = true
|
open = true
|
||||||
// Needs delay before trying to move focus
|
// Needs delay before trying to move focus
|
||||||
setTimeout(() => element.children[1].children[0].focus(), 0)
|
setTimeout(() => (element.children[1].children[0] as HTMLButtonElement).focus(), 0)
|
||||||
} else {
|
} else {
|
||||||
const option = options.find(
|
const option = options.find(
|
||||||
({ label }) => label === document.activeElement.innerHTML.trim()
|
({ label }) => label === document.activeElement.innerHTML.trim()
|
||||||
@@ -112,12 +112,15 @@
|
|||||||
transition:fade={{ duration: 70 }}
|
transition:fade={{ duration: 70 }}
|
||||||
class="select__options"
|
class="select__options"
|
||||||
style:--selected-index={options.indexOf(selected)}>
|
style:--selected-index={options.indexOf(selected)}>
|
||||||
{#each options as option (option.value)}
|
{#each options as option, index (option.value)}
|
||||||
{@const isSelected = selected?.value === option.value}
|
{@const isSelected = selected?.value === option.value}
|
||||||
<button
|
<button
|
||||||
on:click={() => selectOption(option)}
|
on:click={() => selectOption(option)}
|
||||||
class:is-selected={isSelected}
|
class:is-selected={isSelected}
|
||||||
tabindex={isSelected ? -1 : 0}>
|
tabindex={isSelected ? -1 : 0}
|
||||||
|
on:focusout={() => {
|
||||||
|
if (index + 1 === options.length) open = false
|
||||||
|
}}>
|
||||||
{option.label || option.value}
|
{option.label || option.value}
|
||||||
{#if selected?.value === option.value}
|
{#if selected?.value === option.value}
|
||||||
<IconCheck />
|
<IconCheck />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
</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" {id} {min} {max} bind:value />
|
||||||
<span>{value}</span>
|
<span>{value}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
|
||||||
.slider-input {
|
&__input {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border-radius: var(--rounded-sm);
|
border-radius: var(--rounded-sm);
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
<div class="text-input" class:fill>
|
<div class="text-input" class:fill>
|
||||||
{#if multiline}
|
{#if multiline}
|
||||||
<textarea name={id} {placeholder} bind:value />
|
<textarea {id} {placeholder} bind:value />
|
||||||
{:else}
|
{:else}
|
||||||
<input type="text" name={id} {placeholder} bind:value class:has-icon={icon} />
|
<input type="text" {id} {placeholder} bind:value class:has-icon={icon} />
|
||||||
{#if icon}
|
{#if icon}
|
||||||
<svelte:component this={icon} />
|
<svelte:component this={icon} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export { default as CheckboxVirtualList } from './components/CheckboxVirtualList
|
|||||||
|
|
||||||
export { default as Chips } from './components/Chips.svelte'
|
export { default as Chips } from './components/Chips.svelte'
|
||||||
|
|
||||||
export { default as FormField } from './components/FormField.svelte'
|
export { default as Field } from './components/Field.svelte'
|
||||||
|
|
||||||
export { default as Modal } from './components/Modal.svelte'
|
export { default as Modal } from './components/Modal.svelte'
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ input:focus-visible,
|
|||||||
|
|
||||||
input,
|
input,
|
||||||
button,
|
button,
|
||||||
a {
|
a,
|
||||||
|
.select {
|
||||||
outline: 0 solid hsla(290, 100%, 40%, 0);
|
outline: 0 solid hsla(290, 100%, 40%, 0);
|
||||||
transition: outline 0.2s ease-in-out;
|
transition: outline 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/routes/components/Field.md
Normal file
12
src/routes/components/Field.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
```svelte example raised
|
||||||
|
<script lang="ts">
|
||||||
|
import { Field, Slider, TextInput } from 'omorphia'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Field label="Favorite number" let:id>
|
||||||
|
<Slider min="0" max="100" value="69" {id} />
|
||||||
|
</Field>
|
||||||
|
<Field label="Favorite color" helper="Pick whatever color you like the most" let:id>
|
||||||
|
<TextInput placeholder="Enter another color..." {id} />
|
||||||
|
</Field>
|
||||||
|
```
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
```svelte example raised
|
|
||||||
<script lang="ts">
|
|
||||||
import { FormField, Slider, TextInput } from 'omorphia'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<FormField label="Favorite number">
|
|
||||||
<Slider min="0" max="100" value="69" />
|
|
||||||
</FormField>
|
|
||||||
<FormField label="Favorite color">
|
|
||||||
<TextInput placeholder="Enter another color..." />
|
|
||||||
</FormField>
|
|
||||||
```
|
|
||||||
@@ -6,7 +6,7 @@ title: Icons
|
|||||||
|
|
||||||
The follwing icon packs are included with omorphia:
|
The follwing icon packs are included with omorphia:
|
||||||
|
|
||||||
`heroicons-outline` `lucide` `fa-regular` `heroicons-solid` `carbon`
|
`heroicons-outline` `lucide` `fa-regular` `heroicons-solid` `carbon` `simple-icons`
|
||||||
|
|
||||||
Aim to find icons from `heroicons-outline` first, and then from the following packs if you can't find what you are looking for. [Browse icons...](https://icones.js.org/collection/heroicons-outline)
|
Aim to find icons from `heroicons-outline` first, and then from the following packs if you can't find what you are looking for. [Browse icons...](https://icones.js.org/collection/heroicons-outline)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user