@ahmedrowaihi/pdf-forge-preview 1.0.0-canary.0
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/.next/BUILD_ID +1 -0
- package/.next/app-path-routes-manifest.json +7 -0
- package/.next/build/chunks/[root-of-the-server]__12fb5caf._.js +233 -0
- package/.next/build/chunks/[root-of-the-server]__12fb5caf._.js.map +8 -0
- package/.next/build/chunks/[root-of-the-server]__242deb00._.js +500 -0
- package/.next/build/chunks/[root-of-the-server]__242deb00._.js.map +11 -0
- package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_ad9a1eec._.js +13 -0
- package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_ad9a1eec._.js.map +5 -0
- package/.next/build/chunks/[turbopack]_runtime.js +795 -0
- package/.next/build/chunks/[turbopack]_runtime.js.map +10 -0
- package/.next/build/chunks/node_modules__pnpm_806d01c0._.js +6758 -0
- package/.next/build/chunks/node_modules__pnpm_806d01c0._.js.map +47 -0
- package/.next/build/package.json +1 -0
- package/.next/build/postcss.js +6 -0
- package/.next/build/postcss.js.map +5 -0
- package/.next/build-manifest.json +20 -0
- package/.next/diagnostics/build-diagnostics.json +6 -0
- package/.next/diagnostics/framework.json +1 -0
- package/.next/export-marker.json +6 -0
- package/.next/fallback-build-manifest.json +12 -0
- package/.next/images-manifest.json +66 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +65 -0
- package/.next/required-server-files.js +163 -0
- package/.next/required-server-files.json +163 -0
- package/.next/routes-manifest.json +77 -0
- package/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
- package/.next/server/app/_global-error/page/build-manifest.json +17 -0
- package/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
- package/.next/server/app/_global-error/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
- package/.next/server/app/_global-error/page.js +11 -0
- package/.next/server/app/_global-error/page.js.map +5 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/.next/server/app/_global-error/page_client-reference-manifest.js +2 -0
- package/.next/server/app/_global-error.html +2 -0
- package/.next/server/app/_global-error.meta +15 -0
- package/.next/server/app/_global-error.rsc +13 -0
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_full.segment.rsc +13 -0
- package/.next/server/app/_global-error.segments/_head.segment.rsc +6 -0
- package/.next/server/app/_global-error.segments/_index.segment.rsc +4 -0
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
- package/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
- package/.next/server/app/_not-found/page/build-manifest.json +17 -0
- package/.next/server/app/_not-found/page/next-font-manifest.json +16 -0
- package/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/_not-found/page/server-reference-manifest.json +20 -0
- package/.next/server/app/_not-found/page.js +14 -0
- package/.next/server/app/_not-found/page.js.map +5 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +2 -0
- package/.next/server/app/favicon.ico/route/app-paths-manifest.json +3 -0
- package/.next/server/app/favicon.ico/route/build-manifest.json +11 -0
- package/.next/server/app/favicon.ico/route.js +6 -0
- package/.next/server/app/favicon.ico/route.js.map +5 -0
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +1 -0
- package/.next/server/app/page/app-paths-manifest.json +3 -0
- package/.next/server/app/page/build-manifest.json +17 -0
- package/.next/server/app/page/next-font-manifest.json +16 -0
- package/.next/server/app/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/page/server-reference-manifest.json +20 -0
- package/.next/server/app/page.js +17 -0
- package/.next/server/app/page.js.map +5 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +2 -0
- package/.next/server/app/preview/[...slug]/page/app-paths-manifest.json +3 -0
- package/.next/server/app/preview/[...slug]/page/build-manifest.json +17 -0
- package/.next/server/app/preview/[...slug]/page/next-font-manifest.json +16 -0
- package/.next/server/app/preview/[...slug]/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/preview/[...slug]/page/server-reference-manifest.json +65 -0
- package/.next/server/app/preview/[...slug]/page.js +19 -0
- package/.next/server/app/preview/[...slug]/page.js.map +5 -0
- package/.next/server/app/preview/[...slug]/page.js.nft.json +1 -0
- package/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +2 -0
- package/.next/server/app-paths-manifest.json +7 -0
- package/.next/server/chunks/730ea_preview-server__next-internal_server_app_favicon_ico_route_actions_a71a8ae7.js +3 -0
- package/.next/server/chunks/730ea_preview-server__next-internal_server_app_favicon_ico_route_actions_a71a8ae7.js.map +1 -0
- package/.next/server/chunks/[externals]_next_dist_a6d89067._.js +3 -0
- package/.next/server/chunks/[externals]_next_dist_a6d89067._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__a62cd78d._.js +21 -0
- package/.next/server/chunks/[root-of-the-server]__a62cd78d._.js.map +1 -0
- package/.next/server/chunks/[turbopack]_runtime.js +795 -0
- package/.next/server/chunks/[turbopack]_runtime.js.map +10 -0
- package/.next/server/chunks/ssr/730ea_preview-server__next-internal_server_app__global-error_page_actions_986e2de5.js +3 -0
- package/.next/server/chunks/ssr/730ea_preview-server__next-internal_server_app__global-error_page_actions_986e2de5.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__025eaae9._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__025eaae9._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1536282c._.js +4 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1536282c._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__15cf9d36._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__15cf9d36._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__450f653e._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__450f653e._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__4874d0d7._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__4874d0d7._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__49771cdc._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__49771cdc._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__9ff74047._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__9ff74047._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__a9be37b1._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__a9be37b1._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__aeefe74e._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__aeefe74e._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__b13738d2._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__b13738d2._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__bb428c83._.js +4 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__bb428c83._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__c61333e3._.js +10 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__c61333e3._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__cb0c7b1a._.js +4 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__cb0c7b1a._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__dafcae4c._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__dafcae4c._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__e47d0c07._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__e47d0c07._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__ecac8617._.js +31 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__ecac8617._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__fd4bda25._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__fd4bda25._.js.map +1 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js +795 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +10 -0
- package/.next/server/chunks/ssr/_19494208._.js +19 -0
- package/.next/server/chunks/ssr/_19494208._.js.map +1 -0
- package/.next/server/chunks/ssr/_810f54e9._.js +4 -0
- package/.next/server/chunks/ssr/_810f54e9._.js.map +1 -0
- package/.next/server/chunks/ssr/_aa01e67e._.js +4 -0
- package/.next/server/chunks/ssr/_aa01e67e._.js.map +1 -0
- package/.next/server/chunks/ssr/_bf10718b._.js +4 -0
- package/.next/server/chunks/ssr/_bf10718b._.js.map +1 -0
- package/.next/server/chunks/ssr/_c57c12df._.js +4 -0
- package/.next/server/chunks/ssr/_c57c12df._.js.map +1 -0
- package/.next/server/chunks/ssr/_d9b57cb8._.js +5 -0
- package/.next/server/chunks/ssr/_d9b57cb8._.js.map +1 -0
- package/.next/server/chunks/ssr/_e2a766a8._.js +3 -0
- package/.next/server/chunks/ssr/_e2a766a8._.js.map +1 -0
- package/.next/server/chunks/ssr/_e2b86512._.js +8 -0
- package/.next/server/chunks/ssr/_e2b86512._.js.map +1 -0
- package/.next/server/chunks/ssr/_ee8ea3aa._.js +19 -0
- package/.next/server/chunks/ssr/_ee8ea3aa._.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_5870db32._.js +3 -0
- package/.next/server/chunks/ssr/e8449_next_dist_5870db32._.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_builtin_forbidden_5542069c.js +3 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_builtin_forbidden_5542069c.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_builtin_global-error_d0870f3a.js +3 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_builtin_global-error_d0870f3a.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_builtin_unauthorized_4c01c8d5.js +3 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_builtin_unauthorized_4c01c8d5.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_d90ace34._.js +3 -0
- package/.next/server/chunks/ssr/e8449_next_dist_client_components_d90ace34._.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_esm_af7aafb8._.js +6 -0
- package/.next/server/chunks/ssr/e8449_next_dist_esm_af7aafb8._.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_esm_build_templates_app-page_f16f0848.js +4 -0
- package/.next/server/chunks/ssr/e8449_next_dist_esm_build_templates_app-page_f16f0848.js.map +1 -0
- package/.next/server/chunks/ssr/e8449_next_dist_f0d8a2cc._.js +4 -0
- package/.next/server/chunks/ssr/e8449_next_dist_f0d8a2cc._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules__pnpm_37510d96._.js +5 -0
- package/.next/server/chunks/ssr/node_modules__pnpm_37510d96._.js.map +1 -0
- package/.next/server/chunks/ssr/packages_preview-server_src_app_897ecf1c._.js +3 -0
- package/.next/server/chunks/ssr/packages_preview-server_src_app_897ecf1c._.js.map +1 -0
- package/.next/server/chunks/ssr/packages_preview-server_src_e17a2a9b._.js +3 -0
- package/.next/server/chunks/ssr/packages_preview-server_src_e17a2a9b._.js.map +1 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +21 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +34 -0
- package/.next/server/pages/500.html +2 -0
- package/.next/server/pages-manifest.json +3 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +80 -0
- package/.next/static/cdYIhKFtJ0GB-yJK5ywz_/_buildManifest.js +11 -0
- package/.next/static/cdYIhKFtJ0GB-yJK5ywz_/_clientMiddlewareManifest.json +1 -0
- package/.next/static/cdYIhKFtJ0GB-yJK5ywz_/_ssgManifest.js +1 -0
- package/.next/static/chunks/0464c7ff175ee6ff.js +1 -0
- package/.next/static/chunks/10468413db24762a.js +14 -0
- package/.next/static/chunks/2de338262e51ef94.js +3 -0
- package/.next/static/chunks/37adc260f85da877.js +1 -0
- package/.next/static/chunks/521eee9903bc4d1f.js +5 -0
- package/.next/static/chunks/6051bd38272cb442.js +14 -0
- package/.next/static/chunks/8d433d4b9d701456.js +1 -0
- package/.next/static/chunks/92ba72595aad9df6.js +1 -0
- package/.next/static/chunks/959ed978a6e89a66.js +1 -0
- package/.next/static/chunks/a6dad97d9634a72d.js +1 -0
- package/.next/static/chunks/a6dad97d9634a72d.js.map +1 -0
- package/.next/static/chunks/a6db6456c5b75734.js +1 -0
- package/.next/static/chunks/c3ece0a7e3e07076.js +1 -0
- package/.next/static/chunks/d1b29a74f6814a03.css +3 -0
- package/.next/static/chunks/f7ec22614fe1c1fe.js +1 -0
- package/.next/static/chunks/turbopack-e062a8e6d6034eb0.js +4 -0
- package/.next/static/media/1bffadaabf893a1e-s.7cd81963.woff2 +0 -0
- package/.next/static/media/2bbe8d2671613f1f-s.76dcb0b2.woff2 +0 -0
- package/.next/static/media/2c55a0e60120577a-s.2a48534a.woff2 +0 -0
- package/.next/static/media/5476f68d60460930-s.c995e352.woff2 +0 -0
- package/.next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2 +0 -0
- package/.next/static/media/9c72aa0f40e4eef8-s.18a48cbc.woff2 +0 -0
- package/.next/static/media/SFMonoBold-s.p.b90ec775.otf +0 -0
- package/.next/static/media/SFMonoHeavy-s.p.545fe93b.otf +0 -0
- package/.next/static/media/SFMonoLight-s.p.7c5363a6.otf +0 -0
- package/.next/static/media/SFMonoMedium-s.p.a4fc9904.otf +0 -0
- package/.next/static/media/SFMonoRegular-s.p.04ea7bf3.otf +0 -0
- package/.next/static/media/SFMonoSemibold-s.p.2d2ddb43.otf +0 -0
- package/.next/static/media/ad66f9afd8947f86-s.7a40eb73.woff2 +0 -0
- package/.next/static/media/favicon.678eb597.ico +0 -0
- package/.next/static/media/logo.22a370b0.png +0 -0
- package/.next/trace +1 -0
- package/.next/trace-build +1 -0
- package/.next/turbopack +0 -0
- package/.next/types/routes.d.ts +58 -0
- package/.next/types/validator.ts +70 -0
- package/CHANGELOG.md +12 -0
- package/LICENSE.md +8 -0
- package/index.mjs +17 -0
- package/jsx-runtime/jsx-dev-runtime.js +26 -0
- package/module-punycode.d.ts +3 -0
- package/next-env.d.ts +6 -0
- package/next.config.mjs +15 -0
- package/package.json +78 -0
- package/postcss.config.js +5 -0
- package/readme.md +33 -0
- package/scripts/build-preview-server.mts +25 -0
- package/scripts/dev.mts +57 -0
- package/scripts/seed.mts +36 -0
- package/src/actions/export-single-template.ts +74 -0
- package/src/actions/get-template-path-from-slug.ts +32 -0
- package/src/actions/get-templates-directory-metadata-action.ts +19 -0
- package/src/actions/render-template-by-path.tsx +313 -0
- package/src/actions/safe-action.ts +15 -0
- package/src/animated-icons-data/help.json +1082 -0
- package/src/animated-icons-data/link.json +1309 -0
- package/src/animated-icons-data/load.json +443 -0
- package/src/animated-icons-data/mail.json +1320 -0
- package/src/app/env.ts +14 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/fonts/SFMono/SFMonoBold.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoBoldItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoHeavy.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoHeavyItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoLight.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoLightItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoMedium.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoMediumItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoRegular.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoRegularItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoSemibold.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoSemiboldItalic.otf +0 -0
- package/src/app/fonts.ts +39 -0
- package/src/app/globals.css +136 -0
- package/src/app/layout.tsx +46 -0
- package/src/app/logo.png +0 -0
- package/src/app/page.tsx +52 -0
- package/src/app/preview/[...slug]/download-button.tsx +138 -0
- package/src/app/preview/[...slug]/error-overlay.tsx +58 -0
- package/src/app/preview/[...slug]/page.tsx +90 -0
- package/src/app/preview/[...slug]/preview.tsx +249 -0
- package/src/app/preview/[...slug]/template-frame.tsx +68 -0
- package/src/components/button.tsx +101 -0
- package/src/components/code-container.tsx +169 -0
- package/src/components/code-snippet.tsx +9 -0
- package/src/components/code.tsx +185 -0
- package/src/components/heading.tsx +113 -0
- package/src/components/icons/icon-arrow-down.tsx +16 -0
- package/src/components/icons/icon-base.tsx +26 -0
- package/src/components/icons/icon-bug.tsx +19 -0
- package/src/components/icons/icon-button.tsx +23 -0
- package/src/components/icons/icon-check.tsx +19 -0
- package/src/components/icons/icon-clipboard.tsx +40 -0
- package/src/components/icons/icon-cloud-alert.tsx +18 -0
- package/src/components/icons/icon-cloud-check.tsx +17 -0
- package/src/components/icons/icon-download.tsx +19 -0
- package/src/components/icons/icon-file.tsx +19 -0
- package/src/components/icons/icon-folder-open.tsx +19 -0
- package/src/components/icons/icon-folder.tsx +18 -0
- package/src/components/icons/icon-hide-sidebar.tsx +23 -0
- package/src/components/icons/icon-image.tsx +19 -0
- package/src/components/icons/icon-info.tsx +18 -0
- package/src/components/icons/icon-link.tsx +14 -0
- package/src/components/icons/icon-loader.tsx +16 -0
- package/src/components/icons/icon-monitor.tsx +19 -0
- package/src/components/icons/icon-moon.tsx +16 -0
- package/src/components/icons/icon-phone.tsx +26 -0
- package/src/components/icons/icon-reload.tsx +18 -0
- package/src/components/icons/icon-source.tsx +19 -0
- package/src/components/icons/icon-stamp.tsx +14 -0
- package/src/components/icons/icon-sun.tsx +74 -0
- package/src/components/icons/icon-warning.tsx +31 -0
- package/src/components/index.ts +7 -0
- package/src/components/logo.tsx +41 -0
- package/src/components/resizable-wrapper.tsx +269 -0
- package/src/components/shell.tsx +95 -0
- package/src/components/sidebar/file-tree-directory-children.tsx +142 -0
- package/src/components/sidebar/file-tree-directory.tsx +92 -0
- package/src/components/sidebar/file-tree.tsx +31 -0
- package/src/components/sidebar/index.ts +1 -0
- package/src/components/sidebar/sidebar.tsx +46 -0
- package/src/components/text.tsx +99 -0
- package/src/components/toolbar/checking-results.tsx +150 -0
- package/src/components/toolbar/code-preview-line-link.tsx +39 -0
- package/src/components/toolbar/results-table.tsx +0 -0
- package/src/components/toolbar/results.tsx +52 -0
- package/src/components/toolbar/toolbar-button.tsx +52 -0
- package/src/components/toolbar/use-cached-state.ts +36 -0
- package/src/components/toolbar.tsx +182 -0
- package/src/components/tooltip-content.tsx +31 -0
- package/src/components/tooltip.tsx +19 -0
- package/src/components/topbar/active-view-toggle-group.tsx +86 -0
- package/src/components/topbar/emulated-dark-mode-toggle.tsx +58 -0
- package/src/components/topbar/view-size-controls.tsx +173 -0
- package/src/components/topbar.tsx +59 -0
- package/src/contexts/preview.tsx +91 -0
- package/src/contexts/templates.tsx +57 -0
- package/src/contexts/toolbar.tsx +22 -0
- package/src/hooks/use-clamped-state.ts +24 -0
- package/src/hooks/use-fragment-identifier.ts +14 -0
- package/src/hooks/use-hot-reload.ts +31 -0
- package/src/hooks/use-rendering-metadata.ts +37 -0
- package/src/hooks/use-template-rendering-result.ts +58 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/constants.ts +8 -0
- package/src/utils/contains-template.ts +52 -0
- package/src/utils/convert-stack-with-sourcemap.ts +79 -0
- package/src/utils/copy-text-to-clipboard.ts +7 -0
- package/src/utils/create-jsx-runtime.ts +47 -0
- package/src/utils/esbuild/escape-string-for-regex.ts +3 -0
- package/src/utils/esbuild/renderring-utilities-exporter.ts +64 -0
- package/src/utils/get-line-and-column-from-offset.ts +11 -0
- package/src/utils/get-template-component.ts +158 -0
- package/src/utils/get-templates-directory-metadata.ts +195 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/language-map.ts +7 -0
- package/src/utils/load-stream.ts +15 -0
- package/src/utils/register-spinner-autostopping.ts +28 -0
- package/src/utils/result.ts +49 -0
- package/src/utils/run-bundled-code.ts +86 -0
- package/src/utils/sanitize.ts +6 -0
- package/src/utils/sleep.ts +3 -0
- package/src/utils/snake-to-camel.ts +5 -0
- package/src/utils/static-node-modules-for-vm.ts +93 -0
- package/src/utils/style-text.ts +11 -0
- package/src/utils/types/as.ts +26 -0
- package/src/utils/types/error-object.ts +11 -0
- package/src/utils/types/hot-reload-change.ts +13 -0
- package/src/utils/types/template.ts +8 -0
- package/src/utils/unreachable.ts +8 -0
- package/templates/.gitkeep +0 -0
- package/tsconfig.json +47 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { motion } from 'framer-motion';
|
|
2
|
+
import { cn } from '../../utils';
|
|
3
|
+
import { Tooltip } from '../tooltip';
|
|
4
|
+
|
|
5
|
+
interface ToolbarButtonProps extends React.ComponentProps<'button'> {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
active?: boolean;
|
|
8
|
+
tooltip?: React.ReactNode;
|
|
9
|
+
delayDuration?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ToolbarButton = ({
|
|
13
|
+
children,
|
|
14
|
+
className,
|
|
15
|
+
active,
|
|
16
|
+
tooltip,
|
|
17
|
+
delayDuration = 500,
|
|
18
|
+
...props
|
|
19
|
+
}: ToolbarButtonProps) => {
|
|
20
|
+
return (
|
|
21
|
+
<Tooltip.Provider>
|
|
22
|
+
<Tooltip delayDuration={delayDuration}>
|
|
23
|
+
<Tooltip.Trigger asChild>
|
|
24
|
+
<button
|
|
25
|
+
type="button"
|
|
26
|
+
{...props}
|
|
27
|
+
className={cn(
|
|
28
|
+
'h-full w-fit font-regular flex text-sm text-slate-10 items-center align-middle justify-center px-1 gap-2 relative',
|
|
29
|
+
'hover:text-slate-12 transition-colors',
|
|
30
|
+
active && 'data-[state=active]:text-cyan-11',
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
{active ? (
|
|
36
|
+
<motion.span
|
|
37
|
+
className="-bottom-px absolute rounded-xs left-0 w-full bg-cyan-11 h-px"
|
|
38
|
+
layoutId="active-toolbar-button"
|
|
39
|
+
transition={{
|
|
40
|
+
type: 'spring',
|
|
41
|
+
bounce: 0.2,
|
|
42
|
+
duration: 0.6,
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
) : null}
|
|
46
|
+
</button>
|
|
47
|
+
</Tooltip.Trigger>
|
|
48
|
+
{tooltip ? <Tooltip.Content>{tooltip}</Tooltip.Content> : null}
|
|
49
|
+
</Tooltip>
|
|
50
|
+
</Tooltip.Provider>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
|
|
3
|
+
export const useCachedState = <T>(key: string) => {
|
|
4
|
+
let value: T | undefined;
|
|
5
|
+
if (
|
|
6
|
+
'localStorage' in global &&
|
|
7
|
+
typeof global.localStorage.getItem === 'function'
|
|
8
|
+
) {
|
|
9
|
+
const storedValue = global.localStorage.getItem(key);
|
|
10
|
+
if (storedValue !== null && storedValue !== 'undefined') {
|
|
11
|
+
try {
|
|
12
|
+
value = JSON.parse(storedValue) as T;
|
|
13
|
+
} catch (_exception) {
|
|
14
|
+
console.warn(
|
|
15
|
+
'Failed to load stored value for',
|
|
16
|
+
key,
|
|
17
|
+
'with value',
|
|
18
|
+
storedValue,
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return [
|
|
25
|
+
useSyncExternalStore(
|
|
26
|
+
() => () => {},
|
|
27
|
+
() => value,
|
|
28
|
+
() => undefined,
|
|
29
|
+
),
|
|
30
|
+
function setValue(newValue: T | undefined) {
|
|
31
|
+
if ('localStorage' in global) {
|
|
32
|
+
global.localStorage.setItem(key, JSON.stringify(newValue));
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
] as const;
|
|
36
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as Tabs from '@radix-ui/react-tabs';
|
|
4
|
+
import { LayoutGroup } from 'framer-motion';
|
|
5
|
+
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
6
|
+
import type { ComponentProps } from 'react';
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
import { usePreviewContext } from '../contexts/preview';
|
|
9
|
+
import { cn } from '../utils';
|
|
10
|
+
import { IconArrowDown } from './icons/icon-arrow-down';
|
|
11
|
+
import { IconCheck } from './icons/icon-check';
|
|
12
|
+
import { IconInfo } from './icons/icon-info';
|
|
13
|
+
import { ToolbarButton } from './toolbar/toolbar-button';
|
|
14
|
+
|
|
15
|
+
export type ToolbarTabValue = 'linter';
|
|
16
|
+
|
|
17
|
+
export const useToolbarState = () => {
|
|
18
|
+
const searchParams = useSearchParams();
|
|
19
|
+
|
|
20
|
+
const activeTab = (searchParams.get('toolbar-panel') ?? undefined) as
|
|
21
|
+
| ToolbarTabValue
|
|
22
|
+
| undefined;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
activeTab,
|
|
26
|
+
|
|
27
|
+
toggled: activeTab !== undefined,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const ToolbarInner = () => {
|
|
32
|
+
const pathname = usePathname();
|
|
33
|
+
const searchParams = useSearchParams();
|
|
34
|
+
const router = useRouter();
|
|
35
|
+
|
|
36
|
+
const { activeTab, toggled } = useToolbarState();
|
|
37
|
+
|
|
38
|
+
const setActivePanelValue = (newValue: ToolbarTabValue | undefined) => {
|
|
39
|
+
const params = new URLSearchParams(searchParams);
|
|
40
|
+
if (newValue === undefined) {
|
|
41
|
+
params.delete('toolbar-panel');
|
|
42
|
+
} else {
|
|
43
|
+
params.set('toolbar-panel', newValue);
|
|
44
|
+
}
|
|
45
|
+
router.push(`${pathname}?${params.toString()}${location.hash}`);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const id = React.useId();
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
data-toggled={toggled}
|
|
53
|
+
className={cn(
|
|
54
|
+
'absolute bottom-0 left-0 right-0',
|
|
55
|
+
'border-t border-slate-6 group/toolbar text-xs text-slate-11 h-52 transition-transform',
|
|
56
|
+
'data-[toggled=false]:translate-y-42.5',
|
|
57
|
+
)}
|
|
58
|
+
>
|
|
59
|
+
<Tabs.Root
|
|
60
|
+
value={activeTab ?? ''}
|
|
61
|
+
onValueChange={(newValue) => {
|
|
62
|
+
setActivePanelValue(newValue as ToolbarTabValue);
|
|
63
|
+
}}
|
|
64
|
+
asChild
|
|
65
|
+
>
|
|
66
|
+
<div className="flex flex-col h-full">
|
|
67
|
+
<Tabs.List className="flex gap-4 px-4 border-b border-solid border-slate-6 h-10 w-full shrink-0">
|
|
68
|
+
<LayoutGroup id={`toolbar-${id}`}>
|
|
69
|
+
<Tabs.Trigger asChild value="linter">
|
|
70
|
+
<ToolbarButton active={activeTab === 'linter'}>
|
|
71
|
+
Linter
|
|
72
|
+
</ToolbarButton>
|
|
73
|
+
</Tabs.Trigger>
|
|
74
|
+
</LayoutGroup>
|
|
75
|
+
<div className="flex gap-0.5 ml-auto">
|
|
76
|
+
<ToolbarButton
|
|
77
|
+
delayDuration={0}
|
|
78
|
+
tooltip={
|
|
79
|
+
activeTab === 'linter'
|
|
80
|
+
? 'PDF-specific linting features are coming soon. This will check for page breaks, print CSS issues, font loading problems, and more.'
|
|
81
|
+
: 'Info'
|
|
82
|
+
}
|
|
83
|
+
>
|
|
84
|
+
<IconInfo size={24} />
|
|
85
|
+
</ToolbarButton>
|
|
86
|
+
<ToolbarButton
|
|
87
|
+
tooltip="Toggle toolbar"
|
|
88
|
+
onClick={() => {
|
|
89
|
+
if (activeTab === undefined) {
|
|
90
|
+
setActivePanelValue('linter');
|
|
91
|
+
} else {
|
|
92
|
+
setActivePanelValue(undefined);
|
|
93
|
+
}
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
96
|
+
<IconArrowDown
|
|
97
|
+
size={24}
|
|
98
|
+
className="transition-transform group-data-[toggled=false]/toolbar:rotate-180"
|
|
99
|
+
/>
|
|
100
|
+
</ToolbarButton>
|
|
101
|
+
</div>
|
|
102
|
+
</Tabs.List>
|
|
103
|
+
|
|
104
|
+
<div className="grow transition-opacity opacity-100 group-data-[toggled=false]/toolbar:opacity-0 overflow-y-auto pr-3 pl-4 pt-3">
|
|
105
|
+
<Tabs.Content value="linter">
|
|
106
|
+
<SuccessWrapper>
|
|
107
|
+
<SuccessIcon />
|
|
108
|
+
<SuccessTitle>PDF Linter Coming Soon</SuccessTitle>
|
|
109
|
+
<SuccessDescription>
|
|
110
|
+
We're working on PDF-specific linting features that will check
|
|
111
|
+
for page breaks, print CSS issues, font loading problems, and
|
|
112
|
+
more. Stay tuned!
|
|
113
|
+
</SuccessDescription>
|
|
114
|
+
</SuccessWrapper>
|
|
115
|
+
</Tabs.Content>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</Tabs.Root>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const SuccessWrapper = ({ children }: { children: React.ReactNode }) => {
|
|
124
|
+
return (
|
|
125
|
+
<div className="flex flex-col items-center justify-center pt-8">
|
|
126
|
+
{children}
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const SuccessIcon = () => {
|
|
132
|
+
return (
|
|
133
|
+
<div className="relative mb-8 flex items-center justify-center">
|
|
134
|
+
<div className="h-16 w-16 rounded-full bg-linear-to-br from-green-300/20 opacity-80 to-emerald-500/30 blur-md absolute m-auto left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
|
|
135
|
+
<div className="h-12 w-12 rounded-full bg-linear-to-br from-green-400/80 opacity-10 to-emerald-600/80 absolute m-auto left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 shadow-lg" />
|
|
136
|
+
<div className="h-10 w-10 rounded-full bg-linear-to-br from-green-400 to-emerald-600 flex items-center justify-center absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 shadow-[inset_0_1px_1px_rgba(255,255,255,0.4)]">
|
|
137
|
+
<IconCheck size={24} className="text-white drop-shadow-xs" />
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const SuccessTitle = ({
|
|
144
|
+
children,
|
|
145
|
+
className,
|
|
146
|
+
...props
|
|
147
|
+
}: ComponentProps<'h3'>) => {
|
|
148
|
+
return (
|
|
149
|
+
<h3
|
|
150
|
+
className={cn('text-slate-12 font-medium text-base mb-1', className)}
|
|
151
|
+
{...props}
|
|
152
|
+
>
|
|
153
|
+
{children}
|
|
154
|
+
</h3>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const SuccessDescription = ({
|
|
159
|
+
children,
|
|
160
|
+
className,
|
|
161
|
+
...props
|
|
162
|
+
}: ComponentProps<'p'>) => {
|
|
163
|
+
return (
|
|
164
|
+
<p
|
|
165
|
+
className={cn(
|
|
166
|
+
'text-slate-11 text-sm text-center max-w-[320px]',
|
|
167
|
+
className,
|
|
168
|
+
)}
|
|
169
|
+
{...props}
|
|
170
|
+
>
|
|
171
|
+
{children}
|
|
172
|
+
</p>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export function Toolbar() {
|
|
177
|
+
const { renderedTemplateMetadata } = usePreviewContext();
|
|
178
|
+
|
|
179
|
+
if (renderedTemplateMetadata === undefined) return null;
|
|
180
|
+
|
|
181
|
+
return <ToolbarInner />;
|
|
182
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { cn } from '../utils';
|
|
4
|
+
|
|
5
|
+
type ContentElement = React.ComponentRef<typeof TooltipPrimitive.Content>;
|
|
6
|
+
type ContentProps = React.ComponentPropsWithoutRef<
|
|
7
|
+
typeof TooltipPrimitive.Content
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
export type TooltipProps = ContentProps;
|
|
11
|
+
|
|
12
|
+
export const TooltipContent = React.forwardRef<
|
|
13
|
+
ContentElement,
|
|
14
|
+
Readonly<TooltipProps>
|
|
15
|
+
>(({ sideOffset = 6, children, ...props }, forwardedRef) => (
|
|
16
|
+
<TooltipPrimitive.Portal>
|
|
17
|
+
<TooltipPrimitive.Content
|
|
18
|
+
{...props}
|
|
19
|
+
className={cn(
|
|
20
|
+
'z-20 rounded-md border border-slate-6 bg-black px-3 py-2 text-white text-xs',
|
|
21
|
+
'font-sans max-w-60',
|
|
22
|
+
)}
|
|
23
|
+
ref={forwardedRef}
|
|
24
|
+
sideOffset={sideOffset}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</TooltipPrimitive.Content>
|
|
28
|
+
</TooltipPrimitive.Portal>
|
|
29
|
+
));
|
|
30
|
+
|
|
31
|
+
TooltipContent.displayName = 'TooltipContent';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
import { TooltipContent } from './tooltip-content';
|
|
4
|
+
|
|
5
|
+
type RootProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root>;
|
|
6
|
+
|
|
7
|
+
export type TooltipProps = RootProps;
|
|
8
|
+
|
|
9
|
+
export const TooltipRoot: React.FC<Readonly<TooltipProps>> = ({
|
|
10
|
+
children,
|
|
11
|
+
...props
|
|
12
|
+
}) => <TooltipPrimitive.Root {...props}>{children}</TooltipPrimitive.Root>;
|
|
13
|
+
|
|
14
|
+
export const Tooltip = Object.assign(TooltipRoot, {
|
|
15
|
+
Arrow: TooltipPrimitive.TooltipArrow,
|
|
16
|
+
Provider: TooltipPrimitive.TooltipProvider,
|
|
17
|
+
Content: TooltipContent,
|
|
18
|
+
Trigger: TooltipPrimitive.TooltipTrigger,
|
|
19
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as ToggleGroup from '@radix-ui/react-toggle-group';
|
|
2
|
+
import { motion } from 'framer-motion';
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
import { tabTransition } from '../../utils/constants';
|
|
5
|
+
import { IconMonitor } from '../icons/icon-monitor';
|
|
6
|
+
import { IconSource } from '../icons/icon-source';
|
|
7
|
+
import { Tooltip } from '../tooltip';
|
|
8
|
+
|
|
9
|
+
interface ActiveViewToggleGroupProps {
|
|
10
|
+
activeView: string;
|
|
11
|
+
setActiveView: (view: string) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ActiveViewToggleGroup = ({
|
|
15
|
+
activeView,
|
|
16
|
+
setActiveView,
|
|
17
|
+
}: ActiveViewToggleGroupProps) => {
|
|
18
|
+
return (
|
|
19
|
+
<ToggleGroup.Root
|
|
20
|
+
aria-label="View mode"
|
|
21
|
+
className="lg:absolute lg:left-1/2 lg:-translate-x-1/2 inline-block items-center bg-slate-2 border border-slate-6 rounded-md overflow-hidden h-[36px]"
|
|
22
|
+
onValueChange={(value) => {
|
|
23
|
+
if (value) setActiveView(value);
|
|
24
|
+
}}
|
|
25
|
+
type="single"
|
|
26
|
+
value={activeView}
|
|
27
|
+
>
|
|
28
|
+
<ToggleGroup.Item value="preview">
|
|
29
|
+
<Tooltip>
|
|
30
|
+
<Tooltip.Trigger asChild>
|
|
31
|
+
<div
|
|
32
|
+
className={cn(
|
|
33
|
+
'w-9 flex items-center py-2 transition ease-in-out duration-200 relative hover:text-slate-12',
|
|
34
|
+
{
|
|
35
|
+
'text-slate-11': activeView !== 'preview',
|
|
36
|
+
'text-slate-12': activeView === 'preview',
|
|
37
|
+
},
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
{activeView === 'preview' && (
|
|
41
|
+
<motion.span
|
|
42
|
+
animate={{ opacity: 1 }}
|
|
43
|
+
className="absolute left-0 right-0 top-0 bottom-0 bg-slate-4"
|
|
44
|
+
exit={{ opacity: 0 }}
|
|
45
|
+
initial={{ opacity: 0 }}
|
|
46
|
+
layoutId="topbar-tabs"
|
|
47
|
+
transition={tabTransition}
|
|
48
|
+
/>
|
|
49
|
+
)}
|
|
50
|
+
<IconMonitor className="m-auto" />
|
|
51
|
+
</div>
|
|
52
|
+
</Tooltip.Trigger>
|
|
53
|
+
<Tooltip.Content>Preview</Tooltip.Content>
|
|
54
|
+
</Tooltip>
|
|
55
|
+
</ToggleGroup.Item>
|
|
56
|
+
<ToggleGroup.Item value="source">
|
|
57
|
+
<Tooltip>
|
|
58
|
+
<Tooltip.Trigger asChild>
|
|
59
|
+
<div
|
|
60
|
+
className={cn(
|
|
61
|
+
'w-9 flex py-2 transition ease-in-out duration-200 relative hover:text-slate-12',
|
|
62
|
+
{
|
|
63
|
+
'text-slate-11': activeView !== 'source',
|
|
64
|
+
'text-slate-12': activeView === 'source',
|
|
65
|
+
},
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
{activeView === 'source' && (
|
|
69
|
+
<motion.span
|
|
70
|
+
animate={{ opacity: 1 }}
|
|
71
|
+
className="absolute left-0 right-0 top-0 bottom-0 bg-slate-4"
|
|
72
|
+
exit={{ opacity: 0 }}
|
|
73
|
+
initial={{ opacity: 0 }}
|
|
74
|
+
layoutId="topbar-tabs"
|
|
75
|
+
transition={tabTransition}
|
|
76
|
+
/>
|
|
77
|
+
)}
|
|
78
|
+
<IconSource className="m-auto" />
|
|
79
|
+
</div>
|
|
80
|
+
</Tooltip.Trigger>
|
|
81
|
+
<Tooltip.Content>Code</Tooltip.Content>
|
|
82
|
+
</Tooltip>
|
|
83
|
+
</ToggleGroup.Item>
|
|
84
|
+
</ToggleGroup.Root>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as Toggle from '@radix-ui/react-toggle';
|
|
2
|
+
import { cn } from '../../utils';
|
|
3
|
+
import { IconMoon } from '../icons/icon-moon';
|
|
4
|
+
import { IconSun } from '../icons/icon-sun';
|
|
5
|
+
import { Tooltip } from '../tooltip';
|
|
6
|
+
|
|
7
|
+
interface EmulatedDarkModeToggleProps {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
onChange: (enabled: boolean) => unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const EmulatedDarkModeToggle = ({
|
|
13
|
+
enabled,
|
|
14
|
+
onChange,
|
|
15
|
+
}: EmulatedDarkModeToggleProps) => {
|
|
16
|
+
return (
|
|
17
|
+
<Tooltip>
|
|
18
|
+
<Tooltip.Trigger asChild>
|
|
19
|
+
<Toggle.Root
|
|
20
|
+
value="dark"
|
|
21
|
+
className={cn(
|
|
22
|
+
'relative w-9 h-9 flex items-center justify-center border border-slate-6 text-sm rounded-lg transition duration-200 ease-in-out',
|
|
23
|
+
'text-slate-11 hover:text-slate-12 aria-pressed:bg-slate-4',
|
|
24
|
+
)}
|
|
25
|
+
pressed={enabled}
|
|
26
|
+
onPressedChange={() => onChange(!enabled)}
|
|
27
|
+
>
|
|
28
|
+
<div className="relative w-5 h-5">
|
|
29
|
+
<div
|
|
30
|
+
className={cn(
|
|
31
|
+
'absolute inset-0 flex items-center justify-center transition-all duration-300 ease-in-out',
|
|
32
|
+
enabled
|
|
33
|
+
? 'opacity-0 scale-50 rotate-90'
|
|
34
|
+
: 'opacity-100 scale-100 rotate-0',
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
<IconMoon />
|
|
38
|
+
</div>
|
|
39
|
+
<div
|
|
40
|
+
className={cn(
|
|
41
|
+
'absolute inset-0 flex items-center justify-center transition-all duration-300 ease-in-out',
|
|
42
|
+
enabled
|
|
43
|
+
? 'opacity-100 scale-100 rotate-0'
|
|
44
|
+
: 'opacity-0 scale-50 -rotate-90',
|
|
45
|
+
)}
|
|
46
|
+
>
|
|
47
|
+
<IconSun />
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</Toggle.Root>
|
|
51
|
+
</Tooltip.Trigger>
|
|
52
|
+
<Tooltip.Content>
|
|
53
|
+
When enabled, inverts colors in the preview to emulate dark mode
|
|
54
|
+
rendering.
|
|
55
|
+
</Tooltip.Content>
|
|
56
|
+
</Tooltip>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import * as Popover from '@radix-ui/react-popover';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
import { IconArrowDown } from '../icons/icon-arrow-down';
|
|
5
|
+
import { Tooltip } from '../tooltip';
|
|
6
|
+
|
|
7
|
+
interface ViewDimensions {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ViewSizeControlsProps {
|
|
13
|
+
minWidth: number;
|
|
14
|
+
minHeight: number;
|
|
15
|
+
viewWidth: number;
|
|
16
|
+
setViewWidth: (width: number) => void;
|
|
17
|
+
viewHeight: number;
|
|
18
|
+
setViewHeight: (height: number) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PresetOption {
|
|
22
|
+
name: string;
|
|
23
|
+
dimensions: ViewDimensions;
|
|
24
|
+
icon: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A4 dimensions in pixels at 96 DPI (standard web resolution)
|
|
29
|
+
* A4 = 210mm × 297mm = 8.27" × 11.69" = 794px × 1123px at 96 DPI
|
|
30
|
+
*/
|
|
31
|
+
const A4_WIDTH = 794;
|
|
32
|
+
const A4_HEIGHT = 1123;
|
|
33
|
+
|
|
34
|
+
export const VIEW_PRESETS: PresetOption[] = [
|
|
35
|
+
{
|
|
36
|
+
name: 'A4',
|
|
37
|
+
dimensions: { width: A4_WIDTH, height: A4_HEIGHT },
|
|
38
|
+
icon: (
|
|
39
|
+
<svg width="15" height="15" viewBox="0 0 15 15" fill="none">
|
|
40
|
+
<path
|
|
41
|
+
d="M3.5 2C3.22386 2 3 2.22386 3 2.5V12.5C3 12.7761 3.22386 13 3.5 13H11.5C11.7761 13 12 12.7761 12 12.5V2.5C12 2.22386 11.7761 2 11.5 2H3.5ZM2 2.5C2 1.67157 2.67157 1 3.5 1H11.5C12.3284 1 13 1.67157 13 2.5V12.5C13 13.3284 12.3284 14 11.5 14H3.5C2.67157 14 2 13.3284 2 12.5V2.5ZM4 3.5C4 3.22386 4.22386 3 4.5 3H10.5C10.7761 3 11 3.22386 11 3.5C11 3.77614 10.7761 4 10.5 4H4.5C4.22386 4 4 3.77614 4 3.5ZM4.5 5C4.22386 5 4 5.22386 4 5.5C4 5.77614 4.22386 6 4.5 6H10.5C10.7761 6 11 5.77614 11 5.5C11 5.22386 10.7761 5 10.5 5H4.5ZM4 7.5C4 7.22386 4.22386 7 4.5 7H10.5C10.7761 7 11 7.22386 11 7.5C11 7.77614 10.7761 8 10.5 8H4.5C4.22386 8 4 7.77614 4 7.5ZM4.5 9C4.22386 9 4 9.22386 4 9.5C4 9.77614 4.22386 10 4.5 10H10.5C10.7761 10 11 9.77614 11 9.5C11 9.22386 10.7761 9 10.5 9H4.5Z"
|
|
42
|
+
fill="currentColor"
|
|
43
|
+
fillRule="evenodd"
|
|
44
|
+
clipRule="evenodd"
|
|
45
|
+
/>
|
|
46
|
+
</svg>
|
|
47
|
+
),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Desktop',
|
|
51
|
+
dimensions: { width: 1024, height: 600 },
|
|
52
|
+
icon: (
|
|
53
|
+
<svg width="15" height="15" viewBox="0 0 15 15" fill="none">
|
|
54
|
+
<path
|
|
55
|
+
d="M1 3.25C1 3.11193 1.11193 3 1.25 3H13.75C13.8881 3 14 3.11193 14 3.25V10.75C14 10.8881 13.8881 11 13.75 11H1.25C1.11193 11 1 10.8881 1 10.75V3.25ZM1.25 2C0.559643 2 0 2.55964 0 3.25V10.75C0 11.4404 0.559644 12 1.25 12H5.07341L4.82991 13.2986C4.76645 13.6371 5.02612 13.95 5.37049 13.95H9.62951C9.97389 13.95 10.2336 13.6371 10.1701 13.2986L9.92659 12H13.75C14.4404 12 15 11.4404 15 10.75V3.25C15 2.55964 14.4404 2 13.75 2H1.25ZM9.01091 12H5.98909L5.79222 13.05H9.20778L9.01091 12Z"
|
|
56
|
+
fill="currentColor"
|
|
57
|
+
fillRule="evenodd"
|
|
58
|
+
clipRule="evenodd"
|
|
59
|
+
/>
|
|
60
|
+
</svg>
|
|
61
|
+
),
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
export const ViewSizeControls = ({
|
|
66
|
+
minWidth,
|
|
67
|
+
minHeight,
|
|
68
|
+
viewWidth,
|
|
69
|
+
viewHeight,
|
|
70
|
+
setViewWidth,
|
|
71
|
+
setViewHeight,
|
|
72
|
+
}: ViewSizeControlsProps) => {
|
|
73
|
+
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
|
|
74
|
+
const [internalWidth, setInternalWidth] = React.useState(viewWidth);
|
|
75
|
+
const [internalHeight, setInternalHeight] = React.useState(viewHeight);
|
|
76
|
+
|
|
77
|
+
const handlePresetSelect = (dimensions: ViewDimensions) => {
|
|
78
|
+
setViewWidth(dimensions.width);
|
|
79
|
+
setViewHeight(dimensions.height);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
React.useEffect(() => {
|
|
83
|
+
setInternalWidth(viewWidth);
|
|
84
|
+
setInternalHeight(viewHeight);
|
|
85
|
+
}, [viewWidth, viewHeight]);
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div className="relative flex h-9 w-fit overflow-hidden rounded-lg border border-slate-6 text-sm transition-colors duration-300 ease-in-out">
|
|
89
|
+
{VIEW_PRESETS.map((preset) => (
|
|
90
|
+
<Tooltip key={preset.name}>
|
|
91
|
+
<Tooltip.Trigger asChild>
|
|
92
|
+
<button
|
|
93
|
+
key={preset.name}
|
|
94
|
+
onClick={() => handlePresetSelect(preset.dimensions)}
|
|
95
|
+
className={cn(
|
|
96
|
+
'relative flex items-center justify-center w-9 transition-colors hover:text-slate-12',
|
|
97
|
+
{
|
|
98
|
+
'bg-slate-4': viewWidth === preset.dimensions.width,
|
|
99
|
+
},
|
|
100
|
+
)}
|
|
101
|
+
type="button"
|
|
102
|
+
>
|
|
103
|
+
{preset.icon}
|
|
104
|
+
</button>
|
|
105
|
+
</Tooltip.Trigger>
|
|
106
|
+
<Tooltip.Content>{preset.name}</Tooltip.Content>
|
|
107
|
+
</Tooltip>
|
|
108
|
+
))}
|
|
109
|
+
|
|
110
|
+
<Popover.Root open={isDropdownOpen} onOpenChange={setIsDropdownOpen}>
|
|
111
|
+
<Popover.Trigger asChild>
|
|
112
|
+
<button
|
|
113
|
+
type="button"
|
|
114
|
+
className="relative flex items-center justify-center overflow-hidden w-9 text-slate-11 text-sm leading-none outline-hidden transition-colors ease-linear focus-within:text-slate-12 hover:text-slate-12 focus:text-slate-12"
|
|
115
|
+
>
|
|
116
|
+
<span className="sr-only">View presets</span>
|
|
117
|
+
<IconArrowDown
|
|
118
|
+
className={cn(
|
|
119
|
+
'transform transition-transform duration-200 ease-[cubic-bezier(.36,.66,.6,1)]',
|
|
120
|
+
{
|
|
121
|
+
'-rotate-180': isDropdownOpen,
|
|
122
|
+
},
|
|
123
|
+
)}
|
|
124
|
+
/>
|
|
125
|
+
</button>
|
|
126
|
+
</Popover.Trigger>
|
|
127
|
+
<Popover.Portal>
|
|
128
|
+
<Popover.Content
|
|
129
|
+
align="end"
|
|
130
|
+
className="flex min-w-48 flex-col gap-2 rounded-md border border-slate-8 border-solid bg-black px-2 py-2 text-white"
|
|
131
|
+
sideOffset={5}
|
|
132
|
+
>
|
|
133
|
+
<div className="flex w-full items-center justify-between text-sm gap-2">
|
|
134
|
+
<span className="font-medium text-slate-11 text-xs">Width</span>
|
|
135
|
+
<input
|
|
136
|
+
type="number"
|
|
137
|
+
value={internalWidth}
|
|
138
|
+
onChange={(e) => {
|
|
139
|
+
const value = Number(e.target.value);
|
|
140
|
+
|
|
141
|
+
setInternalWidth(value);
|
|
142
|
+
|
|
143
|
+
if (value >= minWidth) {
|
|
144
|
+
setViewWidth(value);
|
|
145
|
+
}
|
|
146
|
+
}}
|
|
147
|
+
className="w-20 appearance-none rounded-lg border border-slate-6 bg-slate-5 px-1 py-1 text-sm text-slate-12 placeholder-slate-10 outline-hidden transition duration-300 ease-in-out focus:ring-1 focus:ring-slate-10"
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div className="flex w-full items-center justify-between text-sm gap-2">
|
|
152
|
+
<span className="font-medium text-slate-11 text-xs">Height</span>
|
|
153
|
+
<input
|
|
154
|
+
type="number"
|
|
155
|
+
value={internalHeight}
|
|
156
|
+
onChange={(e) => {
|
|
157
|
+
const value = Number(e.target.value);
|
|
158
|
+
|
|
159
|
+
setInternalHeight(value);
|
|
160
|
+
|
|
161
|
+
if (value >= minHeight) {
|
|
162
|
+
setViewHeight(value);
|
|
163
|
+
}
|
|
164
|
+
}}
|
|
165
|
+
className="w-20 appearance-none rounded-lg border border-slate-6 bg-slate-5 px-1 py-1 text-sm text-slate-12 placeholder-slate-10 outline-hidden transition duration-300 ease-in-out focus:ring-1 focus:ring-slate-10"
|
|
166
|
+
/>
|
|
167
|
+
</div>
|
|
168
|
+
</Popover.Content>
|
|
169
|
+
</Popover.Portal>
|
|
170
|
+
</Popover.Root>
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
};
|