Add Field
This commit is contained in:
parent
496c08b075
commit
aa88115d45
@ -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"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 728 B After Width: | Height: | Size: 747 B |
@ -48,7 +48,8 @@
|
||||
stroke-linejoin="round"
|
||||
stroke-miterlimit="1.5"
|
||||
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"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
// TODO: sizes
|
||||
// TODO: icon only buttons should have uniform padding
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { classCombine } from '../utils/classCombine'
|
||||
|
||||
/** The element to be styled as a button */
|
||||
@ -42,16 +42,22 @@
|
||||
`button--color-${color}`,
|
||||
badge && 'has-badge',
|
||||
])
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function dispatchClick() {
|
||||
if (!disabled) dispatch('click')
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if as === 'a'}
|
||||
<a class={className} {href} {disabled} {title} {target} on:click>
|
||||
<a class={className} {href} {disabled} {title} {target} on:click={dispatchClick}>
|
||||
<slot />
|
||||
</a>
|
||||
{:else if as === 'input'}
|
||||
<input class={className} {value} {disabled} {title} on:click />
|
||||
<input class={className} {value} {disabled} {title} on:click={dispatchClick} />
|
||||
{:else}
|
||||
<svelte:element this={as} class={className} {disabled} {title} on:click>
|
||||
<svelte:element this={as} class={className} {disabled} {title} on:click={dispatchClick}>
|
||||
<slot />
|
||||
</svelte:element>
|
||||
{/if}
|
||||
@ -76,13 +82,14 @@
|
||||
background-color: var(--color-button-bg);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
&:active:not(&--color-transparent) {
|
||||
&:active:not(&--color-transparent, &:disabled) {
|
||||
transform: scale(0.95);
|
||||
filter: brightness(0.8);
|
||||
}
|
||||
@ -140,9 +147,6 @@
|
||||
opacity: 50%;
|
||||
cursor: not-allowed;
|
||||
filter: grayscale(50%);
|
||||
|
||||
/* Not ideal, but preventing events being fired needs to be implemented */
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&--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 IconTrash from 'virtual:icons/heroicons-outline/trash'
|
||||
import { markdown } from '../utils'
|
||||
import Field from './Field.svelte'
|
||||
|
||||
export let key: string
|
||||
export let type: 'project' | 'version' | 'account' | 'image'
|
||||
@ -22,10 +23,12 @@
|
||||
</div>
|
||||
{/if}
|
||||
{@html markdown($t(`modal.deletion.${type}.description`))}
|
||||
<span class="verify-label">{@html $t('modal.deletion.generic.verify', { values: { key } })}</span>
|
||||
<TextInput
|
||||
placeholder={$t('modal.deletion.generic.placeholder', { values: { key } })}
|
||||
bind:value={keyInput} />
|
||||
<Field label={$t('modal.deletion.generic.verify', { values: { key } })} let:id>
|
||||
<TextInput
|
||||
placeholder={$t('modal.deletion.generic.placeholder', { values: { key } })}
|
||||
bind:value={keyInput}
|
||||
{id} />
|
||||
</Field>
|
||||
<Button color="danger" slot="button" disabled={key !== keyInput}>
|
||||
<IconTrash />
|
||||
{$t(`modal.deletion.${type}.action`)}
|
||||
@ -50,12 +53,4 @@
|
||||
width: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.verify-label {
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
|
||||
:global(i) {
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
class:is-active={query
|
||||
? ($page.url.searchParams.get(query) || '') === link.href
|
||||
: 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}
|
||||
</nav>
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
if (!open) {
|
||||
open = true
|
||||
// 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 {
|
||||
const option = options.find(
|
||||
({ label }) => label === document.activeElement.innerHTML.trim()
|
||||
@ -112,12 +112,15 @@
|
||||
transition:fade={{ duration: 70 }}
|
||||
class="select__options"
|
||||
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}
|
||||
<button
|
||||
on:click={() => selectOption(option)}
|
||||
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}
|
||||
{#if selected?.value === option.value}
|
||||
<IconCheck />
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
</script>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
.slider-input {
|
||||
&__input {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
border-radius: var(--rounded-sm);
|
||||
|
||||
@ -11,9 +11,9 @@
|
||||
|
||||
<div class="text-input" class:fill>
|
||||
{#if multiline}
|
||||
<textarea name={id} {placeholder} bind:value />
|
||||
<textarea {id} {placeholder} bind:value />
|
||||
{: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}
|
||||
<svelte:component this={icon} />
|
||||
{/if}
|
||||
|
||||
@ -12,7 +12,7 @@ export { default as CheckboxVirtualList } from './components/CheckboxVirtualList
|
||||
|
||||
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'
|
||||
|
||||
|
||||
@ -36,7 +36,8 @@ input:focus-visible,
|
||||
|
||||
input,
|
||||
button,
|
||||
a {
|
||||
a,
|
||||
.select {
|
||||
outline: 0 solid hsla(290, 100%, 40%, 0);
|
||||
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:
|
||||
|
||||
`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)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user