@skalfa/skalfa-app 1.0.2 → 1.0.5

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 (99) hide show
  1. package/.env.example +8 -16
  2. package/app/auth/edit/page.tsx +1 -1
  3. package/app/auth/login/page.tsx +1 -1
  4. package/app/auth/me/page.tsx +1 -1
  5. package/app/auth/register/page.tsx +1 -1
  6. package/app/auth/verify/page.tsx +1 -1
  7. package/app/dashboard/layout.tsx +2 -2
  8. package/app/dashboard/page.tsx +1 -1
  9. package/app/index.ts +1 -0
  10. package/app/layout.tsx +2 -4
  11. package/app/page.tsx +2 -2
  12. package/bun.lock +39 -24
  13. package/components/index.ts +1 -3
  14. package/package.json +8 -7
  15. package/styles/components.css +1392 -0
  16. package/styles/globals.css +40 -175
  17. package/styles/utilities.css +37 -0
  18. package/tsconfig.json +4 -2
  19. package/utils/commands/skalfa.ts +3 -0
  20. package/blueprints/starter.blueprint.json +0 -103
  21. package/components/base.components/accordion/Accordion.component.tsx +0 -82
  22. package/components/base.components/breadcrumb/Breadcrumb.component.tsx +0 -80
  23. package/components/base.components/button/Button.component.tsx +0 -91
  24. package/components/base.components/button/IconButton.component.tsx +0 -88
  25. package/components/base.components/button/button.decorate.ts +0 -82
  26. package/components/base.components/card/AlertCard.component.tsx +0 -69
  27. package/components/base.components/card/Card.component.tsx +0 -25
  28. package/components/base.components/card/DashboardCard.component.tsx +0 -44
  29. package/components/base.components/card/GalleryCard.component.tsx +0 -50
  30. package/components/base.components/card/ProductCard.component.tsx +0 -65
  31. package/components/base.components/card/ProfileCard.component.tsx +0 -71
  32. package/components/base.components/carousel/Carousel.component.tsx +0 -113
  33. package/components/base.components/chip/Chip.component.tsx +0 -39
  34. package/components/base.components/document/DocumentViewer.component.tsx +0 -164
  35. package/components/base.components/document/ExportExcel.component.tsx +0 -340
  36. package/components/base.components/document/ImportExcel.component.tsx +0 -315
  37. package/components/base.components/document/PrintTable.component.tsx +0 -204
  38. package/components/base.components/document/RenderPDF.component.tsx +0 -416
  39. package/components/base.components/index.ts +0 -85
  40. package/components/base.components/input/Checkbox.component.tsx +0 -109
  41. package/components/base.components/input/Input.component.tsx +0 -332
  42. package/components/base.components/input/InputCheckbox.component.tsx +0 -174
  43. package/components/base.components/input/InputCurrency.component.tsx +0 -163
  44. package/components/base.components/input/InputDate.component.tsx +0 -352
  45. package/components/base.components/input/InputDatetime.component.tsx +0 -260
  46. package/components/base.components/input/InputDocument.component.tsx +0 -352
  47. package/components/base.components/input/InputImage.component.tsx +0 -533
  48. package/components/base.components/input/InputMap.component.tsx +0 -318
  49. package/components/base.components/input/InputNumber.component.tsx +0 -192
  50. package/components/base.components/input/InputOtp.component.tsx +0 -169
  51. package/components/base.components/input/InputPassword.component.tsx +0 -236
  52. package/components/base.components/input/InputRadio.component.tsx +0 -175
  53. package/components/base.components/input/InputTime.component.tsx +0 -276
  54. package/components/base.components/input/InputValues.component.tsx +0 -68
  55. package/components/base.components/input/Radio.component.tsx +0 -102
  56. package/components/base.components/input/Select.component.tsx +0 -541
  57. package/components/base.components/modal/BottomSheet.component.tsx +0 -246
  58. package/components/base.components/modal/FloatingPage.component.tsx +0 -104
  59. package/components/base.components/modal/Modal.component.tsx +0 -96
  60. package/components/base.components/modal/ModalConfirm.component.tsx +0 -218
  61. package/components/base.components/modal/Toast.component.tsx +0 -126
  62. package/components/base.components/nav/Bottombar.component.tsx +0 -116
  63. package/components/base.components/nav/Footer.component.tsx +0 -144
  64. package/components/base.components/nav/Headbar.component.tsx +0 -104
  65. package/components/base.components/nav/Navbar.component.tsx +0 -100
  66. package/components/base.components/nav/Sidebar.component.tsx +0 -301
  67. package/components/base.components/nav/Tabbar.component.tsx +0 -60
  68. package/components/base.components/nav/Wizard.component.tsx +0 -73
  69. package/components/base.components/supervision/FormSupervision.component.tsx +0 -434
  70. package/components/base.components/supervision/TableSupervision.component.tsx +0 -697
  71. package/components/base.components/table/ControlBar.component.tsx +0 -497
  72. package/components/base.components/table/FilterComponent.tsx +0 -518
  73. package/components/base.components/table/Pagination.component.tsx +0 -159
  74. package/components/base.components/table/Table.component.tsx +0 -469
  75. package/components/base.components/typography/TypographyArticle.component.tsx +0 -26
  76. package/components/base.components/typography/TypographyColumn.component.tsx +0 -20
  77. package/components/base.components/typography/TypographyContent.component.tsx +0 -20
  78. package/components/base.components/typography/TypographyTips.component.tsx +0 -20
  79. package/components/base.components/wrap/Draggable.component.tsx +0 -303
  80. package/components/base.components/wrap/IDBProvider.tsx +0 -12
  81. package/components/base.components/wrap/Image.component.tsx +0 -10
  82. package/components/base.components/wrap/OutsideClick.component.tsx +0 -48
  83. package/components/base.components/wrap/ScrollContainer.component.tsx +0 -104
  84. package/components/base.components/wrap/ShortcutProvider.tsx +0 -57
  85. package/components/base.components/wrap/Swipe.component.tsx +0 -93
  86. package/components/construct.components/example.tsx +0 -1
  87. package/components/construct.components/index.ts +0 -5
  88. package/components/structure.components/example.tsx +0 -1
  89. package/components/structure.components/index.ts +0 -5
  90. package/langs/index.ts +0 -1
  91. package/langs/validation.langs.ts +0 -17
  92. package/schema/idb/app.schema.ts +0 -9
  93. package/schema/index.ts +0 -5
  94. package/utils/commands/barrels.ts +0 -28
  95. package/utils/commands/blueprint.ts +0 -421
  96. package/utils/commands/light.ts +0 -21
  97. package/utils/commands/logger.ts +0 -42
  98. package/utils/commands/stubs/table-blueprint.stub +0 -13
  99. package/utils/commands/use-pdf.ts +0 -29
@@ -1,28 +0,0 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import { exec } from "child_process";
4
- import { logger } from "./logger";
5
-
6
- const rootDir = path.resolve();
7
- const configText = fs.readFileSync("barrels.json", "utf8");
8
- const config = JSON.parse(configText);
9
- const directories: string[] = Array.isArray(config.directory) ? config.directory : [config.directory];
10
-
11
-
12
- directories.forEach((dir) => {
13
- const absoluteDir = path.join(rootDir, dir);
14
-
15
- if (!fs.existsSync(absoluteDir)) {
16
- logger.error(`Barrels error: ${absoluteDir} directory not found`)
17
- return;
18
- }
19
-
20
- fs.watch(absoluteDir, { recursive: true }, (_, filename) => {
21
- if (filename && (filename.endsWith(".ts") || filename.endsWith(".tsx")) && filename !== "index.ts") {
22
- exec("npx barrelsby -c barrels.json", { cwd: rootDir })
23
- logger.info("Barrels updated " + absoluteDir + "/index.ts")
24
- }
25
- });
26
- });
27
-
28
- logger.start("Barrels watched " + directories.join(", "))
@@ -1,421 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { ValidationRules, conversion } from "@skalfa/skalfa-app-core";
4
- import { logger } from "./logger";
5
-
6
-
7
-
8
- type SchemaMap = Record<string, string>
9
-
10
- type ColumnItem = {
11
- selector ?: string
12
- label : string
13
- sortable ?: boolean
14
- item ?: string
15
- }
16
-
17
- type FormItem = {
18
- type ?: string
19
- col ?: number
20
- construction : {
21
- name : string
22
- label : string
23
- placeholder : string
24
- validations : ValidationRules[]
25
- serverOptionControl ?: {
26
- path : string
27
- }
28
- fields ?: FormItem[]
29
- wrap ?: boolean
30
- }
31
- }
32
-
33
- type DetailItem = {
34
- label : string
35
- item : string
36
- }
37
-
38
- type ParsedSchema = {
39
- columns : ColumnItem[]
40
- forms : FormItem[]
41
- details : DetailItem[]
42
- }
43
-
44
- type BlueprintPage = {
45
- features ?: string
46
- path ?: string
47
- schema ?: Record<string, string>
48
- }
49
-
50
- type BlueprintStruct = {
51
- model : string
52
- controllers ?: string[]
53
- schema ?: SchemaMap
54
- pages ?: false | Record<string, BlueprintPage>
55
- [key: string]: any
56
- }
57
-
58
- type LoadedBlueprintFile = {
59
- file : string
60
- blueprints : BlueprintStruct[]
61
- }
62
-
63
-
64
-
65
- const renderJS = (value: unknown, indent = 0): string => {
66
- const pad = " ".repeat(indent)
67
-
68
- if (Array.isArray(value)) {
69
- if (!value.length) return "[]"
70
-
71
- if (value.every(v => typeof v === "string")) {
72
- return `[${value.map(v => JSON.stringify(v)).join(", ")}]`
73
- }
74
-
75
- return `[\n${value
76
- .map(v => pad + " " + renderJS(v, indent + 2))
77
- .join(",\n")}\n${pad}]`
78
- }
79
-
80
- if (value && typeof value === "object") {
81
- const entries = Object.entries(value as Record<string, unknown>)
82
- if (!entries.length) return "{}"
83
-
84
- return `{\n${entries
85
- .map(([k, v]) => `${pad} ${k}: ${renderJS(v, indent + 2)}`)
86
- .join(",\n")}\n${pad}}`
87
- }
88
-
89
- if (typeof value === "string") return JSON.stringify(value)
90
-
91
- return String(value)
92
- }
93
-
94
- function extractValidationArray(def: string = ""): ValidationRules[] {
95
- const rules: ValidationRules[] = []
96
-
97
- if (def.includes("required")) rules.push("required")
98
-
99
- if (def.includes("email")) rules.push("email")
100
-
101
- if (def.includes("url")) rules.push("url")
102
-
103
- const min = def.match(/min,(\d+)/)
104
- if (min) rules.push(`min:${min[1]}`)
105
-
106
- const max = def.match(/max,(\d+)/)
107
- if (max) rules.push(`max:${max[1]}`)
108
-
109
- return rules
110
- }
111
-
112
- function extractFormType(rules: string[]): string | undefined {
113
- const rule = rules.find(r => r.startsWith("form:"))
114
- return rule ? rule.replace("form:", "") : undefined
115
- }
116
-
117
- function inferFormType(pageDef = "", modelDef = ""): string {
118
- const explicit = pageDef.split("|")
119
- if (explicit && explicit[0] && explicit[0] != "text") return explicit[0]
120
-
121
- if (modelDef.includes("type:integer") || modelDef.includes("type:float")) {
122
- return "number"
123
- }
124
-
125
- if (modelDef.includes("type:date")) return "date"
126
- if (modelDef.includes("type:datetime")) return "datetime"
127
- if (modelDef.includes("type:image")) return "image"
128
-
129
- return "default"
130
- }
131
-
132
- function parseFeatures(features?: string): { controlBar: string[]; action: string[] } {
133
- const controlBar: string[] = []
134
- const action: string[] = []
135
-
136
- if (!features) {
137
- return { controlBar: ["CREATE"], action: ["EDIT", "DELETE"] }
138
- }
139
-
140
- const list = features.split(" ")
141
-
142
- if (list.includes("create")) controlBar.push("CREATE")
143
-
144
- controlBar.push("SEARCH", "SORT", "SELECTABLE")
145
-
146
- if (list.includes("import")) controlBar.push("IMPORT")
147
- if (list.includes("export")) controlBar.push("EXPORT")
148
- if (list.includes("print")) controlBar.push("PRINT")
149
-
150
- if (list.includes("update") || list.includes("edit")) action.push("EDIT")
151
- if (list.includes("delete")) action.push("DELETE")
152
- if (list.includes("detail")) action.push("DETAIL")
153
-
154
- return { controlBar, action }
155
- }
156
-
157
- function parseModelSchema(schema: SchemaMap = {}): ParsedSchema {
158
- const columns: ColumnItem[] = []
159
- const forms: FormItem[] = []
160
- const details: DetailItem[] = []
161
-
162
- for (const [field, def] of Object.entries(schema)) {
163
- const label = conversion.strPascal(field, " ")
164
-
165
- if (def.includes("selectable")) {
166
- columns.push({ selector: field, label })
167
- details.push({ label, item: field })
168
- }
169
-
170
- if (def.includes("fillable")) {
171
- const fieldType = inferFormType("", def);
172
- forms.push({
173
- ...(fieldType != "default" ? { type: fieldType } : {}),
174
- construction: {
175
- name: field,
176
- label,
177
- placeholder: "Masukkan " + label.toLowerCase(),
178
- validations: extractValidationArray(def)
179
- }
180
- })
181
- }
182
- }
183
-
184
- return { columns, forms, details }
185
- }
186
-
187
- function resolvePath(page: BlueprintPage, controllers: string[] | boolean | undefined, model: string): string {
188
- if (page.path) return page.path
189
-
190
- if (Array.isArray(controllers)) {
191
- const match = controllers
192
- if (match) return "/" + match[1]
193
- }
194
-
195
- return "/" + model.split("/").pop()
196
- }
197
-
198
- function parsePageSchema(pageSchema: Record<string, string>, modelSchema: SchemaMap = {}): ParsedSchema {
199
- const columns: ColumnItem[] = []
200
- const forms: FormItem[] = []
201
- const details: DetailItem[] = []
202
-
203
- for (const [field, def] of Object.entries(pageSchema)) {
204
- const rules = def.replace(/\|/g, " ").split(" ").filter(Boolean)
205
-
206
- const defaultLabel = conversion.strPascal(field, " ")
207
-
208
- const colLabelRule = rules.find(r => r.includes("column:label,"))
209
- const colLabel = conversion.strPascal(colLabelRule ? colLabelRule.split(",")[1] : defaultLabel, " ")
210
-
211
- const formLabelRule = rules.find(r => r.includes("form:label,"))
212
- const formLabel = conversion.strPascal(formLabelRule ? formLabelRule.split(",")[1] : (colLabelRule ? colLabel : defaultLabel), " ")
213
-
214
- const detailLabel = colLabelRule ? colLabel : (formLabelRule ? formLabel : defaultLabel)
215
-
216
- const hasColumn = rules.some(r => r.includes("column:"))
217
- const hasForm = rules.some(r => r.includes("form:")) || rules.every(r => !r.includes("column:"))
218
-
219
- const hasDetail = rules.includes("detail")
220
-
221
- if (hasColumn) {
222
- columns.push({
223
- selector: field,
224
- label: colLabel,
225
- ...(rules.includes("column:sortable") || rules.includes("sortable") ? { sortable: true } : {})
226
- })
227
- if (!hasDetail) details.push({ label: detailLabel, item: field })
228
- }
229
-
230
- if (hasForm) {
231
- const typeRules = rules.filter(r => !r.startsWith("form:label,"))
232
- const typeRule = extractFormType(typeRules)
233
- let fieldType = inferFormType(typeRule, modelSchema[field] || "");
234
-
235
- let selectPath = ""
236
- const selectRule = rules.find(r => r.startsWith("select,") || r.startsWith("form:select,"))
237
- if (selectRule) {
238
- fieldType = "select"
239
- selectPath = selectRule.split(",")[1]
240
- }
241
-
242
- if (typeRule === "check") fieldType = "boolean"
243
- if (typeRule === "currency") fieldType = "currency"
244
- if (typeRule === "image") fieldType = "image"
245
- if (typeRule === "date") fieldType = "date"
246
- if (typeRule === "time") fieldType = "time"
247
-
248
- let col: number | undefined
249
- const colRule = rules.find(r => /col,(\d+)/.test(r))
250
-
251
- if (colRule) {
252
- const n = Number(colRule.split(',').pop())
253
- if (n >= 1 && n <= 12) col = n
254
- }
255
-
256
- forms.push({
257
- ...(fieldType != "default" && fieldType != "text" ? { type: fieldType } : {}),
258
- ...(col ? { col } : {}),
259
- construction: {
260
- name: field,
261
- label: formLabel,
262
- placeholder: "Masukkan " + formLabel.toLowerCase(),
263
- validations: extractValidationArray(modelSchema[field] || ""),
264
- ...(selectPath ? { serverOptionControl: { path: selectPath } } : {}),
265
- ...(rules.includes("wrap") ? { wrap: true } : {})
266
- }
267
- })
268
- }
269
-
270
- if (hasDetail) details.push({ label: detailLabel, item: field })
271
- }
272
-
273
- const formMap = new Map<string, FormItem>()
274
- forms.forEach(f => formMap.set(f.construction.name, f))
275
-
276
- const nestedForms: FormItem[] = []
277
-
278
- forms.forEach(f => {
279
- const name = f.construction.name
280
- if (name.includes(".")) {
281
- const parts = name.split(".")
282
- const selfName = parts.pop() as string
283
- const parentName = parts.join(".")
284
- const parent = formMap.get(parentName)
285
-
286
- if (parent) {
287
- if (!parent.type) parent.type = "cluster"
288
- if (!parent.construction.fields) parent.construction.fields = []
289
-
290
- f.construction.name = selfName
291
-
292
- parent.construction.fields.push(f)
293
- } else {
294
- nestedForms.push(f)
295
- }
296
- } else {
297
- nestedForms.push(f)
298
- }
299
- })
300
-
301
- return { columns, forms: nestedForms, details }
302
- }
303
-
304
-
305
-
306
- function loadBlueprintFiles(dir: string = "blueprints"): LoadedBlueprintFile[] {
307
- const basePath = path.join(process.cwd(), dir)
308
-
309
- if (!fs.existsSync(basePath)) {
310
- throw new Error("Blueprint folder not found")
311
- }
312
-
313
- return fs.readdirSync(basePath)
314
- .filter(f => f.endsWith(".blueprint.json"))
315
- .map(file => {
316
- const fullPath = path.join(basePath, file)
317
- const content = JSON.parse(fs.readFileSync(fullPath, "utf-8"))
318
-
319
- if (!Array.isArray(content)) {
320
- throw new Error(`${file} must export array of blueprints`)
321
- }
322
-
323
- return {
324
- file: file.replace(".blueprint.json", ""),
325
- blueprints: content as BlueprintStruct[],
326
- }
327
- })
328
- }
329
-
330
- const blueprintMarker = `// ============================================
331
- // ## file THIS FILE IS AUTO-GENERATED BY BLUEPRINT
332
- // ?? Blueprint : {{ blueprint }}
333
- // !! If this comment is removed, blueprint engine WILL NOT override this file.
334
- // ============================================
335
-
336
-
337
- `
338
-
339
-
340
- // ===============================
341
- // ## Main generator
342
- // ===============================
343
-
344
- export async function blueprint(options?: { only?: string[] }): Promise<void> {
345
- const stub = fs.readFileSync(path.join(process.cwd(), "/utils/commands/stubs/table-blueprint.stub"), "utf-8")
346
-
347
- const loaded = loadBlueprintFiles()
348
-
349
- for (const file of loaded) {
350
- for (const bp of file.blueprints) {
351
-
352
- const pagesToGenerate: Record<string, BlueprintPage> = { ...(bp.pages || {}) }
353
-
354
- for (const [key, val] of Object.entries(bp)) {
355
- if (typeof val === "object" && val["schema"]) {
356
- pagesToGenerate[key] = val as BlueprintPage
357
- }
358
- }
359
-
360
- for (const [key, page] of Object.entries(pagesToGenerate)) {
361
-
362
- const route = key;
363
- const name = conversion.strPascal(route.split("/").pop() as string)
364
-
365
- if (options?.only && !options.only.includes(name)) continue
366
-
367
- const outDir = path.join(process.cwd(), "app", route)
368
- fs.mkdirSync(outDir, { recursive: true })
369
-
370
- const filePath = path.join(outDir, "page.tsx");
371
-
372
- if (fs.existsSync(filePath)) {
373
- const content = fs.readFileSync(filePath, "utf-8")
374
-
375
- if (!content.includes("AUTO-GENERATED BY BLUEPRINT")) {
376
- logger.info(`Skip overridden file: ${filePath}`)
377
- continue
378
- }
379
- }
380
-
381
- const schema = bp.schema ?? {}
382
-
383
- const parsed: ParsedSchema = page?.schema ? parsePageSchema(page.schema, schema) : parseModelSchema(schema)
384
-
385
- const { controlBar, action } = parseFeatures(page?.features)
386
-
387
- const fetchPath = resolvePath(page, bp.controllers, bp.model)
388
-
389
- let properties = `
390
- fetchControl={{
391
- path: "${fetchPath}"
392
- }}
393
- columnControl={${renderJS(parsed.columns, 8)}}
394
- formControl={{
395
- fields: ${renderJS(parsed.forms, 10)}
396
- }}
397
- `
398
- if (parsed.details) {
399
- properties += ` detailControl={${renderJS(parsed.details, 8)}}\n`
400
- }
401
-
402
- if (controlBar.length) {
403
- properties += ` controlBar={${JSON.stringify(controlBar)}}\n`
404
- }
405
-
406
- if (action.length) {
407
- properties += ` actionControl={${JSON.stringify(action)}}\n`
408
- }
409
-
410
- const content = stub
411
- .replace(/{{ marker }}/g, blueprintMarker.replace(/{{ blueprint }}/g, file.file + ".blueprint.json"))
412
- .replace(/{{ name }}/g, name)
413
- .replace(/{{ title }}/g, name)
414
- .replace(/{{ properties }}/g, properties)
415
-
416
- fs.writeFileSync(path.join(outDir, "page.tsx"), content)
417
- logger.info(`Generated: ${filePath}`)
418
- }
419
- }
420
- }
421
- }
@@ -1,21 +0,0 @@
1
- import { Command } from "commander";
2
- import { usePdf } from "./use-pdf";
3
- import { blueprint } from "./blueprint";
4
- import { logger } from "./logger";
5
-
6
- const program = new Command();
7
-
8
- program.name("light").description("Next Light CLI").version("1.0.0");
9
-
10
- program.command("use-pdf").description("Copy pdf.worker.min.mjs ke folder public/").action(usePdf );
11
- program.command("blueprint")
12
- .option("-o, --only <names...>", "Run only specific blueprints")
13
- .description("Generate blueprint")
14
- .action(async (opts) => {
15
- await blueprint({ only: opts.only })
16
-
17
- logger.info("Success run all blueprints!")
18
- process.exit(0);
19
- });
20
-
21
- program.parse();
@@ -1,42 +0,0 @@
1
- /* eslint-disable no-console */
2
- type LogType = "start" | "info" | "error" | "warning" | "cavity" | "socket" | "cavityError" | "socketError";
3
-
4
- const colors: Record<LogType | "default", string> = {
5
- default : "\x1b[0m", // default
6
- start : "\x1b[32m", // green
7
- info : "\x1b[36m", // cyan
8
- error : "\x1b[31m", // red
9
- warning : "\x1b[33m", // yellow
10
- cavity : "\x1b[34m", // blue
11
- cavityError : "\x1b[31m", // red
12
- socket : "\x1b[35m", // magenta
13
- socketError : "\x1b[31m", // red
14
- };
15
-
16
- const prefixes: Record<LogType, string> = {
17
- start : "START",
18
- info : "INFO",
19
- error : "ERROR",
20
- warning : "WARNING",
21
- cavity : "CAVITY",
22
- socket : "SOCKET",
23
- cavityError : "CAVITY ERROR",
24
- socketError : "SOCKET ERROR",
25
- };
26
-
27
- function log(type: LogType, ...msg: unknown[]) {
28
- const color = colors[type];
29
- const prefix = prefixes[type];
30
- console.log(`${color}[${prefix}]${colors.default}`, ...msg);
31
- }
32
-
33
- export const logger = {
34
- start : (...msg: unknown[]) => log("start", ...msg),
35
- info : (...msg: unknown[]) => log("info", ...msg),
36
- error : (...msg: unknown[]) => log("error", ...msg),
37
- warning : (...msg: unknown[]) => log("warning", ...msg),
38
- cavity : (...msg: unknown[]) => log("cavity", ...msg),
39
- cavityError : (...msg: unknown[]) => log("cavityError", ...msg),
40
- socket : (...msg: unknown[]) => log("socket", ...msg),
41
- socketError : (...msg: unknown[]) => log("socketError", ...msg),
42
- };
@@ -1,13 +0,0 @@
1
- {{ marker }}
2
- import { TableSupervisionComponent } from "@components";
3
-
4
- export default function {{ name }}Page() {
5
- return (
6
- <>
7
- <TableSupervisionComponent
8
- title="{{ title }}"
9
- {{ properties }}
10
- />
11
- </>
12
- );
13
- }
@@ -1,29 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { fileURLToPath } from "url";
4
- import { logger } from "./logger";
5
-
6
- export function usePdf() {
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
- const projectRoot = path.join(__dirname, "..", "..");
10
-
11
- const source = path.join(
12
- projectRoot,
13
- "node_modules",
14
- "pdfjs-dist",
15
- "legacy",
16
- "build",
17
- "pdf.worker.min.mjs"
18
- );
19
-
20
- const target = path.join(projectRoot, "public", "pdf.worker.min.mjs");
21
-
22
- if (!fs.existsSync(source)) {
23
- logger.error(`Gagal: pdf.worker.min.mjs tidak ditemukan.`)
24
- process.exit(1);
25
- }
26
-
27
- fs.copyFileSync(source, target);
28
- logger.info("Berhasil memindahkan worker ke public/pdf.worker.min.mjs")
29
- }