feat(components/tiles): better small icon

This commit is contained in:
mikhail "synzr" 2025-12-01 19:13:42 +05:00
parent 073676b662
commit 1499e46a0f
5 changed files with 120 additions and 66 deletions

View file

@ -8,6 +8,7 @@ Metro-like tile. Must be in a group to display correctly.
import randomNumber from "$lib/utils/random-number"; import randomNumber from "$lib/utils/random-number";
import { cva } from "class-variance-authority"; import { cva } from "class-variance-authority";
import { onDestroy, onMount } from "svelte"; import { onDestroy, onMount } from "svelte";
import TileIconPage from "./pages/TileIconPage.svelte";
/** /**
* Max angle value. * Max angle value.
@ -68,6 +69,8 @@ Metro-like tile. Must be in a group to display correctly.
icon, icon,
column, column,
children, children,
link = "#",
enabled = true,
}: { }: {
/** /**
* Size. * Size.
@ -89,6 +92,16 @@ Metro-like tile. Must be in a group to display correctly.
*/ */
icon: string; icon: string;
/**
* Link.
*/
link?: string;
/**
* Is tile enabled?
*/
enabled?: boolean;
/** /**
* Pages. * Pages.
*/ */
@ -98,30 +111,34 @@ Metro-like tile. Must be in a group to display correctly.
/** /**
* Tile style. * Tile style.
**/ **/
const style = cva( const style = cva(["relative", "bg-(--tile-color)/80"], {
[ variants: {
"relative", size: {
"bg-(--tile-color)", small: ["row-span-1", "col-span-1"],
"perspective-distant", medium: ["row-span-2", "col-span-2"],
"active:scale-95", wide: ["row-span-2", "col-span-4"],
"active:transform-gpu", large: ["row-span-4", "col-span-4"],
"active:transform-3d", },
"active:rotate-x-(--tile-rotate-x)", enabled: {
"active:rotate-y-(--tile-rotate-y)", false: ["grayscale", "opacity-50"],
"duration-75", true: [
"ease-in-out", "active:scale-95",
], "perspective-distant",
{ "active:transform-gpu",
variants: { "active:transform-3d",
size: { "active:rotate-x-(--tile-rotate-x)",
small: ["row-span-1", "col-span-1"], "active:rotate-y-(--tile-rotate-y)",
medium: ["row-span-2", "col-span-2"], "duration-75",
wide: ["row-span-2", "col-span-4"], "ease-in-out",
large: ["row-span-4", "col-span-4"], ],
},
}, },
}, },
); });
/**
* Is tile active?
*/
const active = link !== "#" && enabled && children !== null;
/** /**
* Icon size. * Icon size.
@ -235,7 +252,7 @@ Metro-like tile. Must be in a group to display correctly.
</script> </script>
<a <a
class={style({ size })} class={style({ size, enabled })}
style=" style="
--tile-icon: url('{icon}'); --tile-icon: url('{icon}');
--tile-icon-size: {iconSize}px; --tile-icon-size: {iconSize}px;
@ -246,7 +263,7 @@ Metro-like tile. Must be in a group to display correctly.
grid-row-start: {row}; grid-row-start: {row};
grid-column-start: {column}; grid-column-start: {column};
" "
onmousemove={updateDynamicMouseValues} onmousemove={active ? updateDynamicMouseValues : null}
href="#h" href="#h"
> >
<!-- Tile pages --> <!-- Tile pages -->
@ -254,25 +271,31 @@ Metro-like tile. Must be in a group to display correctly.
class="w-full h-full overflow-y-hidden scroll-smooth duration-150" class="w-full h-full overflow-y-hidden scroll-smooth duration-150"
bind:this={pages} bind:this={pages}
> >
{@render children()} {#if active}
{@render children()}
{:else}
<TileIconPage />
{/if}
</div> </div>
<!-- Tile border --> {#if active}
<div <!-- Tile border -->
class=" <div
absolute top-0 class="
w-full h-full absolute top-0
border-2 border-white w-full h-full
opacity-0 hover:opacity-50 hover:mask-(--mask) active:opacity-100 border-2 border-white
duration-75 ease-in-out opacity-0 hover:opacity-50 hover:mask-(--mask) active:opacity-100
" duration-75 ease-in-out
style=" "
--mask: radial-gradient( style="
{TILE_BASE_SIZE}px --mask: radial-gradient(
at {mousePosition.x}px {mousePosition.y}px, {TILE_BASE_SIZE}px
black 45%, at {mousePosition.x}px {mousePosition.y}px,
transparent black 45%,
); transparent
" );
></div> "
></div>
{/if}
</a> </a>

View file

@ -0,0 +1,10 @@
<!--
@component
Small icon for a tile pages.
-->
<div
class="w-8 mt-auto aspect-square bg-contain bg-center bg-no-repeat self-start m-2"
style="background-image: var(--tile-icon);"
></div>

View file

@ -5,6 +5,8 @@ Image page for a tile. Must be in a tile to display correctly.
--> -->
<script lang="ts"> <script lang="ts">
import TileSmallIcon from "../TileSmallIcon.svelte";
let { let {
image, image,
}: { }: {
@ -19,8 +21,5 @@ Image page for a tile. Must be in a tile to display correctly.
class="flex flex-col justify-end bg-cover bg-center bg-no-repeat" class="flex flex-col justify-end bg-cover bg-center bg-no-repeat"
style="height: var(--tile-page-height); background-image: url('{image}');" style="height: var(--tile-page-height); background-image: url('{image}');"
> >
<div <TileSmallIcon />
class="w-5 mt-auto aspect-square bg-contain bg-center bg-no-repeat self-end m-2"
style="background-image: var(--tile-icon);"
></div>
</div> </div>

View file

@ -5,6 +5,8 @@ Text page for a tile. Must be in a tile to display correctly.
--> -->
<script lang="ts"> <script lang="ts">
import TileSmallIcon from "../TileSmallIcon.svelte";
let { let {
title, title,
subtitle, subtitle,
@ -16,22 +18,18 @@ Text page for a tile. Must be in a tile to display correctly.
} = $props(); } = $props();
</script> </script>
<div <div class="w-full flex flex-col" style="height: var(--tile-page-height);">
class="p-2 w-full flex flex-col gap-1 select-none text-white" <div class="w-full flex flex-col gap-1 p-2 select-none text-white">
style="height: var(--tile-page-height);" <h1 class="font-bold text-md">{title}</h1>
>
<h1 class="font-bold text-md">{title}</h1>
{#if subtitle} {#if subtitle}
<h2 class="text-md">{subtitle}</h2> <h2 class="text-md">{subtitle}</h2>
{/if} {/if}
{#if text} {#if text}
<p class="text-sm">{text}</p> <p class="text-sm">{text}</p>
{/if} {/if}
</div>
<div <TileSmallIcon />
class="w-5 mt-auto aspect-square bg-contain bg-center bg-no-repeat self-end"
style="background-image: var(--tile-icon);"
></div>
</div> </div>

View file

@ -12,22 +12,46 @@
</script> </script>
<TileGroup title="a lot of mikhails" rows={3} columns={3}> <TileGroup title="a lot of mikhails" rows={3} columns={3}>
<Tile size="small" row={5} column={2} icon={iconSynzr}> <Tile
size="small"
row={5}
column={2}
icon={iconSynzr}
link="https://example.com"
>
<TileIconPage name="mikhail" /> <TileIconPage name="mikhail" />
<TileTextPage title="Title" subtitle="Subtitle" text="Text" /> <TileTextPage title="Title" subtitle="Subtitle" text="Text" />
</Tile> </Tile>
<Tile size="medium" row={3} column={5} icon={iconSynzr}> <Tile
size="medium"
row={3}
column={5}
icon={iconSynzr}
link="https://example.com"
>
<TileImagePage image={imageTestSquare} /> <TileImagePage image={imageTestSquare} />
<TileTextPage title="Title" subtitle="Subtitle" text="Text" /> <TileTextPage title="Title" subtitle="Subtitle" text="Text" />
</Tile> </Tile>
<Tile size="wide" row={5} column={3} icon={iconSynzr}> <Tile
size="wide"
row={5}
column={3}
icon={iconSynzr}
link="https://example.com"
>
<TileIconPage name="mikhail" /> <TileIconPage name="mikhail" />
<TileImagePage image={imageTestRectangle} /> <TileImagePage image={imageTestRectangle} />
</Tile> </Tile>
<Tile size="large" row={1} column={1} icon={iconSynzr}> <Tile
size="large"
row={1}
column={1}
icon={iconSynzr}
link="https://example.com"
>
<TileIconPage name="mikhail" /> <TileIconPage name="mikhail" />
<TileImagePage image={imageTestSquare} /> <TileImagePage image={imageTestSquare} />
</Tile> </Tile>