plugins: added entryIcon frontend-event

Massimo Melina committed May 20, 2023 at 15:15 UTC 0b436c63505634bac1c49b54808b598280e245af
4 files changed +19 -6
dev-plugins.md
+5
@@ -196,6 +196,10 @@ This is a list of available frontend-events, with respective object parameter an
196 - you receive each entry of the list, and optionally produce HTML code that will be added after the name of the entry.
197 - parameter `{ entry: Entry }` (refer above for Entry object)
198 - output `Html`
199 +- `entryIcon`
200 + - you receive an entry of the list and optionally produce HTML that will be used in place of the standard icon.
201 + - parameter `{ entry: Entry }` (refer above for Entry object)
202 + - output `Html`
203 - `beforeHeader` & `afterHeader`
204 - use this to produce content that should go right before/after the `header` part
205 - output `Html`
@@ -253,6 +257,7 @@ HFS will scan through them in inverted alphabetical order searching for a compat
257 - HFS.apiCall, reloadList, logout, h, React, state, t, _, dialogLib
258 - second parameter of onEvent is now deprecated
259 - renamed: additionalEntryProps > additionalEntryDetails & entry-props > entry-details
260 + - entryIcon event
261 - 8 (v0.43.0)
262 - entry.name & .uri
263 - tools.dialogLib
frontend/src/BrowseFiles.ts
+5 -1
@@ -235,7 +235,11 @@ const Entry = memo(({ entry, midnight, separator }: EntryProps) => {
235 })
236
237 export function getEntryIcon(entry: DirEntry) {
238 - return hIcon(entry.isFolder ? 'folder' : 'file')
238 + return h(CustomCode, {
239 + name: 'entryIcon',
240 + props: { entry },
241 + ifEmpty: () => hIcon(entry.isFolder ? 'folder' : 'file')
242 + })
243 }
244
245 const EntryDetails = memo(({ entry, midnight }: { entry: DirEntry, midnight: Date }) => {
frontend/src/components.ts
+6 -4
@@ -4,6 +4,7 @@ import { getHFS, hfsEvent, hIcon } from './misc'
4 import {
5 ChangeEvent,
6 createElement as h,
7 + FC,
8 Fragment,
9 HTMLAttributes,
10 InputHTMLAttributes,
@@ -59,15 +60,15 @@ export function Select({ onChange, value, options, ...props }:SelectProps) {
60 }, options.map(({ value, label }) => h('option', { key:value, value }, label)))
61 }
62
62 -export function Html({ code, ...rest }:{ code:string } & HTMLAttributes<any>) {
63 +export function Html({ code, ...rest }: { code:string } & HTMLAttributes<any>) {
64 return !code ? null : h('span', { ...rest, ref(x) {
65 if (x)
66 x.append(document.createRange().createContextualFragment(code))
67 } })
68 }
69
69 -export function CustomCode({ name, props }: any) {
70 - return h(Fragment, {}, useMemo(() => {
70 +export function CustomCode({ name, props, ifEmpty }: { name: string, props?: any, ifEmpty?: FC }) {
71 + const children = useMemo(() => {
72 const ret = hfsEvent(name, props)
73 .filter(x => x === 0 || x)
74 .map((x, key) => isValidElement(x) ? h(Fragment, { key }, x)
@@ -77,5 +78,6 @@ export function CustomCode({ name, props }: any) {
78 if (html?.trim?.())
79 ret.push(h(Html, { key: 'x', code: html }))
80 return ret
80 - }, props ? Object.values(props) : []))
81 + }, props ? Object.values(props) : [])
82 + return children.length || !ifEmpty ? h(Fragment, {}, children) : h(ifEmpty)
83 }
\ No newline at end of file
frontend/src/index.scss
+3 -1
@@ -68,12 +68,13 @@ input[type=checkbox] {
68 label input[type=checkbox] {
69 margin-right: .8em;
70 }
71 -select { text-align: center; } /* it is surely cooler on the options dialog */
71 +select { text-align: center; } // it is surely cooler on the options dialog
72
73 .hidden { display: none !important }
74
75 .icon {
76 font-size: 1.2em;
77 + height: 1.18em; min-width: 1.4em; // give similar size to <img> icons
78 }
79 .emoji-icon {
80 display: inline-block;
@@ -247,6 +248,7 @@ ul.dir {
248 }
249 & .icon {
250 margin-right: .3em;
251 + vertical-align: text-bottom; // give similar aligning to <img> icons
252 }
253 &:hover {
254 text-decoration: underline;