[READ-ONLY] Mirror of https://github.com/flo-bit/ui-kit. 🦊 fox ui, svelte 5 and tailwind 4 flo-bit.dev/ui-kit/
svelte tailwindcss ui-components
0

Configure Feed

Select the types of activity you want to include in your feed.

improve emoji picker

Florian (May 3, 2025, 7:18 PM +0200) dd21aaae 45b593db

+178 -63
+5
.changeset/better-areas-hide.md
··· 1 + --- 2 + '@fuxui/social': patch 3 + --- 4 + 5 + improve emoji picker
+6 -2
apps/docs/src/routes/+page.svelte
··· 5 5 import Navbar from '$lib/site-components/Navbar.svelte'; 6 6 import Sidebar from '$lib/site-components/Sidebar.svelte'; 7 7 import { components } from '$lib/site-components/components_all'; 8 + import { dev } from '$app/environment'; 8 9 9 10 let count = components.flatMap((c) => c.components).length; 10 11 </script> ··· 14 15 15 16 <div class="mx-auto flex w-full max-w-6xl flex-col items-start justify-center gap-8 px-8 py-24"> 16 17 <h1 17 - class="text-base-950 dark:text-base-50 mt-16 mb-4 max-w-2xl text-4xl font-bold tracking-tight text-pretty md:text-5xl md:leading-14" 18 + class="text-base-950 dark:text-base-50 md:leading-14 mb-4 mt-16 max-w-2xl text-pretty text-4xl font-bold tracking-tight md:text-5xl" 18 19 > 19 - {count} UI components built with Tailwind 4 and Svelte 5 20 + {#if dev} 21 + {count} 22 + {/if} 23 + UI components built with Tailwind 4 and Svelte 5 20 24 </h1> 21 25 22 26 <div class="mb-16 flex gap-2">
+6
apps/docs/src/lib/site-components/components_social.ts
··· 4 4 import CardGithubCorner from '$lib/cards/social/CardGithubCorner.svelte'; 5 5 import CardBlueskyLogin from '$lib/cards/social/CardBlueskyLogin.svelte'; 6 6 import CardStarRating from '$lib/cards/social/CardStarRating.svelte'; 7 + import CardEmojiPicker from '$lib/cards/social/CardEmojiPicker.svelte'; 7 8 8 9 export const socialComponents: ComponentCard[] = [ 9 10 { ··· 30 31 component: CardStarRating, 31 32 label: 'Star Rating', 32 33 href: 'star-rating' 34 + }, 35 + { 36 + component: CardEmojiPicker, 37 + label: 'Emoji Picker', 38 + href: 'emoji-picker' 33 39 } 34 40 ].sort((a, b) => a.label.localeCompare(b.label));
+119
apps/docs/src/lib/cards/social/CardEmojiPicker.svelte
··· 1 + <script lang="ts"> 2 + const emojis = [ 3 + '😀', 4 + '😃', 5 + '😄', 6 + '😁', 7 + '😆', 8 + '😅', 9 + '🤣', 10 + '😂', 11 + '🙂', 12 + '🙃', 13 + '🫠', 14 + '😉', 15 + '😊', 16 + '😇', 17 + '🥰', 18 + '😍', 19 + '🤩', 20 + '😘', 21 + '😗', 22 + '☺️', 23 + '😚', 24 + '😙', 25 + '🥲', 26 + '😋', 27 + '😛', 28 + '😜', 29 + '🤪', 30 + '😝', 31 + '🤑', 32 + '🤗', 33 + '🤭', 34 + '🫢', 35 + '🫣', 36 + '🤫', 37 + '🤔', 38 + '🫡', 39 + '🤐', 40 + '🤨', 41 + '😐️', 42 + '😑', 43 + '😶', 44 + '🫥', 45 + '😶‍🌫️', 46 + '😏', 47 + '😒', 48 + '🙄', 49 + '😬', 50 + '😮‍💨', 51 + '🤥', 52 + '🫨', 53 + '🙂‍↔️', 54 + '🙂‍↕️', 55 + '😌', 56 + '😔', 57 + '😪', 58 + '🤤', 59 + '😴', 60 + '😷', 61 + '🤒', 62 + '🤕', 63 + '🤢', 64 + '🤮', 65 + '🤧', 66 + '🥵', 67 + '🥶', 68 + '🥴', 69 + '😵', 70 + '😵‍💫', 71 + '🤯', 72 + '🤠', 73 + '🥳', 74 + '🥸', 75 + '😎', 76 + '🤓', 77 + '🧐', 78 + '😕', 79 + '🫤', 80 + '😟', 81 + '🙁', 82 + '☹️', 83 + '😮', 84 + '😯', 85 + '😲', 86 + '😳', 87 + '🥺', 88 + '🥹', 89 + '😦', 90 + '😧', 91 + '😨', 92 + '😰', 93 + '😥', 94 + '😢', 95 + '😭', 96 + '😱', 97 + '😖', 98 + '😣', 99 + '😞', 100 + '😓', 101 + '😩', 102 + '😫', 103 + '🥱', 104 + '😤', 105 + '😡', 106 + '😠', 107 + '🤬', 108 + ]; 109 + </script> 110 + 111 + <div class="absolute inset-0 w-full h-full"> 112 + <div class="flex flex-wrap gap-2 text-xl"> 113 + {#each emojis as emoji} 114 + <div> 115 + {emoji} 116 + </div> 117 + {/each} 118 + </div> 119 + </div>
+34 -46
packages/social/src/lib/components/emoji-picker/EmojiPicker.svelte
··· 1 1 <script lang="ts"> 2 2 import { cn, ScrollArea } from '@fuxui/base'; 3 - import { onMount } from 'svelte'; 4 - import { isEmojiSupported } from 'is-emoji-supported'; 5 - import { allGroups, type Emoji } from './emoji'; 6 - 7 - onMount(async () => { 8 - initEmojiPicker(); 9 - }); 10 - 11 - let emojiGroups: { [key: number]: any[] } = $state({}); 3 + import { isEmojiSupported } from 'is-emoji-supported'; 4 + import { allGroups } from './emoji'; 5 + import Database from 'emoji-picker-element/database'; 6 + import type { NativeEmoji } from 'emoji-picker-element/shared'; 12 7 13 8 let currentGroup = $state(allGroups[0].id); 9 + let db: Database | undefined = $state(); 14 10 15 - let { onpicked }: { onpicked?: (emoji: Emoji) => void } = $props(); 11 + let { onpicked }: { onpicked?: (emoji: NativeEmoji) => void } = $props(); 16 12 17 - async function initEmojiPicker() { 18 - const { Database } = await import('emoji-picker-element'); 19 - 20 - const db = new Database(); 21 - 22 - let allEmojis: { [key: number]: any[] } = {}; 23 - for (let group of allGroups) { 24 - const emojis = await db.getEmojiByGroup(group.id); 25 - let validEmojis = []; 26 - for (let emoji of emojis) { 27 - if (isEmojiSupported(emoji.unicode)) { 28 - validEmojis.push(emoji); 29 - } 30 - } 31 - allEmojis[group.id] = validEmojis; 32 - } 33 - 34 - emojiGroups = allEmojis; 35 - } 13 + $effect(() => { 14 + if (db) return; 15 + import('emoji-picker-element').then(({ Database }) => { 16 + db = new Database(); 17 + }); 18 + }); 36 19 </script> 37 20 38 21 <div class="flex w-[344px] flex-col"> 39 22 <ScrollArea class="grid h-[250px] w-full select-none grid-cols-8 space-y-3 px-2"> 40 - {#if !emojiGroups[currentGroup] || emojiGroups[currentGroup].length === 0} 41 - <div class="col-span-8 flex h-full w-full"> 42 - <p class="text-base-500 dark:text-base-400 text-sm">Loading emojis...</p> 43 - </div> 44 - {/if} 45 - {#each emojiGroups[currentGroup] as emoji} 46 - <button 47 - onclick={() => { 48 - onpicked?.(emoji); 49 - }} 50 - class="hover:bg-accent-300/20 dark:hover:bg-accent-700/20 hover:scale-110 transition-transform duration-100 cursor-pointer rounded-full text-center text-xl size-10" 51 - >{emoji.unicode}</button 52 - > 53 - {/each} 23 + {#await db?.getEmojiByGroup(currentGroup) then emojis} 24 + {#if emojis} 25 + {#each emojis as emoji} 26 + {#if isEmojiSupported(emoji.unicode)} 27 + <button 28 + onclick={() => { 29 + onpicked?.(emoji); 30 + }} 31 + class="hover:bg-accent-300/20 dark:hover:bg-accent-700/20 size-10 cursor-pointer rounded-full text-center text-xl transition-transform duration-100 hover:scale-110" 32 + >{emoji.unicode}</button 33 + > 34 + {/if} 35 + {/each} 36 + {/if} 37 + {/await} 54 38 </ScrollArea> 55 - <div class="border-base-300/50 dark:border-base-700/50 flex justify-between gap-2 border-t px-3 py-2"> 39 + <div 40 + class="border-base-300/50 dark:border-base-700/50 flex justify-between gap-2 border-t px-3 py-2" 41 + > 56 42 {#each allGroups as group} 57 43 <button 58 44 onclick={() => (currentGroup = group.id)} 59 45 class={cn( 60 - '[&>svg]:size-4.5 cursor-pointer hover:scale-105 transition-all duration-100', 61 - group.id === currentGroup ? 'text-accent-600 dark:text-accent-400' : 'hover:text-accent-700 dark:hover:text-accent-300' 46 + '[&>svg]:size-4.5 cursor-pointer transition-all duration-100 hover:scale-105', 47 + group.id === currentGroup 48 + ? 'text-accent-600 dark:text-accent-400' 49 + : 'hover:text-accent-700 dark:hover:text-accent-300' 62 50 )} 63 51 >{@html group.svg} 64 52 <span class="sr-only">{group.name}</span>
+2 -2
packages/social/src/lib/components/emoji-picker/PopoverEmojiPicker.svelte
··· 1 1 <script lang="ts"> 2 2 import { Popover, type PopoverProps, cn } from '@fuxui/base'; 3 3 import EmojiPicker from './EmojiPicker.svelte'; 4 - import type { Emoji } from './emoji'; 4 + import type { NativeEmoji } from './emoji'; 5 5 import type { Snippet } from 'svelte'; 6 6 7 7 let { ··· 12 12 triggerRef = $bindable(null), 13 13 ...props 14 14 }: { 15 - onpicked?: (emoji: Emoji) => void; 15 + onpicked?: (emoji: NativeEmoji) => void; 16 16 children?: Snippet; 17 17 class?: string; 18 18 } & PopoverProps = $props();
+1 -8
packages/social/src/lib/components/emoji-picker/emoji.ts
··· 60 60 svg: string; 61 61 }[]; 62 62 63 - export type Emoji = { 64 - annotation: string; 65 - group: number; 66 - order: number; 67 - shortcodes: string[]; 68 - tags: string[]; 69 - unicode: string; 70 - }; 63 + export type { NativeEmoji } from 'emoji-picker-element/shared';
+1 -1
apps/docs/src/routes/(main)/components/3d/depth-3d/Depth3D.md
··· 16 16 17 17 ```svelte 18 18 <script lang="ts"> 19 - import { Depth3D } from 'fuchs'; 19 + import { Depth3D } from '@fuxui/3d'; 20 20 </script> 21 21 22 22 <Depth3D
+1 -1
apps/docs/src/routes/(main)/components/3d/model-picker/ModelPicker.md
··· 12 12 13 13 ```svelte 14 14 <script lang="ts"> 15 - import { ModelPicker } from 'fuchs'; 15 + import { ModelPicker } from '@fuxui/3d'; 16 16 17 17 const items = [ 18 18 {
+1 -1
apps/docs/src/routes/(main)/components/3d/voxel-art/VoxelArt.md
··· 14 14 15 15 ```svelte 16 16 <script lang="ts"> 17 - import { VoxelArt } from 'fuchs'; 17 + import { VoxelArt } from '@fuxui/3d'; 18 18 19 19 import data from '$lib/assets/model.json'; 20 20 </script>
+1 -1
apps/docs/src/routes/(main)/components/time/stopwatch/Stopwatch.md
··· 12 12 13 13 ```svelte 14 14 <script lang="ts"> 15 - import { Button, Stopwatch, StopwatchState } from 'fuchs'; 15 + import { Button, Stopwatch, StopwatchState } from '@fuxui/time'; 16 16 17 17 let stopwatch: StopwatchState | undefined = $state(); 18 18 </script>
+1 -1
apps/docs/src/routes/(main)/components/time/timer/Timer.md
··· 12 12 13 13 ```svelte 14 14 <script lang="ts"> 15 - import { Button, Timer, TimerState } from 'fuchs'; 15 + import { Button, Timer, TimerState } from '@fuxui/time'; 16 16 17 17 let timer = $state(new TimerState(1000 * 60 * 60)); 18 18 </script>