mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-22 02:23:46 +00:00
feat: add EmojiPickerButton and replace plain-text emoji inputs
Create a reusable EmojiPickerButton component that wraps EmojiPicker in a compact dropdown toggle. Replace the plain <input type="text"> emoji fields in quick action icons (EditCollectionModal) and role icons (roles page) with the new picker for a consistent UX.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import type { Collection, CollectionUpdate, CollectionSettings, FieldDef, FieldMigration, QuickAction } from '$lib/types';
|
||||
import { parseSchema, parseSettings } from '$lib/types';
|
||||
import EmojiPicker from '$lib/components/common/EmojiPicker.svelte';
|
||||
import EmojiPickerButton from '$lib/components/common/EmojiPickerButton.svelte';
|
||||
import { toastStore } from '$lib/stores/toast.svelte';
|
||||
|
||||
interface Props {
|
||||
@@ -602,14 +603,7 @@
|
||||
{#each itemActions as { action, index } (index)}
|
||||
<div class="action-card">
|
||||
<div class="action-card-top">
|
||||
<input
|
||||
class="action-icon-input"
|
||||
type="text"
|
||||
placeholder="⚡"
|
||||
bind:value={action.icon}
|
||||
maxlength="2"
|
||||
title="Icon (emoji)"
|
||||
/>
|
||||
<EmojiPickerButton bind:value={action.icon} placeholder="⚡" />
|
||||
<input
|
||||
class="action-label-input"
|
||||
type="text"
|
||||
@@ -644,14 +638,7 @@
|
||||
{#each collectionActions as { action, index } (index)}
|
||||
<div class="action-card">
|
||||
<div class="action-card-top">
|
||||
<input
|
||||
class="action-icon-input"
|
||||
type="text"
|
||||
placeholder="⚡"
|
||||
bind:value={action.icon}
|
||||
maxlength="2"
|
||||
title="Icon (emoji)"
|
||||
/>
|
||||
<EmojiPickerButton bind:value={action.icon} placeholder="⚡" />
|
||||
<input
|
||||
class="action-label-input"
|
||||
type="text"
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import EmojiPicker from '$lib/components/common/EmojiPicker.svelte';
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
placeholder?: string;
|
||||
size?: 'sm' | 'md';
|
||||
}
|
||||
|
||||
let { value = $bindable(), placeholder = '⚡', size = 'sm' }: Props = $props();
|
||||
|
||||
let open = $state(false);
|
||||
|
||||
function handleWindowClick(e: MouseEvent) {
|
||||
if (open && !(e.target as HTMLElement)?.closest('.emoji-picker-button')) {
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSelect(emoji: string) {
|
||||
value = emoji;
|
||||
open = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window onclick={handleWindowClick} />
|
||||
|
||||
<div class="emoji-picker-button" class:size-md={size === 'md'}>
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
class:open
|
||||
class:empty={!value}
|
||||
onclick={() => (open = !open)}
|
||||
>
|
||||
{value || placeholder}
|
||||
</button>
|
||||
|
||||
{#if open}
|
||||
<div class="dropdown">
|
||||
<EmojiPicker selected={value} onselect={handleSelect} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.emoji-picker-button {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
font-size: 1.1em;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.size-md .trigger {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.trigger:hover {
|
||||
border-color: var(--text-muted);
|
||||
}
|
||||
|
||||
.trigger.open {
|
||||
border-color: var(--accent-blue);
|
||||
}
|
||||
|
||||
.trigger.empty {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
top: calc(100% + 4px);
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -8,6 +8,7 @@
|
||||
import { itemUrlId } from '$lib/types';
|
||||
import type { Item, Collection, RoleBoardLane, AgentRole } from '$lib/types';
|
||||
import ItemCard from '$lib/components/collections/ItemCard.svelte';
|
||||
import EmojiPickerButton from '$lib/components/common/EmojiPickerButton.svelte';
|
||||
import { dndzone, TRIGGERS, SHADOW_ITEM_MARKER_PROPERTY_NAME } from 'svelte-dnd-action';
|
||||
import type { DndEvent } from 'svelte-dnd-action';
|
||||
|
||||
@@ -449,7 +450,7 @@
|
||||
<div class="role-field-group">
|
||||
<label class="role-field-label">Icon & Name</label>
|
||||
<div class="role-edit-row">
|
||||
<input class="role-input role-input-icon" type="text" bind:value={editIcon} placeholder="🔨" />
|
||||
<EmojiPickerButton bind:value={editIcon} placeholder="🔨" size="md" />
|
||||
<input class="role-input" type="text" bind:value={editName} placeholder="Role name" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user