From 5f131458d503a0420b1f453340fcbdff1ebbb2ce Mon Sep 17 00:00:00 2001 From: Kresna <13603341+slaveofcode@users.noreply.github.com> Date: Fri, 28 Aug 2026 06:37:24 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20add=20Code=20Beautifier,=20vCard?= =?UTF-8?q?=E2=86=94CSV,=20NPWP=20Validator=20&=20Photo=20Collage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four more client-side tools, each with a unit-tested pure lib + EN/ID SEO + Bahasa labels: - Code Beautifier (Prettier standalone, per-language lazy chunks; prettier-* chunks globIgnored from PWA precache) - vCard <-> CSV contacts converter (RFC-4180 CSV parse + vCard 3.0) - NPWP Validator/Formatter (Indonesian tax ID, 15/16-digit structural check) - Photo Collage Maker (grid layout + center-crop, canvas) --- astro.config.mjs | 10 ++ src/islands/dev/CodeBeautify.tsx | 69 ++++++++++++ src/islands/dev/NpwpTool.tsx | 60 +++++++++++ src/islands/dev/VcardCsv.tsx | 96 +++++++++++++++++ src/islands/image/PhotoCollage.tsx | 134 +++++++++++++++++++++++ src/registry/tool-i18n.ts | 4 + src/registry/tool-seo.ts | 136 ++++++++++++++++++++++++ src/registry/tools.ts | 44 ++++++++ src/tools/dev/code-beautify.lib.test.ts | 17 +++ src/tools/dev/code-beautify.lib.ts | 58 ++++++++++ src/tools/dev/npwp.lib.test.ts | 36 +++++++ src/tools/dev/npwp.lib.ts | 56 ++++++++++ src/tools/dev/vcard.lib.test.ts | 51 +++++++++ src/tools/dev/vcard.lib.ts | 106 ++++++++++++++++++ src/tools/image/collage.lib.test.ts | 26 +++++ src/tools/image/collage.lib.ts | 22 ++++ 16 files changed, 925 insertions(+) create mode 100644 src/islands/dev/CodeBeautify.tsx create mode 100644 src/islands/dev/NpwpTool.tsx create mode 100644 src/islands/dev/VcardCsv.tsx create mode 100644 src/islands/image/PhotoCollage.tsx create mode 100644 src/tools/dev/code-beautify.lib.test.ts create mode 100644 src/tools/dev/code-beautify.lib.ts create mode 100644 src/tools/dev/npwp.lib.test.ts create mode 100644 src/tools/dev/npwp.lib.ts create mode 100644 src/tools/dev/vcard.lib.test.ts create mode 100644 src/tools/dev/vcard.lib.ts create mode 100644 src/tools/image/collage.lib.test.ts create mode 100644 src/tools/image/collage.lib.ts diff --git a/astro.config.mjs b/astro.config.mjs index fbfe074..b8dc891 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -59,6 +59,15 @@ export default defineConfig({ manualChunks(id) { if (id.includes('node_modules/epubjs')) return 'epubjs'; if (id.includes('node_modules/jszip')) return 'jszip'; + // Prettier (Code Beautifier) is large and lazily-imported per language. + // Give every prettier chunk a stable `prettier-` prefix so it can be + // kept out of the PWA precache via globIgnores while still code-split + // per language plugin (loaded on demand, not in the island chunk). + if (id.includes('node_modules/prettier/plugins/')) { + const m = id.match(/plugins\/([a-z0-9]+)/i); + return m ? `prettier-${m[1]}` : 'prettier-plugin'; + } + if (id.includes('node_modules/prettier/')) return 'prettier-standalone'; }, }, }, @@ -142,6 +151,7 @@ export default defineConfig({ '**/terser*.js', '**/csso*.js', '**/zxing*.js', + '**/prettier-*.js', 'og/*.png', ], runtimeCaching: [ diff --git a/src/islands/dev/CodeBeautify.tsx b/src/islands/dev/CodeBeautify.tsx new file mode 100644 index 0000000..e98c3a2 --- /dev/null +++ b/src/islands/dev/CodeBeautify.tsx @@ -0,0 +1,69 @@ +import { useState } from 'react'; +import { Button } from '@/components/ui/Button'; +import { TextArea } from '@/components/ui/TextArea'; +import { CopyButton } from '@/components/ui/CopyButton'; +import { beautify, BEAUTIFY_LANGS, type BeautifyLang } from '@/tools/dev/code-beautify.lib'; +import type { Lang } from '@/i18n/config'; + +const TR: Record> = { + en: { + intro: 'Beautify and format code — JavaScript, TypeScript, CSS, HTML, JSON, Markdown and YAML — with Prettier, entirely in your browser. Nothing is uploaded.', + language: 'Language', input: 'Input', output: 'Output', run: 'Beautify', copy: 'Copy', + placeholder: 'Paste your code…', failed: 'Could not format — check the syntax.', + }, + id: { + intro: 'Percantik dan format kode — JavaScript, TypeScript, CSS, HTML, JSON, Markdown, dan YAML — dengan Prettier, sepenuhnya di browser Anda. Tidak ada yang diunggah.', + language: 'Bahasa', input: 'Masukan', output: 'Keluaran', run: 'Percantik', copy: 'Salin', + placeholder: 'Tempel kode Anda…', failed: 'Tidak dapat memformat — periksa sintaksnya.', + }, +}; + +export default function CodeBeautify({ lang = 'en' }: { lang?: Lang }) { + const t = TR[lang] ?? TR.en; + const [codeLang, setCodeLang] = useState('js'); + const [src, setSrc] = useState('const greet=(name)=>{return "hi "+name}\nconsole.log(greet("world"))'); + const [out, setOut] = useState(''); + const [busy, setBusy] = useState(false); + const [error, setError] = useState(''); + + const run = async () => { + setBusy(true); setError(''); setOut(''); + try { + setOut(await beautify(src, codeLang)); + } catch { + setError(t.failed); + } finally { + setBusy(false); + } + }; + + return ( +
+

{t.intro}

+ + + +
+
+ {t.input} +