directus-extension-csi-gallery-thumbnails 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +51 -0
  2. package/dist/index.js +1 -0
  3. package/package.json +38 -0
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # CSI Gallery Thumbnails display
2
+
3
+ A small Directus display that shows the first few images of a multi-image
4
+ field as thumbnails, so table views show pictures instead of a count
5
+ ("3 items").
6
+
7
+ Directus's built-in Related Values display can only show a count for a
8
+ multi-image field; its thumbnails appear after clicking the count. This display
9
+ draws the thumbnails in the cell itself: the first four by default, then `+N`.
10
+ Non-image files show a short type label such as `PDF`. Empty galleries show `--`.
11
+
12
+ Thumbnails use the same `system-small-cover` preset and cache buster as
13
+ Directus's own Image display, and load with the editor's session, so files in
14
+ private folders work too.
15
+
16
+ ## Fields
17
+
18
+ | Field | Path to the file |
19
+ | --- | --- |
20
+ | `product_families.gallery` (Files) | `directus_files_id` (default) |
21
+ | `products.gallery_assets` (Asset Library) | `asset_library_id.file` |
22
+
23
+ Set the field's display to **Gallery Thumbnails** and fill in **Path to the
24
+ file**: the dot path from one gallery row (the junction item) to its
25
+ `directus_files` record.
26
+
27
+ ## Build and test
28
+
29
+ ```sh
30
+ pnpm --filter directus-extension-csi-gallery-thumbnails test
31
+ pnpm --filter directus-extension-csi-gallery-thumbnails typecheck
32
+ pnpm --filter directus-extension-csi-gallery-thumbnails build
33
+ ```
34
+
35
+ The build creates `dist/index.js`.
36
+
37
+ ## Installation
38
+
39
+ Like the other CSI extensions, it installs from the Directus Marketplace, which
40
+ indexes the npm package:
41
+
42
+ 1. Publish the package to npm (`npm publish` from this folder after a build).
43
+ 2. Once the Marketplace lists it, install it with
44
+ `POST /extensions/registry/install {"extension": "<marketplace id>"}`.
45
+ 3. Set the field displays above.
46
+
47
+ Self-hosted Directus currently loses registry-installed extensions on every
48
+ container restart or instance replacement, so reinstall it with the others
49
+ until the hosting team bakes the CSI extensions into the Directus image. While
50
+ it is missing, the two fields show no thumbnails; switching their display back
51
+ to Related Values restores the click-to-open list.
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{defineDisplay as e}from"@directus/extensions-sdk";import{defineComponent as t,reactive as n,computed as i,openBlock as a,createElementBlock as r,Fragment as l,renderList as s,unref as o,toDisplayString as u,createCommentVNode as d}from"vue";const f="directus_files_id",c=["id","type","title","modified_on"];function m(e){return("string"==typeof e?e.trim().replace(/^\.+|\.+$/g,""):"")||f}function p(e){return e.type?.startsWith("image/")??!1}function h(e,t){const n=new URL(`assets/${t.id}`,e);return n.searchParams.set("key","system-small-cover"),t.modified_on&&n.searchParams.set("v",t.modified_on),n.href}function y(e){const t=e.type?.split("/")[1]?.split(/[+.;-]/)[0];return(t||"file").slice(0,4).toUpperCase()}const v={key:0,class:"null"},g=["title"],b=["alt","src","onError"],_={key:1,class:"thumb file"},x={key:0,class:"more"};var k=t({__name:"display",props:{value:{},filePath:{},limit:{}},setup(e){const t=e,f=function(e){const t=e.split("/"),n=t.indexOf("admin");return`${t.slice(0,n).join("/")}/`}(window.location.href),c=n(new Set),k=i(()=>function(e,t){if(!Array.isArray(e))return[];const n=m(t);return e.flatMap(e=>{const t=function(e,t){return t.split(".").reduce((e,t)=>{if(e&&"object"==typeof e)return e[t]},e)}(e,n);if(!t||"object"!=typeof t)return[];const{id:i,type:a,title:r,modified_on:l}=t;return"string"==typeof i&&i?[{id:i,type:"string"==typeof a?a:null,title:"string"==typeof r?r:null,modified_on:"string"==typeof l?l:null}]:[]})}(t.value,t.filePath)),w=i(()=>k.value.slice(0,function(e){const t="number"==typeof e?e:Number.parseInt(String(e??""),10);return!Number.isFinite(t)||t<1?4:Math.min(Math.floor(t),20)}(t.limit))),j=i(()=>k.value.length-w.value.length),A=i(()=>`${k.value.length} ${1===k.value.length?"file":"files"}`);return(e,t)=>0===k.value.length?(a(),r("span",v,"--")):(a(),r("span",{key:1,class:"gallery-thumbnails",title:A.value},[(a(!0),r(l,null,s(w.value,e=>(a(),r(l,{key:e.id},[o(p)(e)&&!c.has(e.id)?(a(),r("img",{key:0,alt:e.title??"",src:o(h)(o(f),e),class:"thumb",loading:"lazy",onError:t=>{return n=e.id,void c.add(n);var n}},null,40,b)):(a(),r("span",_,u(o(y)(e)),1))],64))),128)),j.value>0?(a(),r("span",x,"+"+u(j.value),1)):d("v-if",!0)],8,g))}}),w=[],j=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,i=!0===t.prepend?"prepend":"append",a=!0===t.singleTag,r="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(a){var l=w.indexOf(r);-1===l&&(l=w.push(r)-1,j[l]={}),n=j[l]&&j[l][i]?j[l][i]:j[l][i]=s()}else n=s();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function s(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),a=0;a<n.length;a++)e.setAttribute(n[a],t.attributes[n[a]]);var l="prepend"===i?"afterbegin":"beforeend";return r.insertAdjacentElement(l,e),e}}("\n.gallery-thumbnails[data-v-dfa8e593] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n max-inline-size: 100%;\n vertical-align: middle;\n}\n.thumb[data-v-dfa8e593] {\n flex: none;\n inline-size: 32px;\n block-size: 32px;\n border-radius: var(--theme--border-radius);\n object-fit: cover;\n background-color: var(--theme--background-normal);\n}\n.file[data-v-dfa8e593] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--theme--foreground-subdued);\n font-size: 9px;\n font-weight: 600;\n}\n.more[data-v-dfa8e593],\n.null[data-v-dfa8e593] {\n color: var(--theme--foreground-subdued);\n}\n.more[data-v-dfa8e593] {\n flex: none;\n font-size: 12px;\n}\n",{});var A=e({id:"csi-gallery-thumbnails",name:"Gallery Thumbnails",icon:"photo_library",description:"Show the first few images of a multi-image field as thumbnails.",component:((e,t)=>{const n=e.__vccOpts||e;for(const[e,i]of t)n[e]=i;return n})(k,[["__scopeId","data-v-dfa8e593"]]),types:["alias"],localTypes:["files","m2m","o2m"],fields:e=>function(e){const t=m(e);return c.map(e=>`${t}.${e}`)}(e?.filePath),options:[{field:"filePath",name:"Path to the file",type:"string",meta:{interface:"input",width:"half",note:"From one gallery row to its file. Files field: directus_files_id. Asset Library: asset_library_id.file",options:{placeholder:f,font:"monospace"}},schema:{default_value:f}},{field:"limit",name:"Thumbnails to show",type:"integer",meta:{interface:"input",width:"half",options:{min:1,max:20}},schema:{default_value:4}}]});export{A as default};
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "directus-extension-csi-gallery-thumbnails",
3
+ "version": "0.1.0",
4
+ "description": "Directus display that shows a row of image thumbnails for multi-file gallery fields in table views.",
5
+ "keywords": [
6
+ "directus",
7
+ "directus-extension",
8
+ "display",
9
+ "gallery",
10
+ "thumbnails"
11
+ ],
12
+ "icon": "photo_library",
13
+ "license": "UNLICENSED",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "type": "module",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "directus-extension build",
23
+ "test": "node --experimental-strip-types --test tests/*.test.ts",
24
+ "typecheck": "tsc --noEmit"
25
+ },
26
+ "devDependencies": {
27
+ "@directus/extensions-sdk": "18.0.3",
28
+ "@types/node": "^22.15.30",
29
+ "typescript": "^5.8.3",
30
+ "vue": "3.5.24"
31
+ },
32
+ "directus:extension": {
33
+ "type": "display",
34
+ "path": "dist/index.js",
35
+ "source": "src/index.ts",
36
+ "host": "^12.2.0"
37
+ }
38
+ }