feat(app-form): icon picker, tag/category autocomplete, typography
- Replace AppIconPicker text input with visual IconPickerButton for lucide icons (grid with search) - Add AutocompleteInput component for category field with existing category suggestions - Add TagsInput component for tags field with tag pills, autocomplete from existing tags, and keyboard navigation - Add GET /api/apps/suggestions endpoint returning all categories/tags - Add getAllTags() to appService (merges Tag model + comma-separated) - Install @tailwindcss/typography plugin to fix prose rendering (headings, lists, blockquotes now render in Note/Markdown widgets) - Fix note widget validator test for new html format
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
import AppIconPicker from './AppIconPicker.svelte';
|
||||
import IntegrationConfigFields from './IntegrationConfigFields.svelte';
|
||||
import AppUrlPreview from './AppUrlPreview.svelte';
|
||||
import AutocompleteInput from '$lib/components/ui/AutocompleteInput.svelte';
|
||||
import TagsInput from '$lib/components/ui/TagsInput.svelte';
|
||||
import IconGrid from '$lib/components/ui/IconGrid.svelte';
|
||||
import type { IconGridItem } from '$lib/components/ui/IconGrid.svelte';
|
||||
|
||||
@@ -25,6 +27,21 @@
|
||||
|
||||
let showAdvanced = $state(false);
|
||||
let showIntegration = $state(false);
|
||||
let categorySuggestions = $state<string[]>([]);
|
||||
let tagSuggestions = $state<string[]>([]);
|
||||
|
||||
// Fetch autocomplete suggestions
|
||||
$effect(() => {
|
||||
fetch('/api/apps/suggestions')
|
||||
.then((r) => r.json())
|
||||
.then((json) => {
|
||||
if (json.success) {
|
||||
categorySuggestions = json.data?.categories ?? [];
|
||||
tagSuggestions = json.data?.tags ?? [];
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
let availableIntegrations = $state<Array<{ id: string; name: string; icon: string; authConfigFields: any[]; extraConfigFields: any[] }>>([]);
|
||||
let integrationConfig = $state<Record<string, unknown>>({});
|
||||
let testingConnection = $state(false);
|
||||
@@ -148,13 +165,13 @@
|
||||
<label for="category" class="mb-1 block text-sm font-medium text-card-foreground">
|
||||
{$t('app.category')}
|
||||
</label>
|
||||
<input
|
||||
<AutocompleteInput
|
||||
id="category"
|
||||
name="category"
|
||||
type="text"
|
||||
bind:value={$form.category}
|
||||
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
suggestions={categorySuggestions}
|
||||
placeholder={$t('app.category_placeholder')}
|
||||
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -162,13 +179,13 @@
|
||||
<label for="tags" class="mb-1 block text-sm font-medium text-card-foreground">
|
||||
{$t('app.tags')}
|
||||
</label>
|
||||
<input
|
||||
<TagsInput
|
||||
id="tags"
|
||||
name="tags"
|
||||
type="text"
|
||||
bind:value={$form.tags}
|
||||
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
suggestions={tagSuggestions}
|
||||
placeholder={$t('app.tags_placeholder')}
|
||||
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user