refactor: reorganize component imports and enhance index page layout

- Grouped component imports into categories for better organization.
- Updated the layout of the index page to include a gallery structure.
- Added new sections for Button, Badge, Selection Controls, TextField, Select, Numeric Stepper, Avatar, Loading Bar, List Item, Link, Tabs, Breadcrumb, Pagination, Notification, Tooltip, Card, Navbar, Sidebar, Modal, and Icons.
- Improved styling for better visual hierarchy and spacing.
- Implemented a theme toggle feature with persistent state using localStorage.
This commit is contained in:
2026-06-23 10:51:40 +02:00
parent dea517fbe5
commit 6967f3c7cd
14 changed files with 1741 additions and 582 deletions
+23 -25
View File
@@ -1,30 +1,28 @@
@use '../../styles/tokens/typography' as *;
@use "../../styles/tokens/typography" as *;
.link {
.link__container {
width: fit-content;
display: inline-flex;
align-items: center;
}
.link {
text-decoration: none;
color: var(--nds-primary);
@include text-base;
&:hover {
color: var(--nds-text);
opacity: 0.25;
}
&:active {
color: var(--nds-text);
opacity: 0.25;
}
&__container {
width: fit-content;
display: flex;
align-items: center;
justify-content: center;
border-bottom: var(--nds-border-width-medium) dashed var(--nds-secondary);
&:hover {
background-color: var(--nds-secondary);
border-bottom: var(--nds-border-width-medium) dashed var(--nds-accent);
}
&:active {
background-color: var(--nds-primary);
border-bottom: var(--nds-border-width-medium) dashed var(--nds-secondary);
}
font-weight: 600;
display: inline-flex;
align-items: center;
gap: var(--nds-spacing-3xs);
border-bottom: 1px solid transparent;
transition:
border-color 130ms ease,
color 130ms ease;
&:hover {
border-bottom-color: var(--nds-primary);
}
}
&:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--nds-ring);
border-radius: var(--nds-radius-xs);
}
}
+17 -20
View File
@@ -1,37 +1,34 @@
@use '../../styles/tokens/typography' as *;
@use "../../styles/tokens/typography" as *;
.loading-bar {
position: relative;
width: 100%;
height: 6px;
background-color: var(--nds-text);
background-color: var(--nds-surface-2);
overflow: hidden;
border-radius: var(--nds-radius-sm);
border-radius: var(--nds-radius-full);
&__progress {
height: 100%;
background-color: var(--nds-primary);
transition: width 0.3s ease;
border-radius: var(--nds-radius-sm);
border-radius: var(--nds-radius-full);
transition: width 0.35s ease;
}
&__unknown {
position: absolute;
top: 0;
left: -50%;
width: 50%;
left: 0;
width: 40%;
height: 100%;
background-color: var(--nds-primary);
border-radius: var(--nds-radius-sm);
animation: loadingBarIndeterminate 1.5s infinite;
border-radius: var(--nds-radius-full);
animation: nds-lb 1.3s ease-in-out infinite;
}
@keyframes loadingBarIndeterminate {
from {
left: -50%;
}
to {
left: 100%;
}
}
@keyframes nds-lb {
0% {
left: -40%;
}
}
100% {
left: 100%;
}
}
+16 -10
View File
@@ -1,19 +1,25 @@
---
export interface Props {
type: 'known' | 'unknown';
type: "known" | "unknown";
percentage?: number;
width?: string;
width?: string;
}
const { type, percentage, width } = Astro.props;
---
<div class='loading-bar loading-bar--${type}' style={width ? `width: ${width}` : undefined}>
{type === 'known' && percentage !== undefined ? (
<div class='loading-bar__progress' style={`width: ${percentage}%`}></div>
) : (
<div class='loading-bar__unknown'></div>
)}
<div
class={`loading-bar loading-bar--${type}`}
style={width ? `width: ${width}` : undefined}
>
{
type === "known" && percentage !== undefined ? (
<div class="loading-bar__progress" style={`width: ${percentage}%`} />
) : (
<div class="loading-bar__unknown" />
)
}
</div>
<style lang="scss">
@use './loadingBar';
</style>
@use "./_loadingBar.scss";
</style>
+42 -53
View File
@@ -1,61 +1,50 @@
@use '../../styles/tokens/typography' as *;
@use "../../styles/tokens/typography" as *;
.notification {
display: flex;
align-items: flex-start;
justify-content: space-between;
align-items: center;
padding: var(--nds-spacing-sm) var(--nds-spacing-xs) ;
border-radius: var(--nds-radius-md);
@include text-sm;
&__error {
background-color: var(--nds-error-low);
&__close {
background: transparent;
border: none;
color: var(--nds-error-medium);
cursor: pointer;
}
&__content {
color: var(--nds-error-high);
}
}
&__success {
background-color: var(--nds-success-low);
&__close {
background: transparent;
border: none;
color: var(--nds-success-medium);
cursor: pointer;
}
&__content {
color: var(--nds-success-high);
}
}
&__warning {
background-color: var(--nds-warning-low);
&__close {
background: transparent;
border: none;
color: var(--nds-warning-medium);
cursor: pointer;
}
&__content {
color: var(--nds-warning-high);
}
}
gap: var(--nds-spacing-sm);
padding: var(--nds-spacing-sm) var(--nds-spacing-md);
border-radius: var(--nds-radius-lg);
background-color: var(--nds-surface);
box-shadow: var(--nds-shadow-md);
border-left: 3px solid var(--nds-info-medium);
@include text-base;
max-width: 400px;
&__info {
background-color: var(--nds-info-low);
&__close {
background: transparent;
border: none;
color: var(--nds-info-medium);
cursor: pointer;
}
&__content {
color: var(--nds-info-high);
border-left-color: var(--nds-info-medium);
}
&__success {
border-left-color: var(--nds-success-medium);
}
&__warning {
border-left-color: var(--nds-warning-medium);
}
&__error {
border-left-color: var(--nds-error-medium);
}
&__info__content,
&__success__content,
&__warning__content,
&__error__content {
color: var(--nds-text);
flex: 1;
}
&__info__close,
&__success__close,
&__warning__close,
&__error__close {
background: transparent;
border: none;
cursor: pointer;
display: flex;
color: var(--nds-neutral);
padding: 0;
border-radius: var(--nds-radius-sm);
transition: color 120ms ease;
&:hover {
color: var(--nds-text);
}
}
}
@@ -1,23 +1,30 @@
---
import { CloseIcon } from "../Icons";
export interface Props {
type: 'info' | 'success' | 'warning' | 'error';
type: "info" | "success" | "warning" | "error";
}
const notificationUUID = `notification-${Math.random().toString(36).substr(2, 9)}`;
const notificationUUID = `notification-${Math.random().toString(36).slice(2, 11)}`;
const { type } = Astro.props;
---
<div class={`notification notification__${type}`} role="alert" id={notificationUUID}>
<div class=`notification__${type}__content`>
<div
class={`notification notification__${type}`}
role="alert"
id={notificationUUID}
>
<div class={`notification__${type}__content`}>
<slot />
</div>
<button class={`notification__${type}__close`} aria-label="Close notification" onclick={`document.getElementById('${notificationUUID}')?.remove()`}>
<button
class={`notification__${type}__close`}
aria-label="Close notification"
onclick={`document.getElementById('${notificationUUID}')?.remove()`}
>
<CloseIcon size={16} label="Close notification" />
</button>
</div>
<style lang="scss">
@use './_notification.scss';
</style>
@use "./_notification.scss";
</style>
+37 -30
View File
@@ -1,33 +1,40 @@
@use '../../styles/tokens/typography' as *;
@use "../../styles/tokens/typography" as *;
.tab {
display: flex;
align-items: flex-start;
gap: var(--nds-spacing-xs);
justify-content: center;
width: fit-content;
&__item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: fit-content;
cursor: pointer;
padding: var(--nds-spacing-2xs);
@include text-base;
&--active {
color: var(--nds-primary);
&::after {
content: '';
display: block;
width: 120%;
height: 1px;
background-color: var(--nds-primary);
border-radius: var(--nds-radius-sm);
}
}
display: flex;
align-items: stretch;
gap: var(--nds-spacing-2xs);
border-bottom: 1px solid var(--nds-border);
width: fit-content;
&__item {
display: inline-flex;
align-items: center;
gap: var(--nds-spacing-2xs);
padding: var(--nds-spacing-xs) var(--nds-spacing-sm);
cursor: pointer;
@include text-label;
color: var(--nds-neutral);
background: transparent;
border: none;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition:
color 130ms ease,
border-color 130ms ease;
&:hover {
color: var(--nds-text);
}
}
&--active {
color: var(--nds-text);
border-bottom-color: var(--nds-primary);
}
}
}
.tab__content {
padding-top: var(--nds-spacing-md);
@include text-base;
color: var(--nds-text);
&[hidden] {
display: none;
}
}
+11 -31
View File
@@ -1,33 +1,13 @@
.toggle {
background-color: var(--nds-disabled);
border-radius: var(--nds-radius-full);
padding: var(--nds-spacing-2xs);
width: 50px;
height: 25px;
display: flex;
align-items: center;
justify-content: left;
cursor: pointer;
transition: background-color 160ms ease;
position: relative;
&-switch {
color: var(--nds-text);
width: 15px;
height: 15px;
background-color: var(--nds-text);
border-radius: var(--nds-radius-full);
position: absolute;
left: var(--nds-spacing-2xs);
top: 50%;
transform: translateY(-50%);
transition: left 160ms ease, background-color 160ms ease, transform 160ms ease;
}
&-active {
display: flex;
justify-content: right;
background-color: var(--nds-primary);
.toggle-switch {
left: calc(100% - var(--nds-spacing-2xs) - 15px);
}
}
--w: 44px; --h: 24px; --pad: 3px;
position: relative; width: var(--w); height: var(--h);
background-color: var(--nds-disabled); border-radius: var(--nds-radius-full);
padding: var(--pad); display: flex; align-items: center; cursor: pointer;
transition: background-color 180ms ease;
&-switch { width: calc(var(--h) - var(--pad) * 2); height: calc(var(--h) - var(--pad) * 2);
background-color: #fff; border-radius: var(--nds-radius-full); box-shadow: var(--nds-shadow-sm);
transition: transform 180ms cubic-bezier(.34,1.4,.6,1); }
&-active { background-color: var(--nds-primary); }
&-active .toggle-switch { transform: translateX(calc(var(--w) - var(--h))); }
}
toggle-switch:focus-visible .toggle { box-shadow: 0 0 0 3px var(--nds-ring); outline: none; }
+4 -6
View File
@@ -1,8 +1,6 @@
---
import { boolean } from 'astro:schema';
export interface Props {
'data-checked': boolean;
'data-checked'?: boolean | string;
name?: string;
id: string;
}
@@ -10,7 +8,7 @@ export interface Props {
const { 'data-checked': dataChecked = 'false', name = 'toggle', id } = Astro.props;
---
<toggle-switch data-checked={dataChecked} data-name={name} id={id}>
<toggle-switch data-checked={String(dataChecked)} data-name={name} id={id}>
<div class="toggle">
<div class="toggle-switch"></div>
</div>
@@ -35,7 +33,7 @@ const { 'data-checked': dataChecked = 'false', name = 'toggle', id } = Astro.pro
this.dispatchEvent(new CustomEvent('change', {
detail: { checked: this._checked, name: this.dataset.name },
bubbles: true,
bubbles: true,
composed: true,
}));
}
@@ -59,4 +57,4 @@ const { 'data-checked': dataChecked = 'false', name = 'toggle', id } = Astro.pro
<style lang="scss">
@use './_toggle.scss';
</style>
</style>
+5 -4
View File
@@ -1,6 +1,7 @@
@use '../../styles/tokens/typography' as *;
@use "../../styles/tokens/typography" as *;
.pagination {
display: flex;
gap: var(--nds-spacing-sm);
}
display: flex;
align-items: center;
gap: var(--nds-spacing-2xs);
}
@@ -1,26 +1,30 @@
@use '../../styles/tokens/typography' as *;
@use "../../styles/tokens/typography" as *;
.pagination-number {
width: 30px;
height: 30px;
display: flex;
min-width: 32px;
height: 32px;
padding: 0 var(--nds-spacing-2xs);
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--nds-radius-full);
border-radius: var(--nds-radius-md);
cursor: pointer;
@include text-label;
color: var(--nds-text);
background: transparent;
border: 1px solid transparent;
transition: all 120ms ease;
user-select: none;
&:hover:not(.pagination-number__disabled):not(.pagination-number__selected) {
background-color: var(--nds-secondary);
cursor: pointer;
}
&:active:not(.pagination-number__disabled):not(.pagination-number__selected) {
background-color: var(--nds-accent);
cursor: pointer;
}
&__disabled {
background-color: var(--nds-disabled);
cursor: not-allowed;
border-color: var(--nds-border-strong);
background-color: var(--nds-surface-hover);
}
&__selected {
background-color: var(--nds-primary);
cursor: pointer;
color: var(--nds-on-primary);
}
}
&__disabled {
color: var(--nds-disabled);
cursor: not-allowed;
}
}
+1
View File
@@ -42,6 +42,7 @@
min-height: 84px;
padding: var(--nds-spacing-sm);
resize: vertical;
width: 100% !important;
line-height: 1.5;
}
&__charCount {