feat: flatten components/kit -> components folder

This commit is contained in:
2026-09-10 20:08:15 +05:00
parent f7623ab3bb
commit f8a1da6ff7
65 changed files with 40 additions and 40 deletions
+98
View File
@@ -0,0 +1,98 @@
<script lang="ts">
import { Check } from "@lucide/svelte";
// TODO: сделать эти типы общими для кнопок \ бейджей \ етц???
const ToneVariantDefine = {
DEFAULT: "default",
ACCENT: "accent",
SUCCESS: "success",
WARNING: "warning",
DANGER: "danger",
INFO: "info",
} as const;
type ToneVariant = (typeof ToneVariantDefine)[keyof typeof ToneVariantDefine];
const BadgeVariantDefine = {
DEFAULT: "default",
OUTLINE: "outline",
CLEAR: "clear",
} as const;
type BadgeVariant =
(typeof BadgeVariantDefine)[keyof typeof BadgeVariantDefine];
interface Props {
tone?: ToneVariant;
variant?: BadgeVariant;
check?: boolean;
label?: string;
}
let {
tone = ToneVariantDefine.DEFAULT,
variant = BadgeVariantDefine.DEFAULT,
check = false,
label = "",
}: Props = $props();
</script>
<span class="badge badge-tone--{tone} badge-variant--{variant}">
{#if check}<Check size={12} />{/if}
{label}
</span>
<style>
.badge {
display: flex;
align-items: center;
gap: var(--space-s);
line-height: normal;
font-family: var(--font-mono);
font-size: var(--font-size-s);
font-weight: bold;
border-width: var(--size-border-thick);
padding: var(--space-s) var(--space-m);
}
.badge-tone--default {
--color-badge-main: var(--color-main);
--color-badge-tint: var(--color-main-tint);
}
.badge-tone--accent {
--color-badge-main: var(--color-accent);
--color-badge-tint: var(--color-accent-tint);
}
.badge-tone--success {
--color-badge-main: var(--color-success);
--color-badge-tint: var(--color-success-tint);
}
.badge-tone--danger {
--color-badge-main: var(--color-danger);
--color-badge-tint: var(--color-danger-tint);
}
.badge-tone--warning {
--color-badge-main: var(--color-warning);
--color-badge-tint: var(--color-warning-tint);
}
.badge-tone--info {
--color-badge-main: var(--color-info);
--color-badge-tint: var(--color-info-tint);
}
.badge-variant--default {
background-color: var(--color-badge-main);
border-color: var(--color-badge-main);
color: var(--color-background);
}
.badge-variant--outline {
background-color: transparent;
border-color: var(--color-badge-tint);
color: var(--color-badge-tint);
}
.badge-variant--clear {
background-color: transparent;
border-color: transparent;
color: var(--color-badge-tint);
}
</style>
+76
View File
@@ -0,0 +1,76 @@
<script lang="ts">
import type { Component } from "svelte";
import { ButtonVariantDefine, type ButtonVariant } from "../define";
import Icon from "./Icon.svelte";
interface Props {
label: string;
ariaLabel?: string;
onclick?: () => void;
variant?: ButtonVariant;
icon?: Component<{ size?: number; class?: string }>;
disabled?: boolean;
}
let {
label,
ariaLabel = label,
onclick,
variant = ButtonVariantDefine.PRIMARY,
icon,
disabled = false,
}: Props = $props();
</script>
<button
class="btn btn--{variant}"
{disabled}
aria-label={ariaLabel}
onclick={() => onclick?.()}
>
{#if icon}
<Icon {icon} size={14} />
{/if}
{#if label}
<span class="btn-label">{label}</span>
{/if}
</button>
<style>
.btn {
display: inline-flex;
align-items: center;
gap: var(--space-m);
padding: var(--space-m) var(--space-xl);
border-color: var(--color-main);
border-width: var(--size-border-thick);
border-radius: var(--radius-s);
font-size: var(--font-size-l);
font-weight: bold;
cursor: pointer;
background: var(--color-main);
color: var(--color-background);
}
.btn--outline {
background: transparent;
color: var(--color-main-tint);
border-color: var(--color-main-tint);
}
.btn--accent {
background: var(--color-accent);
color: var(--color-background);
border-color: var(--color-accent);
}
.btn--danger {
background: var(--color-danger);
color: var(--color-background);
border-color: var(--color-danger);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
@@ -0,0 +1,12 @@
<script lang="ts">
import { Download } from "@lucide/svelte";
import Button from "./Button.svelte";
interface Props {
label: string;
onclick?: () => void;
}
let { label, onclick }: Props = $props();
</script>
<Button icon={Download} {label} {onclick} />
+11
View File
@@ -0,0 +1,11 @@
<script lang="ts">
import type { Component } from "svelte";
interface Props {
icon: Component<{ size?: number; class?: string }>;
size?: number;
}
let { icon: IconComp, size = 16 }: Props = $props();
</script>
<IconComp {size} />
@@ -0,0 +1,23 @@
<script lang="ts">
import type { Component } from "svelte";
import { ButtonVariantDefine, type ButtonVariant } from "../define";
import Button from "./Button.svelte";
interface Props {
icon: Component<{ size?: number; class?: string }>;
label: string;
onclick?: () => void;
variant?: ButtonVariant;
disabled?: boolean;
}
let {
icon,
label,
onclick,
variant = ButtonVariantDefine.PRIMARY,
disabled = false,
}: Props = $props();
</script>
<Button label="" {onclick} {variant} {disabled} {icon} ariaLabel={label} />
@@ -0,0 +1,46 @@
<script lang="ts">
let lang = $state("RU");
// TODO: change to sectioned dual buttons
</script>
<div class="lang" role="group" aria-label="Language">
<button
type="button"
class="lang-btn"
class:active={lang === "RU"}
onclick={() => (lang = "RU")}
>
RU
</button>
<button
type="button"
class="lang-btn"
class:active={lang === "EN"}
onclick={() => (lang = "EN")}>EN</button
>
</div>
<style>
.lang {
display: flex;
align-items: center;
border: var(--size-border) solid var(--color-border);
}
.lang-btn {
border: 0;
background: transparent;
color: var(--color-text-muted);
font: var(--font-size-s) var(--font-mono);
padding: var(--space-s) var(--space-m);
cursor: pointer;
}
.lang-div {
color: var(--color-text);
font-family: var(--font-sans);
}
.lang-btn.active {
background: var(--color-text);
color: var(--color-background);
}
</style>
@@ -0,0 +1,65 @@
<script lang="ts">
interface Option {
value: string;
label: string;
}
interface Props {
options: Option[];
value?: string;
wide?: boolean;
onchange?: (value: string) => void;
}
let {
options,
wide = false,
value = $bindable(),
onchange,
}: Props = $props();
function select(v: string) {
value = v;
onchange?.(v);
}
</script>
<div class="segmented" class:wide role="group">
{#each options as opt (opt.value)}
<button
type="button"
class="segment"
class:selected={value === opt.value}
aria-pressed={value === opt.value}
onclick={() => select(opt.value)}
>
{opt.label}
</button>
{/each}
</div>
<style>
.segmented {
display: inline-flex;
border: var(--size-border) solid var(--color-border);
cursor: pointer;
&.wide {
width: 100%;
}
}
.segment {
border: 0;
border-right: var(--size-border) solid var(--color-border);
color: var(--color-text-muted);
font: var(--font-size-s) var(--font-mono);
background: 0 0;
padding: var(--space-m);
flex: 1;
}
.segment:last-child {
border-right: 0px;
}
.segment.selected {
background: var(--color-main);
color: var(--color-background);
}
</style>
@@ -0,0 +1,20 @@
<script lang="ts">
import { Moon, Sun } from "@lucide/svelte";
import IconButton from "../ui/IconButton.svelte";
interface Props {
theme: "light" | "dark";
ontoggle: () => void;
}
let { theme, ontoggle }: Props = $props();
// TODO: change icon animations - custom button instead of IconButton
</script>
<IconButton
icon={theme === "light" ? Moon : Sun}
label="Toggle theme"
variant="clear"
onclick={ontoggle}
/>
+45
View File
@@ -0,0 +1,45 @@
<script lang="ts">
interface Props {
checked: boolean;
label?: string;
onchange?: (checked: boolean) => void;
}
let { checked = $bindable(), label, onchange }: Props = $props();
function handle() {
checked = !checked;
onchange?.(checked);
}
</script>
<button
type="button"
class="toggle"
class:on={checked}
role="switch"
aria-checked={checked}
aria-label={label}
onclick={handle}
>
<i class="toggle-knob"></i>
</button>
<style>
.toggle {
position: relative;
width: var(--space-xxxl);
height: var(--space-xl);
border: var(--size-border) solid var(--color-border);
border-radius: 0;
background: var(--color-background);
cursor: pointer;
padding: 0;
}
.toggle.on {
background: var(--color-main);
border-color: var(--color-main);
}
.toggle-knob {
transition: transform var(--duration-s) ease;
}
</style>
+28
View File
@@ -0,0 +1,28 @@
<script lang="ts">
import { resolve } from "$app/paths";
</script>
<nav class="nav">
<a href={resolve("/")}>Home page</a>
<a href={resolve("/list-tools")}>Catalog</a>
<a href={resolve("/kit")}> UI Kit </a>
</nav>
<style>
.nav {
display: flex;
align-items: center;
gap: var(--space-xxl);
margin-right: var(--space-xxxl);
margin-left: auto;
}
.nav a {
color: var(--color-text);
font: bold var(--font-size-s) var(--font-mono);
white-space: nowrap;
text-decoration: none;
}
.nav a:hover {
color: var(--color-main);
}
</style>