feat(TypographyMenu): refactor component to align it with new design
This commit is contained in:
@@ -1,25 +1,16 @@
|
|||||||
<!--
|
<!--
|
||||||
Component: TypographyMenu
|
Component: TypographyMenu
|
||||||
Provides a menu for selecting and configuring typography settings
|
Floating controls bar for typography settings.
|
||||||
- On mobile the menu is displayed as a drawer
|
Warm surface, sharp corners, Settings icon header, dividers between units.
|
||||||
|
Mobile: same bar with overflow-x-auto — no drawer.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ResponsiveManager } from '$shared/lib';
|
import type { ResponsiveManager } from '$shared/lib';
|
||||||
import {
|
|
||||||
Content as ItemContent,
|
|
||||||
Root as ItemRoot,
|
|
||||||
} from '$shared/shadcn/ui/item';
|
|
||||||
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
import {
|
import { ComboControl } from '$shared/ui';
|
||||||
ComboControlV2,
|
import Settings2Icon from '@lucide/svelte/icons/settings-2';
|
||||||
Drawer,
|
|
||||||
IconButton,
|
|
||||||
} from '$shared/ui';
|
|
||||||
import { Label } from '$shared/ui';
|
|
||||||
import SlidersIcon from '@lucide/svelte/icons/sliders-vertical';
|
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { cubicOut } from 'svelte/easing';
|
import { fly } from 'svelte/transition';
|
||||||
import { crossfade } from 'svelte/transition';
|
|
||||||
import {
|
import {
|
||||||
MULTIPLIER_L,
|
MULTIPLIER_L,
|
||||||
MULTIPLIER_M,
|
MULTIPLIER_M,
|
||||||
@@ -33,28 +24,14 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { class: className, hidden = false }: Props = $props();
|
const { class: className, hidden = false }: Props = $props();
|
||||||
const responsive = getContext<ResponsiveManager>('responsive');
|
|
||||||
|
|
||||||
const [send, receive] = crossfade({
|
const responsive = getContext<ResponsiveManager>('responsive');
|
||||||
duration: 300,
|
|
||||||
easing: cubicOut,
|
|
||||||
fallback(node, params) {
|
|
||||||
// If it can't find a pair, it falls back to a simple fade/slide
|
|
||||||
return {
|
|
||||||
duration: 300,
|
|
||||||
css: t => `opacity: ${t}; transform: translateY(${(1 - t) * 10}px);`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the common font size multiplier based on the current responsive state.
|
* Sets the common font size multiplier based on the current responsive state.
|
||||||
*/
|
*/
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (!responsive) {
|
if (!responsive) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case responsive.isMobile:
|
case responsive.isMobile:
|
||||||
controlManager.multiplier = MULTIPLIER_S;
|
controlManager.multiplier = MULTIPLIER_S;
|
||||||
@@ -67,68 +44,50 @@ $effect(() => {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
controlManager.multiplier = MULTIPLIER_L;
|
controlManager.multiplier = MULTIPLIER_L;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={cn(
|
class={cn('w-full md:w-auto', hidden && 'hidden', className)}
|
||||||
'w-auto max-screen z-10 flex justify-center',
|
in:fly={{ y: 100, duration: 400 }}
|
||||||
hidden && 'hidden',
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
in:receive={{ key: 'panel' }}
|
|
||||||
out:send={{ key: 'panel' }}
|
|
||||||
>
|
>
|
||||||
{#if responsive.isMobile}
|
<div
|
||||||
<Drawer>
|
class={cn(
|
||||||
{#snippet trigger({ onClick })}
|
'flex items-center gap-1 md:gap-2 p-1.5 md:p-2',
|
||||||
<IconButton onclick={onClick}>
|
'bg-[#f3f0e9]/95 dark:bg-[#121212]/95 backdrop-blur-xl',
|
||||||
{#snippet icon({ className })}
|
'border border-black/5 dark:border-white/10',
|
||||||
<SlidersIcon class={className} />
|
'shadow-[0_20px_40px_-10px_rgba(0,0,0,0.1)]',
|
||||||
{/snippet}
|
'rounded-none ring-1 ring-black/5 dark:ring-white/5',
|
||||||
</IconButton>
|
responsive?.isMobile && 'overflow-x-auto',
|
||||||
{/snippet}
|
)}
|
||||||
{#snippet content({ className })}
|
>
|
||||||
<Label
|
<!-- Header: icon + label -->
|
||||||
class="mt-6 mb-12 px-2"
|
<div class="px-2 md:px-3 flex items-center gap-1.5 md:gap-2 border-r border-black/5 dark:border-white/10 mr-1 text-[#1a1a1a] dark:text-[#e5e5e5] shrink-0">
|
||||||
text="Typography Controls"
|
<Settings2Icon
|
||||||
align="center"
|
size={responsive?.isMobile ? 12 : 14}
|
||||||
/>
|
class="text-[#ff3b30]"
|
||||||
<div class={cn(className, 'flex flex-col gap-8')}>
|
/>
|
||||||
{#each controlManager.controls as control (control.id)}
|
<span
|
||||||
<ComboControlV2
|
class="text-[0.5625rem] md:text-[0.625rem] font-mono uppercase tracking-widest font-bold hidden sm:inline whitespace-nowrap"
|
||||||
control={control.instance}
|
>
|
||||||
orientation="horizontal"
|
GLOBAL_CONTROLS
|
||||||
label={control.controlLabel}
|
</span>
|
||||||
reduced
|
</div>
|
||||||
/>
|
|
||||||
{/each}
|
<!-- Controls with dividers between each -->
|
||||||
</div>
|
{#each controlManager.controls as control, i (control.id)}
|
||||||
{/snippet}
|
{#if i > 0}
|
||||||
</Drawer>
|
<div class="w-px h-6 md:h-8 bg-black/5 dark:bg-white/10 mx-0.5 md:mx-1 shrink-0"></div>
|
||||||
{:else}
|
{/if}
|
||||||
<ItemRoot
|
|
||||||
variant="outline"
|
<ComboControl
|
||||||
class="w-full sm:w-auto max-w-full sm:max-w-max p-2 sm:p-2.5 rounded-xl sm:rounded-2xl backdrop-blur-lg"
|
control={control.instance}
|
||||||
>
|
label={control.controlLabel}
|
||||||
<ItemContent class="flex flex-row justify-center items-center max-w-full sm:max-w-max">
|
increaseLabel={control.increaseLabel}
|
||||||
<div class="sm:py-2 sm:px-10 flex flex-row items-center gap-2">
|
decreaseLabel={control.decreaseLabel}
|
||||||
<div class="flex flex-row gap-3">
|
controlLabel={control.controlLabel}
|
||||||
{#each controlManager.controls as control (control.id)}
|
/>
|
||||||
<ComboControlV2
|
{/each}
|
||||||
control={control.instance}
|
</div>
|
||||||
increaseLabel={control.increaseLabel}
|
|
||||||
decreaseLabel={control.decreaseLabel}
|
|
||||||
controlLabel={control.controlLabel}
|
|
||||||
orientation="vertical"
|
|
||||||
showScale={false}
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ItemContent>
|
|
||||||
</ItemRoot>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user