Coves frontend - a photon fork
at main 174 lines 3.8 kB view raw
1<script lang="ts" generics="T"> 2 import type { Snippet } from 'svelte' 3 import type { ClassValue } from 'svelte/elements' 4 const sizeDelay: Record<'lg' | 'md' | 'sm' | 'xs', number> = { 5 lg: 120, 6 md: 80, 7 sm: 40, 8 xs: 0, 9 } 10 11 interface Props { 12 items?: T[] 13 item?: Snippet<[T, number]> 14 children?: Snippet 15 animate?: boolean 16 size?: 'lg' | 'md' | 'sm' | 'xs' 17 class?: ClassValue 18 selected?: (item: T) => boolean 19 } 20 21 let { 22 items, 23 item: itemSnippet, 24 children, 25 animate = true, 26 size = 'sm', 27 class: clazz, 28 selected, 29 }: Props = $props() 30</script> 31 32<ul> 33 {#if items} 34 {#each items as item, index (item)} 35 <li 36 class={[ 37 'group/li', 38 animate && 'animate', 39 size == 'xs' && 'xs', 40 selected?.(item) && 'selected', 41 clazz, 42 ]} 43 style="--i: {index < 10 ? index * sizeDelay[size] : 0}ms;" 44 > 45 {@render itemSnippet?.(item, index)} 46 </li> 47 {/each} 48 {/if} 49 {@render children?.()} 50</ul> 51 52<style> 53 @reference '../../../app.css'; 54 ul { 55 :global { 56 :where(& > :not(:last-child)) { 57 margin-block-start: calc(calc(var(--spacing) * 1)); 58 margin-block-end: calc(calc(var(--spacing) * 1)); 59 } 60 } 61 } 62 ul > :global(li) { 63 transition: background-color 0.1s; 64 background-color: var(--color-white); 65 container-type: inline-size; 66 border: 1px solid 67 color-mix(in oklab, var(--color-slate-50), var(--color-slate-100)); 68 69 border-radius: var(--radius-lg) var(--radius-lg); 70 71 &:first-child { 72 border-top-left-radius: var(--radius-2xl); 73 border-top-right-radius: var(--radius-2xl); 74 } 75 &:last-child { 76 border-bottom-left-radius: var(--radius-2xl); 77 border-bottom-right-radius: var(--radius-2xl); 78 } 79 80 &:hover { 81 background-color: var(--color-slate-25); 82 } 83 } 84 85 ul > :global(li:not(.xs) > *) { 86 padding-block: calc(var(--spacing) * 3); 87 padding-inline: calc(var(--spacing) * 3.5); 88 89 @media screen and (min-width: 40rem) { 90 padding-block: calc(var(--spacing) * 3); 91 padding-inline: calc(var(--spacing) * 4); 92 } 93 } 94 95 ul > :global(li.xs > *) { 96 padding-block: calc(var(--spacing) * 0.5); 97 padding-block: calc(var(--spacing) * 1); 98 } 99 100 ul > :global(li.selected) { 101 background-color: color-mix( 102 in oklab, 103 var(--color-white), 104 var(--color-slate-50) 105 ); 106 } 107 108 :global(.dark) ul > :global(li.selected) { 109 background-color: color-mix( 110 in oklab, 111 var(--color-zinc-900) 90%, 112 var(--color-zinc-800) 113 ); 114 } 115 116 :global(.dark) ul > :global(li) { 117 border: 1px solid var(--color-zinc-900); 118 background-color: color-mix( 119 in oklab, 120 var(--color-zinc-925), 121 var(--color-zinc-900) 122 ); 123 124 &:hover { 125 background-color: var(--color-zinc-900); 126 } 127 128 &:active { 129 background-color: color-mix( 130 in oklab, 131 var(--color-zinc-900) 80%, 132 var(--color-zinc-925) 133 ); 134 } 135 } 136 137 @keyframes pop-in { 138 from { 139 transform: translateY(16px); 140 opacity: 0; 141 } 142 to { 143 transform: translateY(0px); 144 opacity: 1; 145 } 146 } 147 148 .animate { 149 --delay: var(--i, 0ms); 150 } 151 152 :global(.animate > *:only-child) { 153 animation: pop-in 1s forwards cubic-bezier(0.16, 1, 0.3, 1); 154 animation-delay: var(--delay, 0ms); 155 opacity: 0; 156 } 157 158 :global(.animate:not(:has(> * + *))) { 159 animation: pop-in 1s forwards cubic-bezier(0.16, 1, 0.3, 1); 160 animation-delay: var(--delay, 0ms); 161 opacity: 0; 162 } 163 164 @media (prefers-reduced-motion: reduce) { 165 :global(.animate > *:only-child) { 166 animation: none; 167 opacity: 1; 168 } 169 :global(.animate:not(:has(> * + *))) { 170 animation: none; 171 opacity: 1; 172 } 173 } 174</style>