directus-extension-csi-gallery-thumbnails 0.1.0 → 0.2.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 -15
  2. package/dist/index.js +1 -1
  3. package/package.json +7 -2
package/README.md CHANGED
@@ -1,27 +1,37 @@
1
- # CSI Gallery Thumbnails display
1
+ # CSI Image Thumbnails display
2
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").
3
+ A Directus display for single-image fields and complete galleries. Both follow
4
+ the same Compact, Cozy, and Comfortable table spacing. Gallery cells show
5
+ pictures instead of a count ("3 items").
6
6
 
7
7
  Directus's built-in Related Values display can only show a count for a
8
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`.
9
+ draws every thumbnail in the cell itself, wrapping onto additional lines when the column is narrow.
10
10
  Non-image files show a short type label such as `PDF`. Empty galleries show `--`.
11
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.
12
+ Thumbnails follow Directus 12.3.1 table spacing: **Compact 32px**, **Cozy
13
+ 56px**, **Comfortable 80px**. Rows containing this display expand to fit the
14
+ images, including wrapped galleries. Other tables keep their native row height.
15
+ The display matches the native row's 31/45/60px CSS variable values, without
16
+ relying on their generated names; verify these values when upgrading Directus.
17
+
18
+ Images use 160px contain transformations for crisp 80px previews without
19
+ cropping, retain the modified-on cache buster, and load with the editor's
20
+ session so private files work too. Directus must allow these asset
21
+ transformations. Existing saved `limit` options are ignored; every photo is
22
+ shown. Empty and non-image file behavior is preserved.
15
23
 
16
24
  ## Fields
17
25
 
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` |
26
+ | Field | Path to the file |
27
+ | ------------------------------------------- | ----------------------------- |
28
+ | `products.thumbnail` (single file) | No option needed |
29
+ | `product_families.hero_image` (single file) | No option needed |
30
+ | `product_families.gallery` (Files) | `directus_files_id` (default) |
31
+ | `products.gallery_assets` (Asset Library) | `asset_library_id.file` |
22
32
 
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
33
+ Set the field's display to **Image Thumbnails**. Single-file fields need no
34
+ options. For galleries, fill in **Path to the file**: the dot path from one gallery row (the junction item) to its
25
35
  `directus_files` record.
26
36
 
27
37
  ## Build and test
@@ -39,7 +49,7 @@ The build creates `dist/index.js`.
39
49
  Like the other CSI extensions, it installs from the Directus Marketplace, which
40
50
  indexes the npm package:
41
51
 
42
- 1. Publish the package to npm (`npm publish` from this folder after a build).
52
+ 1. Publish the package to npm using the GitHub workflow below.
43
53
  2. Once the Marketplace lists it, install it with
44
54
  `POST /extensions/registry/install {"extension": "<marketplace id>"}`.
45
55
  3. Set the field displays above.
@@ -49,3 +59,29 @@ container restart or instance replacement, so reinstall it with the others
49
59
  until the hosting team bakes the CSI extensions into the Directus image. While
50
60
  it is missing, the two fields show no thumbnails; switching their display back
51
61
  to Related Values restores the click-to-open list.
62
+
63
+ ## Single-image activation
64
+
65
+ After 0.2.0 is installed, change only the display metadata on
66
+ `products.thumbnail` and `product_families.hero_image` to
67
+ `display=csi-gallery-thumbnails`, with `display_options=null`. Preserve their
68
+ interfaces and file references. The extension uses Directus's field type to
69
+ fetch the related file directly; it does not change the stored image.
70
+
71
+ ## Publishing without browser authentication
72
+
73
+ Configure an npm trusted publisher for this package with GitHub owner
74
+ `Nuwave-Marketing`, repository `csi-big-commerce-catalyst`, workflow filename
75
+ `publish-gallery-thumbnails.yml`, and **Allow npm publish** enabled. Leave the
76
+ environment name empty; dist-tag management is not needed.
77
+
78
+ After merging a version change to `main`, run **Publish Directus Image
79
+ Thumbnails** in GitHub Actions on `main` and enter the package version. The
80
+ workflow checks that version, tests and builds the extension using locked
81
+ dependencies, and publishes using GitHub's short-lived OIDC identity. It needs
82
+ no npm login, saved publishing token, or passkey prompt for routine releases.
83
+ An npm owner still authenticates when initially configuring the connection.
84
+ The workflow refuses releases from other branches.
85
+
86
+ The repository is private, so npm currently does not generate public provenance
87
+ for this workflow. Trusted publishing still authenticates the release.
package/dist/index.js CHANGED
@@ -1 +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};
1
+ import{defineDisplay as e}from"@directus/extensions-sdk";import{defineComponent as t,reactive as n,computed as i,openBlock as a,createElementBlock as s,Fragment as r,renderList as l,unref as o,toDisplayString as u}from"vue";const c="directus_files_id",d=["id","type","title","modified_on"];function p(e){return("string"==typeof e?e.trim().replace(/^\.+|\.+$/g,""):"")||c}function f(e){return e.type?.startsWith("image/")??!1}function m(e,t){const n=new URL(`assets/${t.id}`,e);return n.searchParams.set("width","160"),n.searchParams.set("height","160"),n.searchParams.set("fit","contain"),n.searchParams.set("format","auto"),t.modified_on&&n.searchParams.set("v",t.modified_on),n.href}function h(e){const t=e.type?.split("/")[1]?.split(/[+.;-]/)[0];return(t||"file").slice(0,4).toUpperCase()}const y={key:0,class:"csi-gallery-thumbnails null"},g=["title"],b=["alt","src","onError"],v={key:1,class:"thumb file"};var x=t({__name:"display",props:{value:{},type:{},filePath:{}},setup(e){const t=e,c=function(e){const t=e.split("/"),n=t.indexOf("admin");return`${t.slice(0,n).join("/")}/`}(window.location.href),d=n(new Set),x=i(()=>function(e,t,n){const i="uuid"===n?[e]:Array.isArray(e)?e:[],a=p(t);return i.flatMap(e=>{const t="uuid"===n?e:function(e,t){return t.split(".").reduce((e,t)=>{if(e&&"object"==typeof e)return e[t]},e)}(e,a);if(!t||"object"!=typeof t)return[];const{id:i,type:s,title:r,modified_on:l}=t;return"string"==typeof i&&i?[{id:i,type:"string"==typeof s?s:null,title:"string"==typeof r?r:null,modified_on:"string"==typeof l?l:null}]:[]})}(t.value,t.filePath,t.type)),w=i(()=>`${x.value.length} ${1===x.value.length?"file":"files"}`);return(e,t)=>0===x.value.length?(a(),s("span",y,"--")):(a(),s("span",{key:1,class:"csi-gallery-thumbnails",title:w.value},[(a(!0),s(r,null,l(x.value,(e,t)=>(a(),s(r,{key:`${e.id}-${t}`},[o(f)(e)&&!d.has(e.id)?(a(),s("img",{key:0,alt:e.title??"",src:o(m)(o(c),e),class:"thumb",loading:"lazy",onError:t=>{return n=e.id,void d.add(n);var n}},null,40,b)):(a(),s("span",v,u(o(h)(e)),1))],64))),128))],8,g))}}),w=[],_=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,i=!0===t.prepend?"prepend":"append",a=!0===t.singleTag,s="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(a){var r=w.indexOf(s);-1===r&&(r=w.push(s)-1,_[r]={}),n=_[r]&&_[r][i]?_[r][i]:_[r][i]=l()}else n=l();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function l(){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 r="prepend"===i?"afterbegin":"beforeend";return s.insertAdjacentElement(r,e),e}}('\n.csi-gallery-thumbnails[data-v-0d10bd92] {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px;\n max-inline-size: 100%;\n min-inline-size: 0;\n vertical-align: middle;\n}\n.thumb[data-v-0d10bd92] {\n flex: none;\n inline-size: var(--csi-gallery-thumbnail-size, 32px);\n block-size: var(--csi-gallery-thumbnail-size, 32px);\n border-radius: var(--theme--border-radius);\n object-fit: contain;\n background-color: var(--theme--background-normal);\n}\n.file[data-v-0d10bd92] {\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.null[data-v-0d10bd92] {\n color: var(--theme--foreground-subdued);\n}\n\n/* Directus 12.3 table rows expose their native spacing as Vue CSS variables:\n 29/43/58px plus a 2px border. Match those values without depending on the\n generated variable name. Leave the native variables intact so switching\n spacing continues to work; only rows containing this display grow. */\n.table-row:has(.csi-gallery-thumbnails) {\n --csi-gallery-thumbnail-size: 32px;\n block-size: auto;\n min-block-size: calc(var(--csi-gallery-thumbnail-size) + 16px);\n}\n.table-row[style*=": 45px;"]:has(.csi-gallery-thumbnails) {\n --csi-gallery-thumbnail-size: 56px;\n}\n.table-row[style*=": 60px;"]:has(.csi-gallery-thumbnails) {\n --csi-gallery-thumbnail-size: 80px;\n}\n',{});var z=e({id:"csi-gallery-thumbnails",name:"Image Thumbnails",icon:"photo_library",description:"Show single images or every gallery image, sized to the table spacing.",component:((e,t)=>{const n=e.__vccOpts||e;for(const[e,i]of t)n[e]=i;return n})(x,[["__scopeId","data-v-0d10bd92"]]),types:["alias","uuid"],localTypes:["files","m2m","o2m","file"],fields:(e,t)=>function(e,t){if("uuid"===t)return[...d];const n=p(e);return d.map(e=>`${n}.${e}`)}(e?.filePath,t.type),options:e=>"uuid"===e.field?.type?[]:[{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:c,font:"monospace"}},schema:{default_value:c}}]});export{z as default};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
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.",
3
+ "version": "0.2.0",
4
+ "description": "Directus display for single images and complete galleries, sized to table spacing.",
5
5
  "keywords": [
6
6
  "directus",
7
7
  "directus-extension",
@@ -11,6 +11,11 @@
11
11
  ],
12
12
  "icon": "photo_library",
13
13
  "license": "UNLICENSED",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/Nuwave-Marketing/csi-big-commerce-catalyst.git",
17
+ "directory": "directus/extensions/csi-gallery-thumbnails"
18
+ },
14
19
  "publishConfig": {
15
20
  "access": "public"
16
21
  },