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.
- package/README.md +51 -0
- package/dist/index.js +1 -0
- 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
|
+
}
|