Compare commits
6 Commits
662d4ac626
...
b4e97da3a0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4e97da3a0 | ||
|
|
b3c0898735 | ||
|
|
f4875d7324 | ||
|
|
b16928ac80 | ||
|
|
7f01a9cc85 | ||
|
|
a1bc359c7f |
@@ -85,8 +85,8 @@ $effect(() => {
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet content()}
|
{#snippet content({ className })}
|
||||||
<div class="flex flex-col gap-6 px-2 py-4">
|
<div class={cn(className, 'flex flex-col gap-6')}>
|
||||||
{#each controlManager.controls as control (control.id)}
|
{#each controlManager.controls as control (control.id)}
|
||||||
<ComboControlV2
|
<ComboControlV2
|
||||||
control={control.instance}
|
control={control.instance}
|
||||||
|
|||||||
43
src/shared/ui/ComboControlV2/ComboControlV2.stories.svelte
Normal file
43
src/shared/ui/ComboControlV2/ComboControlV2.stories.svelte
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<script module>
|
||||||
|
import { createTypographyControl } from '$shared/lib';
|
||||||
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
|
import ComboControlV2 from './ComboControlV2.svelte';
|
||||||
|
|
||||||
|
const { Story } = defineMeta({
|
||||||
|
title: 'Shared/ComboControlV2',
|
||||||
|
component: ComboControlV2,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: 'ComboControl with input field and slider',
|
||||||
|
},
|
||||||
|
story: { inline: false }, // Render stories in iframe for state isolation
|
||||||
|
},
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
orientation: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['horizontal', 'vertical'],
|
||||||
|
description: 'Orientation of the ComboControl',
|
||||||
|
defaultValue: 'vertical',
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
control: 'text',
|
||||||
|
description: 'Label for the ComboControl',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
const control = createTypographyControl({ min: 0, max: 100, step: 1, value: 50 });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Story name="Horizontal" args={{ orientation: 'horizontal', control }}>
|
||||||
|
<ComboControlV2 control={control} orientation="horizontal" />
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story name="Vertical" args={{ orientation: 'vertical', control, class: 'h-48' }}>
|
||||||
|
<ComboControlV2 control={control} orientation="vertical" />
|
||||||
|
</Story>
|
||||||
@@ -4,62 +4,113 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { TypographyControl } from '$shared/lib';
|
import type { TypographyControl } from '$shared/lib';
|
||||||
import { Input } from '$shared/shadcn/ui/input';
|
|
||||||
import { Slider } from '$shared/shadcn/ui/slider';
|
|
||||||
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
|
import { Input } from '$shared/ui';
|
||||||
|
import { Slider } from '$shared/ui';
|
||||||
import type { Orientation } from 'bits-ui';
|
import type { Orientation } from 'bits-ui';
|
||||||
import type { ChangeEventHandler } from 'svelte/elements';
|
import type { ChangeEventHandler } from 'svelte/elements';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* Typography control instance
|
* Control instance
|
||||||
*/
|
*/
|
||||||
control: TypographyControl;
|
control: TypographyControl;
|
||||||
/**
|
/**
|
||||||
* Orientation of the component
|
* Orientation
|
||||||
*/
|
*/
|
||||||
orientation?: Orientation;
|
orientation?: Orientation;
|
||||||
|
/**
|
||||||
|
* Label text
|
||||||
|
*/
|
||||||
|
label?: string;
|
||||||
|
/**
|
||||||
|
* CSS class
|
||||||
|
*/
|
||||||
|
class?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
control,
|
control,
|
||||||
orientation = 'vertical',
|
orientation = 'vertical',
|
||||||
|
label,
|
||||||
|
class: className,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
let sliderValue = $state(Number(control.value));
|
let inputValue = $state(String(control.value));
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
sliderValue = Number(control?.value);
|
inputValue = String(control.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleInputChange: ChangeEventHandler<HTMLInputElement> = event => {
|
const handleInputChange: ChangeEventHandler<HTMLInputElement> = event => {
|
||||||
const parsedValue = parseFloat(event.currentTarget.value);
|
const parsedValue = parseFloat(event.currentTarget.value);
|
||||||
if (!isNaN(parsedValue)) {
|
if (!isNaN(parsedValue)) {
|
||||||
control.value = parsedValue;
|
control.value = parsedValue;
|
||||||
|
inputValue = String(parsedValue);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSliderChange = (newValue: number) => {
|
|
||||||
control.value = newValue;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={cn('flex flex-col items-center gap-4 w-full', orientation === 'vertical' ? 'flex-col' : 'flex-row')}>
|
<div
|
||||||
|
class={cn(
|
||||||
|
'flex gap-4 sm:p-4 rounded-xl transition-all duration-300',
|
||||||
|
'backdrop-blur-md',
|
||||||
|
orientation === 'horizontal' ? 'flex-row items-end w-full' : 'flex-col items-center h-full',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Input
|
<Input
|
||||||
value={control.value}
|
class="h-10 rounded-lg w-12 pl-1 pr-1 sm:pr-1 md:pr-1 sm:pl-1 md:pl-1 text-center"
|
||||||
|
value={inputValue}
|
||||||
onchange={handleInputChange}
|
onchange={handleInputChange}
|
||||||
min={control.min}
|
|
||||||
max={control.max}
|
|
||||||
class="w-14 h-8 text-xs text-center bg-white/40 border-none rounded-lg focus-visible:ring-indigo-500/50"
|
|
||||||
/>
|
|
||||||
<Slider
|
|
||||||
min={control.min}
|
min={control.min}
|
||||||
max={control.max}
|
max={control.max}
|
||||||
step={control.step}
|
step={control.step}
|
||||||
value={sliderValue}
|
|
||||||
onValueChange={handleSliderChange}
|
|
||||||
type="single"
|
|
||||||
orientation={orientation}
|
|
||||||
class={cn(orientation === 'vertical' ? 'h-30' : 'w-full')}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div class={cn('relative', orientation === 'horizontal' ? 'w-full' : 'h-full')}>
|
||||||
|
<div
|
||||||
|
class={cn(
|
||||||
|
'absolute flex justify-between',
|
||||||
|
orientation === 'horizontal' ? 'flex-row w-full -top-5 px-0.5' : 'flex-col h-full -left-5 py-0.5',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{#each Array(5) as _, i}
|
||||||
|
<div
|
||||||
|
class={cn(
|
||||||
|
'flex items-center gap-1.5',
|
||||||
|
orientation === 'horizontal' ? 'flex-col' : 'flex-row',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span class="font-mono text-[0.375rem] text-gray-400 tabular-nums">
|
||||||
|
{
|
||||||
|
Number.isInteger(control.step)
|
||||||
|
? Math.round(control.min + (i * (control.max - control.min) / 4))
|
||||||
|
: (control.min + (i * (control.max - control.min) / 4)).toFixed(2)
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
<div class={cn('bg-gray-300', orientation === 'horizontal' ? 'w-px h-1' : 'h-px w-1')}></div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Slider
|
||||||
|
class={cn(orientation === 'horizontal' ? 'w-full' : 'h-full')}
|
||||||
|
bind:value={control.value}
|
||||||
|
min={control.min}
|
||||||
|
max={control.max}
|
||||||
|
step={control.step}
|
||||||
|
{orientation}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if label}
|
||||||
|
<div class="flex items-center gap-2 opacity-70">
|
||||||
|
<div class="w-1 h-1 rounded-full bg-gray-900"></div>
|
||||||
|
<div class="w-px h-2 bg-gray-400/50"></div>
|
||||||
|
<span class="font-mono text-[8px] uppercase tracking-[0.2em] text-gray-500 font-medium">
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import type { Snippet } from 'svelte';
|
|||||||
interface Props {
|
interface Props {
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
trigger?: Snippet<[{ isOpen: boolean; onClick: () => void }]>;
|
trigger?: Snippet<[{ isOpen: boolean; onClick: () => void }]>;
|
||||||
content?: Snippet<[{ isOpen: boolean }]>;
|
content?: Snippet<[{ isOpen: boolean; className?: string }]>;
|
||||||
contentClassName?: string;
|
contentClassName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ function handleClick() {
|
|||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</DrawerTrigger>
|
</DrawerTrigger>
|
||||||
<DrawerContent class={cn('min-h-60', contentClassName)}>
|
<DrawerContent>
|
||||||
{@render content?.({ isOpen })}
|
{@render content?.({ isOpen, className: cn('min-h-60 px-2 pt-4 pb-8', contentClassName) })}
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
</DrawerRoot>
|
</DrawerRoot>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ let {
|
|||||||
'placeholder:font-mono',
|
'placeholder:font-mono',
|
||||||
'placeholder:text-xs sm:placeholder:text-sm',
|
'placeholder:text-xs sm:placeholder:text-sm',
|
||||||
'placeholder:tracking-wide',
|
'placeholder:tracking-wide',
|
||||||
'pl-11 sm:pl-14 pr-4 sm:pr-6',
|
'pl-4 sm:pl-6 pr-4 sm:pr-6',
|
||||||
'rounded-xl',
|
'rounded-xl',
|
||||||
'transition-all duration-200',
|
'transition-all duration-200',
|
||||||
'font-medium',
|
'font-medium',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<!-- Component: SearchBar -->
|
<!-- Component: SearchBar -->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
import { Input } from '$shared/ui';
|
import { Input } from '$shared/ui';
|
||||||
import AsteriskIcon from '@lucide/svelte/icons/asterisk';
|
import AsteriskIcon from '@lucide/svelte/icons/asterisk';
|
||||||
|
|
||||||
@@ -34,5 +35,5 @@ let {
|
|||||||
<div class="absolute left-4 sm:left-5 top-1/2 -translate-y-1/2 pointer-events-none z-10">
|
<div class="absolute left-4 sm:left-5 top-1/2 -translate-y-1/2 pointer-events-none z-10">
|
||||||
<AsteriskIcon class="size-3 sm:size-4 stroke-gray-400 stroke-[1.5]" />
|
<AsteriskIcon class="size-3 sm:size-4 stroke-gray-400 stroke-[1.5]" />
|
||||||
</div>
|
</div>
|
||||||
<Input {id} class={className} bind:value={value} placeholder={placeholder} />
|
<Input {id} class={cn('pl-11 sm:pl-14', className)} bind:value={value} placeholder={placeholder} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
51
src/shared/ui/Slider/Slider.stories.svelte
Normal file
51
src/shared/ui/Slider/Slider.stories.svelte
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<script module>
|
||||||
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
|
import Slider from './Slider.svelte';
|
||||||
|
|
||||||
|
const { Story } = defineMeta({
|
||||||
|
title: 'Shared/Slider',
|
||||||
|
component: Slider,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: 'Styled bits-ui slider component for selecting a value within a range.',
|
||||||
|
},
|
||||||
|
story: { inline: false }, // Render stories in iframe for state isolation
|
||||||
|
},
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
value: {
|
||||||
|
control: 'number',
|
||||||
|
description: 'Current value (two-way bindable)',
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
control: 'number',
|
||||||
|
description: 'Minimum value',
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
control: 'number',
|
||||||
|
description: 'Maximum value',
|
||||||
|
},
|
||||||
|
step: {
|
||||||
|
control: 'number',
|
||||||
|
description: 'Step size for value increments',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
let minValue = 0;
|
||||||
|
let maxValue = 100;
|
||||||
|
let stepValue = 1;
|
||||||
|
let value = $state(50);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Story name="Horizontal" args={{ orientation: 'horizontal', min: minValue, max: maxValue, step: stepValue, value }}>
|
||||||
|
<Slider bind:value min={minValue} max={maxValue} step={stepValue} />
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story name="Vertical" args={{ orientation: 'vertical', min: minValue, max: maxValue, step: stepValue, value }}>
|
||||||
|
<Slider bind:value min={minValue} max={maxValue} step={stepValue} orientation="vertical" />
|
||||||
|
</Story>
|
||||||
105
src/shared/ui/Slider/Slider.svelte
Normal file
105
src/shared/ui/Slider/Slider.svelte
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<!--
|
||||||
|
Component: Slider
|
||||||
|
Styled bits-ui slider component with single value.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
|
import {
|
||||||
|
Slider,
|
||||||
|
type SliderRootProps,
|
||||||
|
} from 'bits-ui';
|
||||||
|
|
||||||
|
type Props = Omit<SliderRootProps, 'type' | 'onValueChange' | 'onValueCommit'> & {
|
||||||
|
/**
|
||||||
|
* Slider value, numeric.
|
||||||
|
*/
|
||||||
|
value: number;
|
||||||
|
/**
|
||||||
|
* A callback function called when the value changes.
|
||||||
|
* @param newValue - number
|
||||||
|
*/
|
||||||
|
onValueChange?: (newValue: number) => void;
|
||||||
|
/**
|
||||||
|
* A callback function called when the user stops dragging the thumb and the value is committed.
|
||||||
|
* @param newValue - number
|
||||||
|
*/
|
||||||
|
onValueCommit?: (newValue: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
let { value = $bindable(), orientation = 'horizontal', class: className, ...rest }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Slider.Root
|
||||||
|
bind:value={value}
|
||||||
|
class={cn(
|
||||||
|
'relative flex h-full w-6 touch-none select-none items-center justify-center',
|
||||||
|
orientation === 'horizontal' ? 'w-48 h-6' : 'w-6 h-48',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
type="single"
|
||||||
|
{orientation}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{#snippet children(props)}
|
||||||
|
<span
|
||||||
|
{...props}
|
||||||
|
class={cn('relative bg-gray-200 rounded-full', orientation === 'horizontal' ? 'w-full h-px' : 'h-full w-px')}
|
||||||
|
>
|
||||||
|
<!-- Filled range with NO transition -->
|
||||||
|
<Slider.Range
|
||||||
|
class={cn('absolute bg-gray-900 rounded-full', orientation === 'horizontal' ? 'h-full' : 'w-full')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Slider.Thumb
|
||||||
|
index={0}
|
||||||
|
class={cn(
|
||||||
|
'group/thumb relative block',
|
||||||
|
orientation === 'horizontal' ? '-top-1 w-2 h-2.25' : '-left-1 h-2 w-2.25',
|
||||||
|
'rounded-sm',
|
||||||
|
'bg-gray-900',
|
||||||
|
// Glow shadow
|
||||||
|
'shadow-[0_0_6px_rgba(0,0,0,0.4)]',
|
||||||
|
// Smooth transitions only for size/position
|
||||||
|
'duration-200 ease-out',
|
||||||
|
orientation === 'horizontal' ? 'transition-[height,top,left,box-shadow]' : 'transition-[width,top,left,box-shadow]',
|
||||||
|
// Hover: bigger glow
|
||||||
|
'hover:shadow-[0_0_10px_rgba(0,0,0,0.5)]',
|
||||||
|
orientation === 'horizontal' ? 'hover:h-3 hover:-top-[5.5px]' : 'hover:w-3 hover:-left-[5.5px]',
|
||||||
|
// Active: smaller glow
|
||||||
|
'active:shadow-[0_0_4px_rgba(0,0,0,0.3)]',
|
||||||
|
orientation === 'horizontal' ? 'active:h-2.5 active:-top-[4.5px]' : 'active:w-2.5 active:-left-[4.5px]',
|
||||||
|
'focus:outline-none',
|
||||||
|
'cursor-grab active:cursor-grabbing',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<!-- Soft glow on hover -->
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
absolute inset-0 rounded-sm
|
||||||
|
bg-white/20
|
||||||
|
opacity-0 group-hover/thumb:opacity-100
|
||||||
|
transition-opacity duration-200
|
||||||
|
"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Value label -->
|
||||||
|
<span
|
||||||
|
class={cn(
|
||||||
|
'absolute',
|
||||||
|
orientation === 'horizontal' ? '-top-8 left-1/2 -translate-x-1/2' : 'left-5 top-1/2 -translate-y-1/2',
|
||||||
|
'px-1.5 py-0.5 rounded-md',
|
||||||
|
'bg-gray-900/90 backdrop-blur-sm',
|
||||||
|
'font-mono text-[0.625rem] font-medium text-white ',
|
||||||
|
'opacity-0 group-hover/thumb:opacity-100',
|
||||||
|
'transition-all duration-300',
|
||||||
|
'pointer-events-none',
|
||||||
|
'shadow-sm',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
</Slider.Thumb>
|
||||||
|
</span>
|
||||||
|
{/snippet}
|
||||||
|
</Slider.Root>
|
||||||
@@ -12,4 +12,5 @@ export { default as Logo } from './Logo/Logo.svelte';
|
|||||||
export { default as SearchBar } from './SearchBar/SearchBar.svelte';
|
export { default as SearchBar } from './SearchBar/SearchBar.svelte';
|
||||||
export { default as Section } from './Section/Section.svelte';
|
export { default as Section } from './Section/Section.svelte';
|
||||||
export { default as Skeleton } from './Skeleton/Skeleton.svelte';
|
export { default as Skeleton } from './Skeleton/Skeleton.svelte';
|
||||||
|
export { default as Slider } from './Slider/Slider.svelte';
|
||||||
export { default as VirtualList } from './VirtualList/VirtualList.svelte';
|
export { default as VirtualList } from './VirtualList/VirtualList.svelte';
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ResponsiveManager } from '$shared/lib';
|
import type { ResponsiveManager } from '$shared/lib';
|
||||||
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
IconButton,
|
IconButton,
|
||||||
@@ -36,23 +37,23 @@ const responsive = getContext<ResponsiveManager>('responsive');
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{#snippet content({ isOpen })}
|
{#snippet content({ isOpen, className })}
|
||||||
<div class="px-2 py-4">
|
<div class={cn(className, 'flex flex-col gap-6')}>
|
||||||
<SelectComparedFonts {sliderPos} />
|
<SelectComparedFonts {sliderPos} />
|
||||||
|
<TypographyControls
|
||||||
|
{sliderPos}
|
||||||
|
{isDragging}
|
||||||
|
isActive={isOpen}
|
||||||
|
bind:wrapper={typographyControls}
|
||||||
|
containerWidth={container?.clientWidth}
|
||||||
|
staticPosition
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<TypographyControls
|
|
||||||
{sliderPos}
|
|
||||||
{isDragging}
|
|
||||||
isActive={isOpen}
|
|
||||||
bind:wrapper={typographyControls}
|
|
||||||
containerWidth={container?.clientWidth}
|
|
||||||
staticPosition
|
|
||||||
/>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Drawer>
|
</Drawer>
|
||||||
{:else}
|
{:else}
|
||||||
{#if !isLoading}
|
{#if !isLoading}
|
||||||
<div class="absolute top-3 sm:top-6 left-3 sm:left-6">
|
<div class="absolute top-3 sm:top-6 left-3 sm:left-6 z-50">
|
||||||
<TypographyControls
|
<TypographyControls
|
||||||
{sliderPos}
|
{sliderPos}
|
||||||
{isDragging}
|
{isDragging}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ $effect(() => {
|
|||||||
out:fade={{ duration: 300, delay: 300 }}
|
out:fade={{ duration: 300, delay: 300 }}
|
||||||
>
|
>
|
||||||
{#if staticPosition}
|
{#if staticPosition}
|
||||||
<div class="flex flex-col gap-6 px-2 py-4">
|
<div class="flex flex-col gap-6">
|
||||||
<Input
|
<Input
|
||||||
class="p-6"
|
class="p-6"
|
||||||
bind:value={comparisonStore.text}
|
bind:value={comparisonStore.text}
|
||||||
@@ -194,9 +194,9 @@ $effect(() => {
|
|||||||
{#snippet hiddenContent()}
|
{#snippet hiddenContent()}
|
||||||
{#if typography.weightControl && typography.sizeControl && typography.heightControl}
|
{#if typography.weightControl && typography.sizeControl && typography.heightControl}
|
||||||
<div class="flex flex-row justify-between items-center-safe gap-2 sm:gap-0">
|
<div class="flex flex-row justify-between items-center-safe gap-2 sm:gap-0">
|
||||||
<ComboControlV2 control={typography.weightControl} />
|
<ComboControlV2 control={typography.weightControl} orientation="vertical" />
|
||||||
<ComboControlV2 control={typography.sizeControl} />
|
<ComboControlV2 control={typography.sizeControl} orientation="vertical" />
|
||||||
<ComboControlV2 control={typography.heightControl} />
|
<ComboControlV2 control={typography.heightControl} orientation="vertical" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|||||||
Reference in New Issue
Block a user