feat(components): surface library metadata in assets
- Show imported library badges in the local Assets panel - Display component descriptions and documentation links from Figma metadata - Cover library metadata rendering in the Assets panel test
This commit is contained in:
parent
66f91de825
commit
880fcf3d5b
|
|
@ -6,6 +6,7 @@ import { useI18n } from '@open-pencil/vue'
|
|||
|
||||
import { nodeIcon } from '@/app/editor/icons'
|
||||
import { useEditorStore } from '@/app/editor/active-store'
|
||||
import { openExternalLink } from '@/app/shell/ui'
|
||||
import { useButtonUI } from '@/components/ui/button'
|
||||
import { useInputUI } from '@/components/ui/input'
|
||||
import Tip from '@/components/ui/Tip.vue'
|
||||
|
|
@ -18,6 +19,9 @@ type LocalAsset = {
|
|||
variants: Array<{ name: string; values: string[] }>
|
||||
variantCount: number
|
||||
hasConflicts: boolean
|
||||
sourceLibraryKey: string | null
|
||||
description: string
|
||||
docsUrl: string | null
|
||||
}
|
||||
|
||||
const editor = useEditorStore()
|
||||
|
|
@ -59,7 +63,10 @@ const assets = computed<LocalAsset[]>(() => {
|
|||
componentId: defaultVariant?.id ?? null,
|
||||
variants,
|
||||
variantCount: node.type === 'COMPONENT_SET' ? node.childIds.length : 0,
|
||||
hasConflicts: conflicts.length > 0
|
||||
hasConflicts: conflicts.length > 0,
|
||||
sourceLibraryKey: node.sourceLibraryKey,
|
||||
description: node.symbolDescription,
|
||||
docsUrl: node.symbolLinks[0]?.uri ?? null
|
||||
}
|
||||
})
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
|
@ -129,7 +136,16 @@ function insertAsset(asset: LocalAsset) {
|
|||
aria-hidden="true"
|
||||
/>
|
||||
<span class="min-w-0 flex-1">
|
||||
<span data-test-id="asset-name" class="block truncate">{{ asset.name }}</span>
|
||||
<span class="flex min-w-0 items-center gap-1.5">
|
||||
<span data-test-id="asset-name" class="truncate">{{ asset.name }}</span>
|
||||
<span
|
||||
v-if="asset.sourceLibraryKey"
|
||||
data-test-id="asset-library-badge"
|
||||
class="shrink-0 rounded bg-component/15 px-1 py-px text-[9px] font-medium text-component uppercase"
|
||||
>
|
||||
Library
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
v-if="asset.variants.length > 0"
|
||||
data-test-id="asset-variant-summary"
|
||||
|
|
@ -138,6 +154,13 @@ function insertAsset(asset: LocalAsset) {
|
|||
{{ asset.variantCount }} variants ·
|
||||
{{ asset.variants.map((variant) => variant.name).join(', ') }}
|
||||
</span>
|
||||
<span
|
||||
v-if="asset.description"
|
||||
data-test-id="asset-description"
|
||||
class="mt-0.5 block truncate text-[10px] text-muted"
|
||||
>
|
||||
{{ asset.description }}
|
||||
</span>
|
||||
<span
|
||||
v-if="asset.hasConflicts"
|
||||
data-test-id="asset-variant-conflict"
|
||||
|
|
@ -146,6 +169,17 @@ function insertAsset(asset: LocalAsset) {
|
|||
Duplicate variant values
|
||||
</span>
|
||||
</span>
|
||||
<Tip v-if="asset.docsUrl" label="Open documentation">
|
||||
<span
|
||||
:class="insertButton.base"
|
||||
data-test-id="asset-docs"
|
||||
@pointerdown.stop
|
||||
@dblclick.stop
|
||||
@click.stop="asset.docsUrl ? openExternalLink(asset.docsUrl) : undefined"
|
||||
>
|
||||
<icon-lucide-book-open class="size-3" />
|
||||
</span>
|
||||
</Tip>
|
||||
<Tip :label="commands.createInstance">
|
||||
<span
|
||||
:class="insertButton.base"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ test('assets panel groups component sets and inserts the default variant', async
|
|||
y: 80,
|
||||
width: 260,
|
||||
height: 100,
|
||||
sourceLibraryKey: 'lk-test-library',
|
||||
symbolDescription: 'Reusable button component',
|
||||
symbolLinks: [{ uri: 'https://example.com/button', displayName: 'Button docs' }],
|
||||
componentPropertyDefinitions: [
|
||||
{
|
||||
id: 'prop:type',
|
||||
|
|
@ -117,12 +120,16 @@ test('assets panel groups component sets and inserts the default variant', async
|
|||
await expect(assetsPanel).toContainText('Card')
|
||||
await expect(assetsPanel).not.toContainText('Type=Primary')
|
||||
await expect(assetsPanel).not.toContainText('Type=Secondary')
|
||||
await expect(
|
||||
page.locator(`[data-asset-id="${ids.setId}"] [data-test-id="asset-variant-summary"]`)
|
||||
).toContainText('Type')
|
||||
await expect(
|
||||
page.locator(`[data-asset-id="${ids.setId}"] [data-test-id="asset-variant-conflict"]`)
|
||||
).toContainText('Duplicate variant values')
|
||||
const buttonAsset = page.locator(`[data-asset-id="${ids.setId}"]`)
|
||||
await expect(buttonAsset.locator('[data-test-id="asset-variant-summary"]')).toContainText('Type')
|
||||
await expect(buttonAsset.locator('[data-test-id="asset-library-badge"]')).toContainText('Library')
|
||||
await expect(buttonAsset.locator('[data-test-id="asset-description"]')).toContainText(
|
||||
'Reusable button component'
|
||||
)
|
||||
await expect(buttonAsset.locator('[data-test-id="asset-docs"]')).toBeVisible()
|
||||
await expect(buttonAsset.locator('[data-test-id="asset-variant-conflict"]')).toContainText(
|
||||
'Duplicate variant values'
|
||||
)
|
||||
|
||||
await page.locator('[data-test-id="assets-search"]').fill('card')
|
||||
await expect(assetItems).toHaveCount(1)
|
||||
|
|
|
|||
Loading…
Reference in a new issue