diff --git a/apps/docs/next-env.d.ts b/apps/docs/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/apps/docs/next-env.d.ts +++ b/apps/docs/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/example-studio/package.json b/apps/example-studio/package.json index 7823305..b96af75 100644 --- a/apps/example-studio/package.json +++ b/apps/example-studio/package.json @@ -17,9 +17,10 @@ "dependencies": { "@sanity/color-input": "^6.0.2", "@sanity/dashboard": "^5.0.1", + "@sanity/sanity-plugin-async-list": "1.3.3", "@sanity/vision": "^5.1.0", "@seidhr/sanity-plugin-dashboard-widget-muna-docs": "*", - "@seidhr/sanity-plugin-muna-kulturnav-api": "*", + "@seidhr/sanity-plugin-muna-la-external-references": "*", "@seidhr/sanity-plugin-timespan-input": "*", "react": "^19.2.3", "react-dom": "^19.2.3", @@ -42,4 +43,4 @@ "bracketSpacing": false, "singleQuote": true } -} \ No newline at end of file +} diff --git a/apps/example-studio/sanity.config.ts b/apps/example-studio/sanity.config.ts index 4907632..e1a28d2 100644 --- a/apps/example-studio/sanity.config.ts +++ b/apps/example-studio/sanity.config.ts @@ -3,10 +3,11 @@ import { structureTool } from 'sanity/structure' import { dashboardTool } from "@sanity/dashboard"; import { visionTool } from '@sanity/vision' import { colorInput } from '@sanity/color-input' -import { APISearchInput } from '@seidhr/sanity-plugin-muna-kulturnav-api' +import { createKulturnavLoader, externalReferenceInput } from '@seidhr/sanity-plugin-muna-la-external-references' import { munaDocsWidget } from '@seidhr/sanity-plugin-dashboard-widget-muna-docs' import { timespanInput } from '@seidhr/sanity-plugin-timespan-input' import { schemaTypes } from './schemas' +import { asyncList } from '@sanity/sanity-plugin-async-list'; export default defineConfig({ name: 'default', @@ -23,9 +24,26 @@ export default defineConfig({ munaDocsWidget({ layout: { width: 'auto' } }), ] }), - APISearchInput({}), + externalReferenceInput({ + schemaType: 'kulturnavReference', + loader: createKulturnavLoader({ + entityTypes: ['Concept'], + }), + }), timespanInput(), colorInput(), + asyncList({ + schemaType: 'disneyCharacter', // Name of type to be used in schema definitions + // Loader function to fetch data however you prefer + loader: async () => { + const response = await fetch('https://api.disneyapi.dev/character') + const result: { data: { name: string }[] } = await response.json() + + return result.data.map((item) => { + return { value: item.name, ...item } + }) + }, + }), ], schema: { diff --git a/apps/example-studio/schemas/Post.js b/apps/example-studio/schemas/Post.js index 25c2a7e..dab25e5 100644 --- a/apps/example-studio/schemas/Post.js +++ b/apps/example-studio/schemas/Post.js @@ -15,6 +15,63 @@ export default defineType({ title: 'Timespan', type: 'Timespan', }), + defineField({ + name: 'creator', + title: 'Creator', + type: 'array', + description: 'References to people from kulturnav.org', + of: [ + { + type: 'kulturnavReference', + // Field-level options override plugin defaults + // This field will search for Person entities instead of Concept + options: { + loaderOptions: { + entityTypes: ['Person'], + }, + autocompleteProps: { + placeholder: 'Search for a person...', + }, + }, + }, + ], + }), + defineField({ + name: 'subjects', + title: 'Subjects', + type: 'array', + description: 'Array of concept references from kulturnav.org', + of: [ + { + type: 'kulturnavReference', + // This field uses the plugin default (Concept) from sanity.config.ts + // but you could override it here if needed: + // options: { loaderOptions: { entityTypes: ['Concept'] } } + }, + ], + }), + defineField({ + name: 'related_posts', + title: 'Related Posts', + type: 'array', + description: 'References to other posts', + of: [ + { + type: 'reference', + to: [{ type: 'Post' }], + }, + ], + }), + defineField({ + name: 'disney', + type: 'array', + description: 'References to disney characters', + of: [ + { + type: 'disneyCharacter', + }, + ], + }), ], preview: { diff --git a/apps/example-studio/turbo.json b/apps/example-studio/turbo.json index 9823271..0a6b127 100644 --- a/apps/example-studio/turbo.json +++ b/apps/example-studio/turbo.json @@ -18,7 +18,7 @@ "with": [ "@seidhr/sanity-plugin-dashboard-widget-muna-docs#watch", "@seidhr/sanity-plugin-timespan-input#watch", - "@seidhr/sanity-plugin-muna-kulturnav-api#watch" + "@seidhr/sanity-plugin-muna-la-external-references#watch" ] } } diff --git a/package-lock.json b/package-lock.json index 14cb58f..dd26fe6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -122,9 +122,10 @@ "dependencies": { "@sanity/color-input": "^6.0.2", "@sanity/dashboard": "^5.0.1", + "@sanity/sanity-plugin-async-list": "1.3.3", "@sanity/vision": "^5.1.0", "@seidhr/sanity-plugin-dashboard-widget-muna-docs": "*", - "@seidhr/sanity-plugin-muna-kulturnav-api": "*", + "@seidhr/sanity-plugin-muna-la-external-references": "*", "@seidhr/sanity-plugin-timespan-input": "*", "react": "^19.2.3", "react-dom": "^19.2.3", @@ -12838,6 +12839,282 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@sanity/sanity-plugin-async-list": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@sanity/sanity-plugin-async-list/-/sanity-plugin-async-list-1.3.3.tgz", + "integrity": "sha512-b5vs05JAWua8+o/bRN869P5+y74TkHLiJ0IqCz5r7f8om3EdnwkKR6zxREvo2talrlMjzsH7FMxxRWgVzQj3XQ==", + "license": "MIT", + "dependencies": { + "@sanity/icons": "^3.5.0", + "@sanity/incompatible-plugin": "^1.0.4", + "@sanity/studio-secrets": "^3.0.0", + "@sanity/ui": "^2.9.0", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19", + "sanity": "^3 || ^4.0.0-0 || ^5.0.0-0", + "styled-components": "^6.1" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/@sanity/ui": { + "version": "2.16.22", + "resolved": "https://registry.npmjs.org/@sanity/ui/-/ui-2.16.22.tgz", + "integrity": "sha512-Zw217nqjLhROHrjFYPCwV61xEYHwUbBOohHO2DZ4LdQKqNfTKsqcjLVx9Heb4oDzB06L+1CamIrvPaexVijfeg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.6", + "@juggle/resize-observer": "^3.4.0", + "@sanity/color": "^3.0.6", + "@sanity/icons": "^3.7.4", + "csstype": "^3.1.3", + "motion": "^12.23.24", + "react-compiler-runtime": "1.0.0", + "react-refractor": "^2.2.0", + "use-effect-event": "^2.0.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^18 || >=19.0.0-0", + "react-dom": "^18 || >=19.0.0-0", + "react-is": "^18 || >=19.0.0-0", + "styled-components": "^5.2 || ^6" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/react-refractor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/react-refractor/-/react-refractor-2.2.0.tgz", + "integrity": "sha512-UvWkBVqH/2b9nkkkt4UNFtU3aY1orQfd4plPjx5rxbefy6vGajNHU9n+tv8CbykFyVirr3vEBfN2JTxyK0d36g==", + "license": "MIT", + "dependencies": { + "refractor": "^3.6.0", + "unist-util-filter": "^2.0.2", + "unist-util-visit-parents": "^3.0.2" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "license": "MIT", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/unist-util-filter": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-2.0.3.tgz", + "integrity": "sha512-8k6Jl/KLFqIRTHydJlHh6+uFgqYHq66pV75pZgr1JwfyFSjbWb12yfb0yitW/0TbHXjr9U4G9BQpOvMANB+ExA==", + "license": "MIT", + "dependencies": { + "unist-util-is": "^4.0.0" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@sanity/sanity-plugin-async-list/node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/@sanity/schema": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@sanity/schema/-/schema-5.1.0.tgz", @@ -13023,6 +13300,279 @@ "@noble/hashes": "^2.0.0" } }, + "node_modules/@sanity/studio-secrets": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@sanity/studio-secrets/-/studio-secrets-3.0.3.tgz", + "integrity": "sha512-L9eNKVOelFhnFxM3WTyXfal63iiOjlHdXiwdJg9Iz9+5mjXOiHgtiVSWSlkqsexTDgTqAyONcQGL6FMJxSOF6w==", + "license": "MIT", + "dependencies": { + "@sanity/incompatible-plugin": "^1.0.5", + "@sanity/ui": "^2.10.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18.2.0 || ^19", + "sanity": "^3.36.4 || ^4.0.0-0 || ^5.0.0", + "styled-components": "^6.1" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/@sanity/ui": { + "version": "2.16.22", + "resolved": "https://registry.npmjs.org/@sanity/ui/-/ui-2.16.22.tgz", + "integrity": "sha512-Zw217nqjLhROHrjFYPCwV61xEYHwUbBOohHO2DZ4LdQKqNfTKsqcjLVx9Heb4oDzB06L+1CamIrvPaexVijfeg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.6", + "@juggle/resize-observer": "^3.4.0", + "@sanity/color": "^3.0.6", + "@sanity/icons": "^3.7.4", + "csstype": "^3.1.3", + "motion": "^12.23.24", + "react-compiler-runtime": "1.0.0", + "react-refractor": "^2.2.0", + "use-effect-event": "^2.0.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^18 || >=19.0.0-0", + "react-dom": "^18 || >=19.0.0-0", + "react-is": "^18 || >=19.0.0-0", + "styled-components": "^5.2 || ^6" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@sanity/studio-secrets/node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/react-refractor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/react-refractor/-/react-refractor-2.2.0.tgz", + "integrity": "sha512-UvWkBVqH/2b9nkkkt4UNFtU3aY1orQfd4plPjx5rxbefy6vGajNHU9n+tv8CbykFyVirr3vEBfN2JTxyK0d36g==", + "license": "MIT", + "dependencies": { + "refractor": "^3.6.0", + "unist-util-filter": "^2.0.2", + "unist-util-visit-parents": "^3.0.2" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "license": "MIT", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/unist-util-filter": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-2.0.3.tgz", + "integrity": "sha512-8k6Jl/KLFqIRTHydJlHh6+uFgqYHq66pV75pZgr1JwfyFSjbWb12yfb0yitW/0TbHXjr9U4G9BQpOvMANB+ExA==", + "license": "MIT", + "dependencies": { + "unist-util-is": "^4.0.0" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@sanity/studio-secrets/node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/@sanity/telemetry": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@sanity/telemetry/-/telemetry-0.8.1.tgz", @@ -13206,8 +13756,8 @@ "resolved": "packages/sanity-plugin-dashboard-widget-muna-docs", "link": true }, - "node_modules/@seidhr/sanity-plugin-muna-kulturnav-api": { - "resolved": "packages/sanity-plugin-muna-kulturnav-api", + "node_modules/@seidhr/sanity-plugin-muna-la-external-references": { + "resolved": "packages/sanity-plugin-muna-la-external-references", "link": true }, "node_modules/@seidhr/sanity-plugin-muna-schemas": { @@ -35228,7 +35778,7 @@ "@svgr/cli": "^8.1.0", "@swc/core": "^1.3.84", "eslint-config-sanity": "^7.1.3", - "svgo": "^3.3.2", + "svgo": "^4.0.0", "svgo-autocrop": "^1.1.2", "tsup": "^7.2.0" }, @@ -35241,6 +35791,63 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, + "packages/react-muna-logo/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "packages/react-muna-logo/node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "packages/react-muna-logo/node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true, + "license": "CC0-1.0" + }, + "packages/react-muna-logo/node_modules/svgo": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", + "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.4.1" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, "packages/sanity-plugin-dashboard-widget-muna-docs": { "name": "@seidhr/sanity-plugin-dashboard-widget-muna-docs", "version": "3.0.0", @@ -35334,6 +35941,7 @@ "packages/sanity-plugin-muna-kulturnav-api": { "name": "@seidhr/sanity-plugin-muna-kulturnav-api", "version": "1.0.0", + "extraneous": true, "license": "MIT", "dependencies": { "@pnpm/npm-conf": "^3.0.1", @@ -35371,7 +35979,49 @@ "sanity": "^5" } }, - "packages/sanity-plugin-muna-kulturnav-api/node_modules/eslint-plugin-prettier": { + "packages/sanity-plugin-muna-la-external-references": { + "name": "@seidhr/sanity-plugin-muna-la-external-references", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^3.0.1", + "@sanity/icons": "^3.1.11", + "@sanity/incompatible-plugin": "^1.0.5", + "@sanity/ui": "^3.1.11", + "prettier-linter-helpers": "^1.0.0" + }, + "devDependencies": { + "@sanity/pkg-utils": "^10.2.3", + "@sanity/plugin-kit": "^4.0.0", + "@types/react": "^19.2.7", + "@typescript-eslint/eslint-plugin": "^8.0.0", + "@typescript-eslint/parser": "^8.0.0", + "eslint": "^9", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.0", + "npm-run-all": "^4.1.5", + "prettier": "^3.7.4", + "prettier-plugin-packagejson": "^2.5.20", + "react": "^19.2.3", + "react-dom": "^19.2.3", + "react-is": "^19.2.3", + "rimraf": "^6.0.0", + "sanity": "^5.1.0", + "styled-components": "^6.1.19", + "typescript": "^5.9.3", + "typescript-eslint": "^8.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^19.2.3", + "sanity": "^5" + } + }, + "packages/sanity-plugin-muna-la-external-references/node_modules/eslint-plugin-prettier": { "version": "5.5.4", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", @@ -35402,7 +36052,7 @@ } } }, - "packages/sanity-plugin-muna-kulturnav-api/node_modules/prettier": { + "packages/sanity-plugin-muna-la-external-references/node_modules/prettier": { "version": "3.7.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", diff --git a/packages/sanity-plugin-muna-kulturnav-api/src/index.ts b/packages/sanity-plugin-muna-kulturnav-api/src/index.ts deleted file mode 100644 index 902f66e..0000000 --- a/packages/sanity-plugin-muna-kulturnav-api/src/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { definePlugin } from 'sanity' - -interface MyPluginConfig { - /* nothing here yet */ -} - -/** - * Usage in `sanity.config.ts` (or .js) - * - * ```ts - * import {defineConfig} from 'sanity' - * import {APISearchInput} from 'sanity-plugin-muna-kulturnav-api' -* - * export default defineConfig({ - * // ... - * plugins: [APISearchInput()], - * }) - * ``` - * - * @public - */ -export const APISearchInput = definePlugin((config = {}) => { - // eslint-disable-next-line no-console - console.log('hello from sanity-plugin-muna-kulturnav-api, Tarje') - return { - name: 'sanity-plugin-muna-kulturnav-api', - } -}) diff --git a/packages/sanity-plugin-muna-kulturnav-api/tsconfig.tsbuildinfo b/packages/sanity-plugin-muna-kulturnav-api/tsconfig.tsbuildinfo deleted file mode 100644 index 1bfdbc2..0000000 --- a/packages/sanity-plugin-muna-kulturnav-api/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./src/index.ts","./package.config.ts"],"version":"5.9.3"} \ No newline at end of file diff --git a/packages/sanity-plugin-muna-kulturnav-api/.editorconfig b/packages/sanity-plugin-muna-la-external-references/.editorconfig similarity index 100% rename from packages/sanity-plugin-muna-kulturnav-api/.editorconfig rename to packages/sanity-plugin-muna-la-external-references/.editorconfig diff --git a/packages/sanity-plugin-muna-kulturnav-api/.prettierignore b/packages/sanity-plugin-muna-la-external-references/.prettierignore similarity index 100% rename from packages/sanity-plugin-muna-kulturnav-api/.prettierignore rename to packages/sanity-plugin-muna-la-external-references/.prettierignore diff --git a/packages/sanity-plugin-muna-kulturnav-api/.prettierrc b/packages/sanity-plugin-muna-la-external-references/.prettierrc similarity index 100% rename from packages/sanity-plugin-muna-kulturnav-api/.prettierrc rename to packages/sanity-plugin-muna-la-external-references/.prettierrc diff --git a/packages/sanity-plugin-muna-kulturnav-api/LICENSE b/packages/sanity-plugin-muna-la-external-references/LICENSE similarity index 100% rename from packages/sanity-plugin-muna-kulturnav-api/LICENSE rename to packages/sanity-plugin-muna-la-external-references/LICENSE diff --git a/packages/sanity-plugin-muna-kulturnav-api/README.md b/packages/sanity-plugin-muna-la-external-references/README.md similarity index 78% rename from packages/sanity-plugin-muna-kulturnav-api/README.md rename to packages/sanity-plugin-muna-la-external-references/README.md index f6b4b76..0a994f8 100644 --- a/packages/sanity-plugin-muna-kulturnav-api/README.md +++ b/packages/sanity-plugin-muna-la-external-references/README.md @@ -1,11 +1,11 @@ -# sanity-plugin-muna-kulturnav-api +# sanity-plugin-muna-la-external-references > This is a **Sanity Studio v3** plugin. ## Installation ```sh -npm install sanity-plugin-muna-kulturnav-api +npm install sanity-plugin-muna-la-external-references ``` ## Usage @@ -14,7 +14,7 @@ Add it as a plugin in `sanity.config.ts` (or .js): ```ts import {defineConfig} from 'sanity' -import {myPlugin} from 'sanity-plugin-muna-kulturnav-api' +import {myPlugin} from 'sanity-plugin-muna-la-external-references' export default defineConfig({ //... diff --git a/packages/sanity-plugin-muna-kulturnav-api/eslint.config.js b/packages/sanity-plugin-muna-la-external-references/eslint.config.js similarity index 90% rename from packages/sanity-plugin-muna-kulturnav-api/eslint.config.js rename to packages/sanity-plugin-muna-la-external-references/eslint.config.js index 942637c..5fe3bc3 100644 --- a/packages/sanity-plugin-muna-kulturnav-api/eslint.config.js +++ b/packages/sanity-plugin-muna-la-external-references/eslint.config.js @@ -1,7 +1,6 @@ import tseslint from 'typescript-eslint'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; -import prettier from 'eslint-plugin-prettier'; export default [ { @@ -17,7 +16,6 @@ export default [ plugins: { react, 'react-hooks': reactHooks, - prettier, }, settings: { react: { @@ -29,7 +27,6 @@ export default [ ...react.configs['jsx-runtime'].rules, ...reactHooks.configs.recommended.rules, '@typescript-eslint/no-unnecessary-type-constraint': 'off', - 'prettier/prettier': 'error', }, }, { diff --git a/packages/sanity-plugin-muna-kulturnav-api/package.config.ts b/packages/sanity-plugin-muna-la-external-references/package.config.ts similarity index 100% rename from packages/sanity-plugin-muna-kulturnav-api/package.config.ts rename to packages/sanity-plugin-muna-la-external-references/package.config.ts diff --git a/packages/sanity-plugin-muna-kulturnav-api/package.json b/packages/sanity-plugin-muna-la-external-references/package.json similarity index 95% rename from packages/sanity-plugin-muna-kulturnav-api/package.json rename to packages/sanity-plugin-muna-la-external-references/package.json index 0415c27..0d68eda 100644 --- a/packages/sanity-plugin-muna-kulturnav-api/package.json +++ b/packages/sanity-plugin-muna-la-external-references/package.json @@ -1,5 +1,5 @@ { - "name": "@seidhr/sanity-plugin-muna-kulturnav-api", + "name": "@seidhr/sanity-plugin-muna-la-external-references", "private": true, "version": "1.0.0", "description": "", @@ -48,6 +48,8 @@ "dependencies": { "@pnpm/npm-conf": "^3.0.1", "@sanity/incompatible-plugin": "^1.0.5", + "@sanity/icons": "^3.1.11", + "@sanity/ui": "^3.1.11", "prettier-linter-helpers": "^1.0.0" }, "devDependencies": { diff --git a/packages/sanity-plugin-muna-kulturnav-api/sanity.json b/packages/sanity-plugin-muna-la-external-references/sanity.json similarity index 100% rename from packages/sanity-plugin-muna-kulturnav-api/sanity.json rename to packages/sanity-plugin-muna-la-external-references/sanity.json diff --git a/packages/sanity-plugin-muna-la-external-references/src/components/DetailsPopup.tsx b/packages/sanity-plugin-muna-la-external-references/src/components/DetailsPopup.tsx new file mode 100644 index 0000000..1d0b352 --- /dev/null +++ b/packages/sanity-plugin-muna-la-external-references/src/components/DetailsPopup.tsx @@ -0,0 +1,349 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react' +import { + Portal, + Card, + Stack, + Text, + Button, + Heading, + Box, + Flex, + Spinner, + Badge, + Code, +} from '@sanity/ui' +import { CloseIcon, LaunchIcon } from '@sanity/icons' + +import type { KulturnavDetails, KulturnavReference } from '../types' + +interface DetailsPopupProps { + item: KulturnavReference + details: KulturnavDetails | null + isLoading: boolean + onClose: () => void +} + +/** + * Extract value from JSON-LD object or return the value itself + */ +function extractJsonLdValue(value: any): string { + if (value == null) return '' + if (typeof value === 'string') return value + if (typeof value === 'object' && value['@value']) return value['@value'] + if (typeof value === 'object' && Array.isArray(value)) { + // If it's an array, get the first value + return value.map(extractJsonLdValue).filter(Boolean).join(', ') || '' + } + return String(value) +} + +/** + * Parse kulturnav caption to extract structured information + */ +function parseCaption(caption: string): { + name: string + dates?: string + language?: string + profession?: string +} { + // Pattern: "Name (dates) [lang] Profession" or variations + const match = caption.match(/^(.+?)(?:\s*\(([^)]+)\))?(?:\s*\[([^\]]+)\])?(?:\s+(.+))?$/) + if (!match) { + return { name: caption } + } + + const [, name, dates, language, profession] = match + return { + name: name.trim(), + dates: dates?.trim(), + language: language?.trim(), + profession: profession?.trim(), + } +} + +/** + * Popup component to show detailed information about a kulturnav reference + * + * @public + */ +export function DetailsPopup({ + item, + details, + isLoading, + onClose, +}: DetailsPopupProps): React.JSX.Element { + const popupRef = useRef(null) + + const parsedCaption = useMemo(() => { + // Try to get caption from details first, then from item + let caption = details?.caption || item.label || '' + + // Handle JSON-LD format: entity.fullCaption, name, or title with @value + if (details && !caption) { + if (details['entity.fullCaption']) { + const fullCaption = details['entity.fullCaption'] + if (typeof fullCaption === 'object' && fullCaption['@value']) { + caption = fullCaption['@value'] + } else if (typeof fullCaption === 'string') { + caption = fullCaption + } + } else if (details.name) { + const name = details.name + if (typeof name === 'object' && name['@value']) { + caption = name['@value'] + } else if (typeof name === 'string') { + caption = name + } + } else if (details.title) { + const title = details.title + if (typeof title === 'object' && title['@value']) { + caption = title['@value'] + } else if (typeof title === 'string') { + caption = title + } + } + } + + return parseCaption(caption) + }, [details, item.label]) + + // Close on escape key + useEffect(() => { + function handleEscape(e: KeyboardEvent) { + if (e.key === 'Escape') { + onClose() + } + } + + document.addEventListener('keydown', handleEscape) + return () => { + document.removeEventListener('keydown', handleEscape) + } + }, [onClose]) + + // Close on click outside + useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if (popupRef.current && !popupRef.current.contains(e.target as Node)) { + onClose() + } + } + + document.addEventListener('mousedown', handleClickOutside) + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, [onClose]) + + // Extract UUID for external link + const uuid = useMemo(() => { + const match = item.id.match(/\/([a-f0-9-]+)$/i) + return match ? match[1] : null + }, [item.id]) + + const externalUrl = uuid ? `https://kulturnav.org/${uuid}` : null + + return ( + + + e.stopPropagation()} + > + {/* Header */} + + + + {isLoading ? ( + + + Loading details... + + + + ) : details ? ( + + {parsedCaption.name} + + {parsedCaption.dates && ( + + {parsedCaption.dates} + + )} + {parsedCaption.language && ( + + {parsedCaption.language} + + )} + {parsedCaption.profession && ( + + {parsedCaption.profession} + + )} + + + ) : ( + {item.label || 'Untitled'} + )} + +