@opengis/fastify-table 1.4.14 → 1.4.16

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/index.js CHANGED
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url';
6
6
  import config from './config.js';
7
7
 
8
8
  // helpers
9
- import helperPlugin from './server/helpers/index.js';
9
+ // import helperPlugin from './server/helpers/index.js';
10
10
 
11
11
  // plugins
12
12
  import cronPlugin from './server/plugins/cron/index.js';
@@ -89,7 +89,7 @@ async function plugin(fastify, opt) {
89
89
  policyPlugin(fastify);
90
90
  metricPlugin(fastify);
91
91
  redisPlugin(fastify);
92
- helperPlugin(fastify);
92
+ // helperPlugin(fastify);
93
93
  await pgPlugin(fastify, opt);
94
94
  tablePlugin(fastify, opt);
95
95
  crudPlugin(fastify, opt);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.4.14",
3
+ "version": "1.4.16",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
6
  "keywords": [
@@ -0,0 +1,14 @@
1
+ import getSelect from '../../plugins/table/funcs/getSelect.js';
2
+
3
+ export default async function badge(id, options) {
4
+ if (!id?.toString) return '-';
5
+ const data = options.hash?.data;
6
+ if (!data) return id;
7
+ const classifier = await getSelect(data);
8
+ if (!classifier?.arr) return id;
9
+
10
+ const item = classifier?.arr.find(el => el.id?.toString?.() === id.toString());
11
+ if (!item) return id;
12
+ return `<span style='color:${item.color || '#14b8a6'};border-color:${item.color || '#14b8a6'}; overflow:hidden;
13
+ text-overflow:ellipsis; white-space:nowrap;' class="block w-fit py-1.5 px-3 rounded-full text-xs font-medium border border-teal-500 text-teal-500 max-w-[220px] text-nowrap ">${item.text}</span>`;
14
+ }
@@ -0,0 +1,13 @@
1
+
2
+ import buttonPreview from '../utils/buttonPreview.js';
3
+ import buttonDownload from '../utils/buttonDownload.js';
4
+
5
+ export default function buttonFilePreviewHelper(data, options = {}) {
6
+ const { hash } = options;
7
+ if (data && typeof data !== 'string') return 'wrong input data type';
8
+ if (!data) return '';
9
+
10
+ const preview = buttonPreview(data);
11
+ const download = buttonDownload(data);
12
+ return `<div class='flex gap-x-2'>${hash?.action === 'download' ? '' : preview}${hash?.action === 'preview' ? '' : download}</div>`;
13
+ }
@@ -0,0 +1,21 @@
1
+ import buttonAdd from "../utils/buttonAdd.js";
2
+ import buttonDel from "../utils/buttonDel.js";
3
+ import buttonEdit from "../utils/buttonEdit.js";
4
+ import button from "../utils/button.js";
5
+ export default function buttonHelper(data, opt) {
6
+ const { hash } = opt;
7
+
8
+ // console.log(params)
9
+
10
+ if (!hash.token) return "token empty";
11
+ if (hash.add) {
12
+ return buttonAdd(hash.token, hash.title);
13
+ }
14
+ if (hash.del) {
15
+ return buttonDel(hash.token, hash.title, hash.icon);
16
+ }
17
+ if (hash.edit) {
18
+ return buttonEdit(hash.token, hash.title, hash.icon);
19
+ }
20
+ return button(hash.token, hash.title);
21
+ }
@@ -0,0 +1,18 @@
1
+ import setToken from '../../plugins/crud/funcs/setToken.js';
2
+
3
+ export default function tokenFunc(params) {
4
+ const { data, hash } = params;
5
+
6
+ if (!data?.root?.user?.uid && !hash.uid) return '-';
7
+ if (!hash || typeof hash !== 'object') return '-';
8
+
9
+ // const id = hash?.edit ? hash?.id : data?.root?.id;
10
+ // console.log(hash)
11
+ const [token] = setToken({
12
+ ids: [JSON.stringify(hash)],
13
+
14
+ uid: data?.root?.user?.uid || hash.uid,
15
+ array: 1,
16
+ });
17
+ return token;
18
+ }
@@ -1,8 +1,8 @@
1
- import { logger } from '../../utils.js';
2
-
3
1
  import handlebarsSync from 'handlebars';
4
2
  import promisedHandlebars from 'promised-handlebars';
5
3
 
4
+ import logger from '../plugins/logger/getLogger.js';
5
+
6
6
  const handlebars = promisedHandlebars(handlebarsSync);
7
7
 
8
8
  // funcs
@@ -26,17 +26,27 @@ import formatNum from './format/formatNum.js';
26
26
  import formatNumber from './format/formatNumber.js';
27
27
  import formatRelative from './format/formatRelative.js';
28
28
  import formatUnit from './format/formatUnit.js';
29
- import num_format from './format/num_format.js';
29
+ import numFormat from './format/num_format.js';
30
30
  import set from './format/set.js';
31
31
 
32
32
  // string
33
- import str_replace from './string/str_replace.js';
33
+ import strReplace from './string/str_replace.js';
34
34
  import coalesce from './string/coalesce.js';
35
35
  import concat from './string/concat.js';
36
36
  import split from './string/split.js';
37
37
  import translit from './string/translit.js';
38
38
  import substr from './string/substr.js';
39
39
 
40
+ // from npm/admin
41
+ import token from './core/token.js';
42
+ import descriptionList from './list/descriptionList.js';
43
+ import tableList from './list/tableList.js';
44
+ import buttonHelper from './core/buttonHelper.js';
45
+ import buttonFilePreview from './core/buttonFilePreview.js';
46
+ import badge from './core/badge.js';
47
+ import mdToHTML from './utils/mdToHTML.js';
48
+ import paddingNumber from './utils/paddingNumber.js';
49
+
40
50
  function getKeysRecursive(obj, prefix = '') {
41
51
  if (!obj || typeof obj !== 'object' || obj?.constructor?.name !== 'Object') return [];
42
52
  const obj1 = Array.isArray(obj) ? obj[0] : obj;
@@ -70,11 +80,11 @@ handlebars.registerHelper('formatNum', formatNum);
70
80
  handlebars.registerHelper('formatNumber', formatNumber);
71
81
  handlebars.registerHelper('formatRelative', formatRelative);
72
82
  handlebars.registerHelper('formatUnit', formatUnit);
73
- handlebars.registerHelper('num_format', num_format);
83
+ handlebars.registerHelper('num_format', numFormat);
74
84
  handlebars.registerHelper('set', set);
75
85
 
76
86
  // string
77
- handlebars.registerHelper('str_replace', str_replace);
87
+ handlebars.registerHelper('str_replace', strReplace);
78
88
  handlebars.registerHelper('coalesce', coalesce);
79
89
  handlebars.registerHelper('concat', concat);
80
90
  handlebars.registerHelper('split', split);
@@ -98,11 +108,29 @@ handlebars.registerHelper('qrcode', qrcode);
98
108
  // Підтримка старого коду
99
109
  handlebars.registerHelper('qrcode-generator-base64', qrcode);
100
110
 
101
- export default function helpers(fastify) {
111
+ // from npm/admin
112
+ handlebars.registerHelper('token', token);
113
+ handlebars.registerHelper('mdToHTML', mdToHTML);
114
+ handlebars.registerHelper('descriptionList', descriptionList);
115
+ handlebars.registerHelper('tableList', tableList);
116
+ handlebars.registerHelper('button', buttonHelper);
117
+ handlebars.registerHelper('buttonFilePreview', buttonFilePreview);
118
+ handlebarsSync.registerHelper('buttonFilePreview', buttonFilePreview);
119
+ handlebars.registerHelper('select', select);
120
+ handlebars.registerHelper('badge', badge);
121
+ handlebars.registerHelper('contentList', contentList);
122
+ handlebarsSync.registerHelper('ifCond', ifCond);
123
+ handlebarsSync.registerHelper('button', buttonHelper);
124
+ handlebars.registerHelper('ifCond', ifCond);
125
+ handlebars.registerHelper('empty', () => { });
126
+ handlebarsSync.registerHelper('empty', () => { });
127
+ handlebars.registerHelper('coalesce', coalesce);
128
+ handlebarsSync.registerHelper('coalesce', coalesce);
102
129
 
103
- }
130
+ handlebarsSync.registerHelper('paddingNumber', paddingNumber);
131
+ handlebars.registerHelper('paddingNumber', paddingNumber);
104
132
 
105
133
  export {
106
134
  handlebars,
107
135
  handlebarsSync,
108
- }
136
+ };
@@ -0,0 +1,21 @@
1
+ import buttonAdd from "../utils/buttonAdd.js";
2
+ import buttonDel from "../utils/buttonDel.js";
3
+ import buttonEdit from "../utils/buttonEdit.js";
4
+ import button from "../utils/button.js";
5
+ export default function buttonHelper(data, opt) {
6
+ const { hash } = opt;
7
+
8
+ // console.log(params)
9
+
10
+ if (!hash.token) return "token empty";
11
+ if (hash.add) {
12
+ return buttonAdd(hash.token, hash.title);
13
+ }
14
+ if (hash.del) {
15
+ return buttonDel(hash.token, hash.title);
16
+ }
17
+ if (hash.edit) {
18
+ return buttonEdit(hash.token, hash.title);
19
+ }
20
+ return button(hash.token, hash.title);
21
+ }
@@ -0,0 +1,44 @@
1
+ import { handlebars } from '../index.js';
2
+
3
+ async function format(d, key, data) {
4
+ if (!key?.includes) return '';
5
+ if (d === true) return 'Так';
6
+ if (d === false) return 'Ні';
7
+
8
+ if (key.includes('{{')) {
9
+ return await handlebars.compile(key)(data);
10
+ }
11
+
12
+ return d;
13
+ }
14
+ export default async function descriptionList(data, opt) {
15
+ const { hash } = opt;
16
+
17
+ // no data
18
+ if (hash.nodata && !data) {
19
+ const noDataText = typeof hash.nodata === 'string' ? hash.nodata : '<div class="bg-gray-200 text-center p-6 rounded-xl"><h3 class="text-lg font-semibold">Інформація відсутня</h3></div>';
20
+ return noDataText;
21
+ }
22
+ if (!hash.columns) return 'columns empty';
23
+ const keys = hash.columns.split(hash.divider || ',').map(el => (hash.comma ? el.trim().replace(new RegExp(hash.comma || '#', 'g'), ',') : el.trim()));
24
+
25
+ const result = [];
26
+
27
+ for (let i = 0; i < keys.length; i += 2) {
28
+ const name = keys[i];
29
+ const nameHBS = name.includes('{{') ? await handlebars.compile(name)({ ...data, hash }) : false;
30
+
31
+ if (!nameHBS && name.includes('{{')) continue;
32
+
33
+ const key = keys[i + 1];
34
+
35
+ const d1 = await format(data[key], key, data) || '-';
36
+
37
+ result.push(`<div class="grid grid-cols-1 gap-1 py-3 sm:grid-cols-3 sm:gap-4 even:bg-gray-50 text-[12px]">
38
+ <dt class="text-gray-900">${nameHBS || name}</dt>
39
+ <dd class="text-gray-700 sm:col-span-2">${d1}</dd>
40
+ </div>
41
+ `);
42
+ }
43
+ return `<dl class=" divide-y divide-gray-100 py-[5px] w-full">${result.join('')}</dl>`;
44
+ }
@@ -0,0 +1,85 @@
1
+ import setToken from '../../plugins/crud/funcs/setToken.js';
2
+
3
+ import { handlebars } from '../index.js';
4
+
5
+ import buttonEdit from './utils/buttonEdit.js';
6
+ import buttonDel from './utils/buttonDel.js';
7
+
8
+ function format(d, key, data, hash) {
9
+ if (!key?.includes) return '';
10
+ if (d === true) return 'Так';
11
+ if (d === false) return 'Ні';
12
+ if (key === 'actions') {
13
+ return `<div class="flex items-center gap-2">${(hash.form ? buttonEdit(d, 'Редагувати') : '') + buttonDel(d)}</div>`;
14
+ }
15
+ if (key.startsWith('{{')) {
16
+ return handlebars.compile(key)(data);
17
+ } if (key.startsWith('{{') && key.includes(' ') && !(key.match(/\{\{([^\s]+)/)?.[1] in handlebars.helpers)) {
18
+ return null;
19
+ }
20
+ if (!d) return '-';
21
+ return d;
22
+ }
23
+ export default async function tableList(data, opt) {
24
+ const { hash } = opt;
25
+ // no data
26
+ // const time = Date.now();
27
+ if (hash.nodata && !data?.length) {
28
+ const noDataText = typeof hash.nodata === 'string' ? hash.nodata : '<div class="bg-gray-200 text-center p-6 rounded-xl"><h3 class="text-lg font-semibold">Інформація відсутня</h3></div>';
29
+ return noDataText;
30
+ }
31
+ if (!hash.columns) return 'columns empty';
32
+ const keys = hash.columns.split(hash.divider || ',').map(el => (hash.comma ? el.trim().replace(new RegExp(hash.comma, 'g'), ',') : el.trim())).concat(hash.uid && hash.table && hash.id && !hash.noactions ? ['Дії', 'actions'] : []);
33
+
34
+ const result = [];
35
+ result.push('<thead class="text-left font-medium text-gray-700"> <tr>');
36
+
37
+ // thead
38
+ const skip = {};
39
+ for (let i = 0; i < keys.length; i += 2) {
40
+ const name = keys[i];
41
+
42
+ // check hbs
43
+ if (name.includes('{{')) {
44
+ console.log(hash);
45
+ }
46
+ const nameHBS = name.includes('{{') ? await handlebars.compile(name)({ ...data, hash }) : false;
47
+ // console.log(name, data, nameHBS)
48
+ skip[name] = name.includes('{{') && !nameHBS;
49
+ if (skip[name]) continue;
50
+
51
+ const isActionsColumn = hash.noactions && i === keys.length - 2;
52
+ result.push(`<th class="py-2 min-w-[200px] ${isActionsColumn ? 'last:min-w-[60px] last:max-w-[60px] last:bg-white last:sticky last:right-0' : ''}">
53
+ ${nameHBS || name}
54
+ </th>`);
55
+ }
56
+ result.push('</tr></thead><tbody class="divide-y divide-gray-200">');
57
+
58
+ // body
59
+ for (let k = 0; k < data.length; k += 1) {
60
+ const row = data[k];
61
+ result.push('<tr class="bg-white odd:bg-gray-50 ">');
62
+ const obj = { form: hash.form, table: hash.table, id: row[hash.id] };
63
+ const token = hash.table ? setToken({ ids: [JSON.stringify(obj)], uid: hash.uid, array: 1 })[0] : null;
64
+ for (let i = 0; i < keys.length; i += 2) {
65
+ const name = keys[i];
66
+ const key = keys[i + 1];
67
+ if (!key) continue;
68
+ if (skip[name]) continue;
69
+
70
+ const tokenData = key === 'actions' ? token : null;
71
+ const d1 = key.includes('{{') ? await handlebars.compile(key)({ ...row, token, hash }) || '-' : null;
72
+ const isActionsColumn = hash.noactions && i === keys.length - 2;
73
+ result.push(`<td class="py-2 pr-5 ${isActionsColumn ? 'last:sticky last:right-0' : ''}">
74
+ ${d1 || format(tokenData || row[key], key, row, hash)}
75
+ </td>`);
76
+ }
77
+ // action token
78
+
79
+ result.push('</tr>');
80
+ }
81
+ result.push('</tbody>');
82
+
83
+ // console.log(Date.now() - time)
84
+ return `<table class="min-w-full relative divide-y-2 divide-gray-200 bg-white min-w-full overflow-auto divide-y-2 divide-gray-200 bg-white text-[12px] text-gray-600">${result.join('')}</table>`;
85
+ }
@@ -0,0 +1,6 @@
1
+
2
+
3
+ export default function button(token, title) {
4
+ return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
5
+ class="inline-flex items-center px-2 py-1 text-sm font-medium text-white duration-300 bg-blue-600 border border-transparent rounded-lg gap-x-2 hover:bg-blue-700 hover:text-white">${title || 'Додати'}</button>`;
6
+ }
@@ -0,0 +1,13 @@
1
+ // export default function button(token, title) {
2
+ // return `<button onclick="window.v3plugin.$api({ api: '/api/table/${token}', method:'delete',confirm: { title:'Підтвердити операцію', text: 'Ви впевнені що хочете вилучити запис?', cancel: 'Скасувати', confirm : 'Виконати'} })"
3
+ // class="inline-flex items-center px-2 py-1 text-sm font-medium text-white duration-300 bg-red-600 border border-transparent rounded-lg gap-x-2 hover:bg-red-700 hover:text-white">${title || 'Вилучити'}</button>`;
4
+ // }
5
+
6
+
7
+ const newColor = 'red'
8
+ export default function button(token, title) {
9
+ return `<button onclick="window.v3plugin.$api({ api: '/api/table/${token}', method:'delete',confirm: { title:'Підтвердити операцію', text: 'Ви впевнені що хочете вилучити запис?', cancel: 'Скасувати', confirm : 'Виконати'} })"
10
+ class="group px-2 py-1 inline-flex border-solid justify-center items-center gap-2 rounded-md font-semibold focus:outline-none text-sm transition-all border border-transparent hover:text-white ring-offset-white bg-${newColor}-100 text-${newColor}-100 hover:bg-${newColor}-500 focus:ring-${newColor}-500">
11
+ <svg class="group-hover:fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="13" height="13" fill="#ef4444"><path d="M135.2 17.7L128 32 32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0-7.2-14.3C307.4 6.8 296.3 0 284.2 0L163.8 0c-12.1 0-23.2 6.8-28.6 17.7zM416 128L32 128 53.2 467c1.6 25.3 22.6 45 47.9 45l245.8 0c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>
12
+ </button>`;
13
+ }
@@ -0,0 +1,15 @@
1
+
2
+
3
+ // export default function button(token, title) {
4
+ // return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
5
+ // class="inline-flex items-center px-2 py-1 text-sm font-medium text-white duration-300 bg-blue-600 border border-transparent rounded-lg gap-x-2 hover:bg-blue-700 hover:text-white">${title || 'Редагувати'}</button>`;
6
+ // }
7
+
8
+
9
+ const newColor = 'blue'
10
+ export default function button(token, title) {
11
+ return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
12
+ class="group px-2 py-1 inline-flex border-solid justify-center items-center gap-2 rounded-md font-semibold focus:outline-none text-sm transition-all border border-transparent hover:text-white ring-offset-white bg-${newColor}-100 text-${newColor}-100 hover:bg-${newColor}-500 focus:ring-${newColor}-500">
13
+ <svg class="group-hover:fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="13" height="13" fill="#3b82f6"><path d="M471.6 21.7c-21.9-21.9-57.3-21.9-79.2 0L362.3 51.7l97.9 97.9 30.1-30.1c21.9-21.9 21.9-57.3 0-79.2L471.6 21.7zm-299.2 220c-6.1 6.1-10.8 13.6-13.5 21.9l-29.6 88.8c-2.9 8.6-.6 18.1 5.8 24.6s15.9 8.7 24.6 5.8l88.8-29.6c8.2-2.7 15.7-7.4 21.9-13.5L437.7 172.3 339.7 74.3 172.4 241.7zM96 64C43 64 0 107 0 160L0 416c0 53 43 96 96 96l256 0c53 0 96-43 96-96l0-96c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 96c0 17.7-14.3 32-32 32L96 448c-17.7 0-32-14.3-32-32l0-256c0-17.7 14.3-32 32-32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L96 64z"/></svg>
14
+ </button>`;
15
+ }
@@ -0,0 +1,6 @@
1
+
2
+
3
+ export default function button(token, title) {
4
+ return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
5
+ class="inline-flex items-center px-2 py-1 text-sm font-medium text-white duration-300 bg-blue-600 border border-transparent rounded-lg gap-x-2 hover:bg-blue-700 hover:text-white">${title || 'Редагувати'}</button>`;
6
+ }
@@ -0,0 +1,7 @@
1
+
2
+
3
+ const newColor = 'blue'
4
+ export default function button(token, title) {
5
+ return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
6
+ class="px-2 py-1 inline-flex border-solid justify-center items-center gap-2 rounded-md font-semibold focus:outline-none text-sm transition-all border border-transparent hover:text-white ring-offset-white bg-${newColor}-100 text-${newColor}-500 hover:bg-${newColor}-500 focus:ring-${newColor}-500">${title || 'Додати'}</button>`;
7
+ }
@@ -0,0 +1,26 @@
1
+ const newColor = 'red';
2
+
3
+ export default function button(token, title, icon) {
4
+ const apiCall = `window.v3plugin.$api({
5
+ api: '/api/table/${token}',
6
+ method: 'delete',
7
+ confirm: {
8
+ title: 'Підтвердити операцію',
9
+ text: 'Ви впевнені що хочете вилучити запис?',
10
+ cancel: 'Скасувати',
11
+ confirm: 'Виконати'
12
+ }
13
+ })`;
14
+
15
+ const buttonClass = icon
16
+ ? `size-8 inline-flex justify-center items-center gap-x-2 rounded-e-lg border border-stone-200 bg-${newColor}-100 text-stone-800 shadow-sm hover:bg-${newColor}-200 disabled:opacity-50 disabled:pointer-events-none focus:outline-none focus:bg-stone-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-700 dark:focus:bg-neutral-700`
17
+ : `px-2 py-1 inline-flex border-solid justify-center items-center gap-2 rounded-md font-semibold focus:outline-none text-sm transition-all border border-transparent hover:text-white ring-offset-white bg-${newColor}-100 text-${newColor}-500 hover:bg-${newColor}-500 focus:ring-${newColor}-500`;
18
+
19
+ const buttonContent = icon
20
+ ? `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="${newColor}" class="size-3.5">
21
+ <path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"/>
22
+ </svg>`
23
+ : `${title || 'Вилучити'}`;
24
+
25
+ return `<button onclick="${apiCall}" class="${buttonClass}">${buttonContent}</button>`;
26
+ }
@@ -0,0 +1,3 @@
1
+ export default function buttonDownload(filepath) {
2
+ return `<a download=1 class="flex items-center gap-x-2 border py-2 px-3 shadow rounded-xl cursor-pointer w-[42px] y-[34px]" href="${filepath}" target="_blank"><img src="https://cdn.softpro.ua/assets/file-up.svg" alt="generate"></a>`;
3
+ }
@@ -0,0 +1,19 @@
1
+
2
+ const newColor = 'blue';
3
+ export default function button(token, title, icon) {
4
+ const formCall = `window.v3plugin.$form({ token: '${token}' })`;
5
+
6
+ const buttonClass = icon
7
+ ? `size-8 inline-flex justify-center items-center gap-x-2 font-medium rounded-s-lg border border-stone-200 bg-${newColor}-100 text-stone-800 shadow-sm hover:bg-${newColor}-200 disabled:opacity-50 disabled:pointer-events-none focus:outline-none focus:bg-${newColor}-50 dark:bg-neutral-800 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-700 dark:focus:bg-neutral-700 `
8
+ : `px-2 py-1 inline-flex border-solid justify-center items-center gap-2 rounded-md font-semibold focus:outline-none text-sm transition-all border border-transparent hover:text-white ring-offset-white bg-${newColor}-100 text-${newColor}-500 hover:bg-${newColor}-500 focus:ring-${newColor}-500`;
9
+
10
+ const buttonContent = icon
11
+ ? `<svg class="shrink-0 size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="${newColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
12
+ <path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"></path>
13
+ <path d="m15 5 4 4"></path>
14
+ </svg>`
15
+ : `${title || 'Редагувати'}`;
16
+
17
+ return `<button onclick="${formCall}" class="${buttonClass}">${buttonContent}</button>`;
18
+
19
+ }
@@ -0,0 +1,3 @@
1
+ export default function buttonPreview(filepath) {
2
+ return `<a class="flex items-center gap-x-2 border py-2 px-3 shadow rounded-xl cursor-pointer w-[42px] y-[34px]" href="${filepath}" target="_blank"><img src="https://cdn.softpro.ua/assets/eye.svg" alt="eye"></a>`;
3
+ }
@@ -0,0 +1,17 @@
1
+ import md from 'markdown-it';
2
+
3
+ const md1 = md({ html: true });
4
+
5
+ /**
6
+ * Перетворення з файла readme.md до формату HTML.
7
+ * Потрабно вставити в хелпер шлях до файла або текст readme.md і за допомогою бібліотеки markdown-it перетвориться в HTML.
8
+
9
+ * @returns {String} Returns HTML
10
+ */
11
+ export default function mdToHTML(data, options) {
12
+ // auto detect HTML or MD
13
+ // const result = md().render(data);
14
+ if (!data) return 'empty data';
15
+ const result = md1.render(data);
16
+ return result;
17
+ };
@@ -0,0 +1,4 @@
1
+ export default function (num) {
2
+ const padding = arguments.length === 3 ? arguments[1] : 6;
3
+ return num.toLocaleString('en', { minimumIntegerDigits: padding, useGrouping: false })
4
+ }
@@ -27,7 +27,7 @@ export default async function deleteCrud(req, reply) {
27
27
  return reply.status(400).send('invalid token');
28
28
  }
29
29
 
30
- if (!actions.includes('del') && !config?.local) {
30
+ if (!actions.includes('del') && !config?.local && !tokenData) {
31
31
  return reply.status(403).send('access restricted: actions');
32
32
  }
33
33
 
@@ -45,7 +45,7 @@ export default async function update(req, reply) {
45
45
  }
46
46
 
47
47
  if (!id && tokenData?.table) {
48
- return insert(req);
48
+ return insert(req, reply);
49
49
  }
50
50
 
51
51
  if (!id) {