Skip to content

Commit 9f7c70b

Browse files
authored
Merge pull request #741 from devforth/feature/AdminForth/1955/implement-ability-for-agent-pl
Feature/admin forth/1955/implement ability for agent pl
2 parents 447fe53 + 086240e commit 9f7c70b

10 files changed

Lines changed: 125 additions & 3 deletions

File tree

‎adminforth/design/system.html‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2388,7 +2388,7 @@ <h2 class="ds-board-title"><span>Components</span>Data display</h2>
23882388
<h1 style="font-size: 32px; line-height: 38px; font-weight: 600; letter-spacing: -0.02em">Data display</h1>
23892389
<p class="t-muted">White surfaces on the gray ground, 1px hairlines instead of shadows, muted headers and tabular numbers.</p>
23902390
</div>
2391-
<div style="display: flex; flex-wrap: wrap; gap: 8px"><span class="badge">Table</span><span class="badge">Card</span><span class="badge">VerticalTabs</span><span class="badge">JsonViewer</span><span class="badge">CountryFlag</span><span class="badge">Badge</span></div>
2391+
<div style="display: flex; flex-wrap: wrap; gap: 8px"><span class="badge">Table</span><span class="badge">Card</span><span class="badge">VerticalTabs</span><span class="badge">JsonViewer</span><span class="badge">CountryFlag</span><span class="badge">ZoomableImage</span><span class="badge">Badge</span></div>
23922392
</div>
23932393

23942394
<section class="sec">
@@ -2622,6 +2622,24 @@ <h3 class="t-h3">Storage adapter</h3>
26222622
</div>
26232623
</section>
26242624

2625+
<section class="sec">
2626+
<div class="sec-head"><span class="sec-name">&lt;ZoomableImage&gt;</span><span class="t-sm t-muted">an img which opens over the page; medium-zoom, overlay black/80 in both themes</span></div>
2627+
<div class="grid5">
2628+
<div class="tile">
2629+
<div class="tile-stage">
2630+
<span style="display: block; width: 120px; height: 68px; border-radius: 6px; border: 1px solid #E4E4E7; background: linear-gradient(135deg, #D4D4D8, #A1A1AA); cursor: zoom-in"></span>
2631+
</div>
2632+
<div class="tile-cap"><b>Thumbnail</b><code>cursor zoom-in · size and border by class</code></div>
2633+
</div>
2634+
<div class="tile">
2635+
<div class="tile-stage" style="background: rgb(0 0 0 / 0.8); border-radius: 6px">
2636+
<span style="display: block; width: 180px; height: 102px; border-radius: 6px; background: linear-gradient(135deg, #D4D4D8, #A1A1AA); cursor: zoom-out"></span>
2637+
</div>
2638+
<div class="tile-cap"><b>Opened</b><code>z-50 over the docked chat · click, scroll or Esc closes</code></div>
2639+
</div>
2640+
</div>
2641+
</section>
2642+
26252643
<section class="sec">
26262644
<div class="sec-head"><span class="sec-name">&lt;Badge&gt;</span><span class="t-sm t-muted">20px pill, status tokens: *Soft fill, *Border edge, base text</span></div>
26272645
<div class="grid5">

‎adminforth/index.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,10 @@ class AdminForth implements IAdminForth {
629629
for (const res of this.config.resources) {
630630
this.configValidator.postProcessAfterDiscover(res);
631631
}
632+
// resource plugins are validated by postProcessAfterDiscover, global ones belong to no resource
633+
for (const plugin of this.config.globalPlugins ?? []) {
634+
plugin.validateConfigAfterDiscover?.(this);
635+
}
632636

633637
this.operationalResources = {};
634638
this.config.resources.forEach((resource) => {

‎adminforth/spa/package-lock.json‎

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎adminforth/spa/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"flowbite-datepicker": "^1.2.6",
3131
"javascript-time-ago": "^2.5.11",
3232
"lodash.debounce": "^4.0.8",
33+
"medium-zoom": "^1.1.2",
3334
"pinia": "^4.1.0",
3435
"sanitize-html": "^2.17.4",
3536
"tailwind-merge": "^3.7.0",

‎adminforth/spa/pnpm-lock.yaml‎

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<template>
2+
<img ref="image" v-bind="restAttrs" :src="src" :alt="alt" :class="rootClasses" @click.stop="zoom.open()" />
3+
</template>
4+
5+
<style>
6+
/* medium-zoom appends the overlay and the zoomed image to body: they have to cover the page
7+
and the docked agent chat (z-40); the zoomed image comes later, so it is above the overlay */
8+
.medium-zoom-overlay,
9+
.medium-zoom-image--opened {
10+
@apply z-50;
11+
}
12+
</style>
13+
14+
<script setup lang="ts">
15+
import { computed, onBeforeUnmount, onMounted, useAttrs, useTemplateRef } from 'vue';
16+
import mediumZoom, { type Zoom } from 'medium-zoom';
17+
import { type ClassNameValue } from 'tailwind-merge';
18+
import { mergeClasses } from './classMerge';
19+
20+
defineOptions({ inheritAttrs: false });
21+
22+
withDefaults(defineProps<{
23+
src: string,
24+
alt?: string,
25+
}>(), {
26+
alt: '',
27+
});
28+
29+
// a photo lightbox is dark in both themes, so the overlay is a black tint and not a theme token;
30+
// medium-zoom sets it inline, a class could not override it
31+
const OVERLAY_BACKGROUND = 'rgb(0 0 0 / 0.8)';
32+
const ZOOM_MARGIN = 24;
33+
34+
const attrs = useAttrs();
35+
const restAttrs = computed(() => {
36+
const { class: _class, ...rest } = attrs;
37+
return rest;
38+
});
39+
40+
const rootClasses = computed(() => mergeClasses(
41+
'afcl-zoomable-image cursor-zoom-in',
42+
attrs.class as ClassNameValue,
43+
));
44+
45+
const image = useTemplateRef<HTMLImageElement>('image');
46+
// medium-zoom opens an image from a click listener on document, which a parent stopping the click
47+
// (a table row which opens the record) would never let through. The image opens itself and keeps
48+
// the click from its parents; closing stays with medium-zoom (overlay, zoomed image, Esc, scroll).
49+
let zoom: Zoom;
50+
51+
onMounted(() => {
52+
zoom = mediumZoom(image.value!, { margin: ZOOM_MARGIN, background: OVERLAY_BACKGROUND });
53+
});
54+
55+
onBeforeUnmount(() => zoom.detach());
56+
</script>

‎adminforth/spa/src/afcl/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export { default as Dialog } from './Dialog.vue';
2222
export { default as DialogPanel } from './DialogPanel.vue';
2323
export { default as MixedChart } from './MixedChart.vue';
2424
export { default as CountryFlag } from './CountryFlag.vue';
25+
export { default as ZoomableImage } from './ZoomableImage.vue';
2526
export { default as Badge } from './Badge.vue';
2627
export { default as JsonViewer } from './JsonViewer.vue';
2728
export { default as Toggle } from './Toggle.vue';

‎adminforth/types/Back.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,8 +799,9 @@ export interface IAdminForthPlugin {
799799
/**
800800
* Optional method which will be called after AdminForth discovers all resources and their columns.
801801
* Can be used to validate types of columns, check if some columns are missing, etc.
802+
* `resourceConfig` is the resource of a resource plugin; a global plugin gets no resource.
802803
*/
803-
validateConfigAfterDiscover?(adminforth: IAdminForth, resourceConfig: AdminForthResource): void;
804+
validateConfigAfterDiscover?(adminforth: IAdminForth, resourceConfig?: AdminForthResource): void;
804805

805806
/**
806807
* Here you can register custom endpoints for your plugin.

‎documentation/docs/tutorial/03-Customization/15-afcl/03-dataDisplay.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,28 @@ import { CountryFlag } from '@/afcl'
579579

580580
</AfclPreview>
581581

582+
## Zoomable Image
583+
584+
A Zoomable Image is an image which opens over the whole page on a click, and closes on a click, a scroll or Escape. The dark overlay covers the page and the docked agent chat. The Upload plugin shows its previews with it, the agent chat the images of messages.
585+
586+
<AfclPreview id="zoomable-image">
587+
588+
```js
589+
import { ZoomableImage } from '@/afcl'
590+
```
591+
592+
```html
593+
<ZoomableImage
594+
src="/img/preview_light.png"
595+
alt="AdminForth admin panel"
596+
class="max-w-64 rounded-default border border-lightListBorder dark:border-darkListBorder"
597+
/>
598+
```
599+
600+
</AfclPreview>
601+
602+
The image takes the attributes and classes of an `img`, e.g. `@error` or a size. A click on it does not reach its parents, so it can stay in a clickable block, e.g. a table row which opens the record.
603+
582604
## Badge
583605

584606
A Badge labels a status or a category. Variants are `default`, `success`, `warning`, `danger`, `accent` (the `primary` color of the theme) and `muted`.

‎documentation/docs/tutorial/03-Customization/15-afcl/index.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ Examples are live: each of them renders the code below it with real AFCL compone
2121

2222
- [Buttons and Inputs](./01-buttonsAndInputs.md): [Button](./01-buttonsAndInputs.md#button), [Button Group](./01-buttonsAndInputs.md#button-group), [Link](./01-buttonsAndInputs.md#link), [LinkButton](./01-buttonsAndInputs.md#linkbutton), [Select](./01-buttonsAndInputs.md#select), [Input](./01-buttonsAndInputs.md#input), [Code Input](./01-buttonsAndInputs.md#code-input), [Textarea](./01-buttonsAndInputs.md#textarea), [Checkbox](./01-buttonsAndInputs.md#checkbox), [Toggle](./01-buttonsAndInputs.md#toggle), [Date picker](./01-buttonsAndInputs.md#date-picker), [Dropzone](./01-buttonsAndInputs.md#dropzone)
2323
- [Layout and Overlays](./02-layoutAndOverlays.md): [VerticalTabs](./02-layoutAndOverlays.md#verticaltabs), [Card](./02-layoutAndOverlays.md#card), [Page Header](./02-layoutAndOverlays.md#page-header), [Tooltip](./02-layoutAndOverlays.md#tooltip), [Dialog](./02-layoutAndOverlays.md#dialog-pop-up), [Dialog Panel](./02-layoutAndOverlays.md#dialog-panel), [Dropdown Menu](./02-layoutAndOverlays.md#dropdown-menu), [Modal](./02-layoutAndOverlays.md#modal)
24-
- [Data Display and Loading](./03-dataDisplay.md): [Table](./03-dataDisplay.md#table), [Json Viewer](./03-dataDisplay.md#json-viewer), [Country Flag](./03-dataDisplay.md#country-flag), [Badge](./03-dataDisplay.md#badge), [ProgressBar](./03-dataDisplay.md#progressbar), [Skeleton](./03-dataDisplay.md#skeleton), [Spinner](./03-dataDisplay.md#spinner)
24+
- [Data Display and Loading](./03-dataDisplay.md): [Table](./03-dataDisplay.md#table), [Json Viewer](./03-dataDisplay.md#json-viewer), [Country Flag](./03-dataDisplay.md#country-flag), [Zoomable Image](./03-dataDisplay.md#zoomable-image), [Badge](./03-dataDisplay.md#badge), [ProgressBar](./03-dataDisplay.md#progressbar), [Skeleton](./03-dataDisplay.md#skeleton), [Spinner](./03-dataDisplay.md#spinner)
2525
- [Charts](./04-charts.md): [Bar Chart](./04-charts.md#bar-chart), [Area Chart](./04-charts.md#area-chart), [Pie Chart](./04-charts.md#pie-chart), [Treemap Chart](./04-charts.md#treemap-chart), [Mixed Chart](./04-charts.md#mixed-chart)

0 commit comments

Comments
 (0)