From 87cd5553547b764449229fd02675ae427f957b48 Mon Sep 17 00:00:00 2001 From: RaviTejaKNTS Date: Tue, 13 Oct 2026 18:49:43 +0530 Subject: [PATCH] Add per-page sidebar positions and flatten tool folders - AppShell takes sidebarPosition: left (default), right, or none, with width, mobile, print, and consent banner rules for each. Dev-only previews at /components-ui/sidebar-modes/[position]. - Homepage, keyboard shortcuts pages, domain status codes, and the TLD directory now have no sidebar. Tools and catalogs stay on the left. - Keyboard shortcuts directory lists apps as compact cards with the shortcut count and supported platforms. - DNS, domain, storage, and SaaS tools move out of their route groups into flat app/(site)/(tools)// folders. Shared DNS and domain code moves to app/ui/tools/. Family CSS loads only on pages that use it. - Cheat sheet generator: controls no longer stretch, the sheet fits its column, and a cancelled initial load no longer throws an AbortError. - Docs and the page-build skill describe the sidebar positions and prefer left. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 2 +- app/(site)/(catalogs)/layout.tsx | 7 - .../components-ui/examples/page-layout.tsx | 16 +- .../sidebar-modes/[position]/layout.tsx | 7 + .../sidebar-modes/[position]/page.tsx | 87 ++ .../(directories)/epp-status-codes/page.tsx | 12 +- .../keyboard-shortcuts/(index)/page.tsx | 8 +- .../keyboard-shortcuts-app-page.tsx | 8 +- .../keyboard-shortcuts-directory.tsx | 52 +- .../keyboard-shortcuts.module.css | 40 +- .../(directories)/tld-directory/page.tsx | 10 +- .../(directories)/tld-directory/tld-table.tsx | 2 +- app/(site)/(site-pages)/(home)/page.tsx | 53 +- app/(site)/(tools)/(dns)/layout.tsx | 6 - .../(tools)/(domain)/domain-tools-sidebar.tsx | 5 - app/(site)/(tools)/(domain)/layout.tsx | 6 - app/(site)/(tools)/(storage)/layout.tsx | 5 - .../(storage)/storage-tools.module.css | 777 ------------------ ...annual-plan-discount-calculator.module.css | 0 .../annual-plan-discount-calculator.tsx | 0 .../annual-plan-discount-calculator.spec.json | 0 .../art/annual-plan-discount-calculator.svg | 0 .../art/annual-plan-discount-calculator.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../layout.tsx | 0 .../annual-plan-discount-calculator/page.tsx | 0 .../arpu-arpa-calculator.module.css | 0 .../arpu-arpa-calculator.tsx | 0 .../arpu-arpa-calculator/content/article.mdx | 0 .../arpu-arpa-calculator/content/intro.mdx | 0 .../arpu-arpa-calculator/content/usage.mdx | 0 .../arpu-arpa-calculator/layout.tsx | 0 .../arpu-arpa-calculator/page.tsx | 0 .../arr-calculator/arr-calculator.module.css | 0 .../arr-calculator/arr-calculator.tsx | 0 .../arr-calculator/content/article.mdx | 0 .../arr-calculator/content/intro.mdx | 0 .../arr-calculator/content/usage.mdx | 0 .../{(saas) => }/arr-calculator/layout.tsx | 0 .../{(saas) => }/arr-calculator/page.tsx | 0 .../backup-321-calculator-from-url.tsx | 0 .../backup-321-calculator.module.css | 0 .../backup-321-calculator.tsx | 0 .../backup-321-calculator/content/article.mdx | 0 .../backup-321-calculator/content/intro.mdx | 0 .../backup-321-calculator/content/usage.mdx | 0 .../backup-321-calculator/layout.tsx | 0 .../backup-321-calculator/page.tsx | 2 +- .../art/break-even-mrr-calculator.spec.json | 0 .../art/break-even-mrr-calculator.svg | 0 .../art/break-even-mrr-calculator.ts | 0 .../break-even-mrr-calculator.module.css | 0 .../break-even-mrr-calculator.tsx | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../break-even-mrr-calculator/layout.tsx | 0 .../break-even-mrr-calculator/page.tsx | 0 .../burn-multiple-calculator.module.css | 0 .../burn-multiple-calculator.tsx | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../burn-multiple-calculator/layout.tsx | 0 .../burn-multiple-calculator/page.tsx | 0 .../caa-checker/caa-checker-from-url.tsx | 0 .../caa-checker/caa-checker.module.css | 0 .../{(dns) => }/caa-checker/caa-checker.tsx | 2 +- .../caa-checker/content/article.mdx | 0 .../{(dns) => }/caa-checker/content/intro.mdx | 0 .../{(dns) => }/caa-checker/content/usage.mdx | 0 .../{(dns) => }/caa-checker/layout.tsx | 0 .../(tools)/{(dns) => }/caa-checker/page.tsx | 2 +- .../art/cac-payback-calculator.spec.json | 0 .../art/cac-payback-calculator.svg | 0 .../art/cac-payback-calculator.ts | 0 .../cac-payback-calculator.module.css | 0 .../cac-payback-calculator.tsx | 0 .../content/article.mdx | 0 .../cac-payback-calculator/content/intro.mdx | 0 .../cac-payback-calculator/content/usage.mdx | 0 .../cac-payback-calculator/layout.tsx | 0 .../cac-payback-calculator/page.tsx | 0 .../ceph-capacity-calculator-from-url.tsx | 0 .../ceph-capacity-calculator.module.css | 0 .../ceph-capacity-calculator.tsx | 0 .../ceph-capacity-engine.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../ceph-capacity-calculator/layout.tsx | 0 .../ceph-capacity-calculator/page.tsx | 2 +- .../art/churn-rate-converter.spec.json | 0 .../art/churn-rate-converter.svg | 0 .../art/churn-rate-converter.ts | 0 .../churn-rate-converter.module.css | 0 .../churn-rate-converter.tsx | 0 .../churn-rate-converter/content/article.mdx | 0 .../churn-rate-converter/content/intro.mdx | 0 .../churn-rate-converter/content/usage.mdx | 0 .../churn-rate-converter/layout.tsx | 0 .../churn-rate-converter/page.tsx | 0 ...omer-acquisition-cost-calculator.spec.json | 0 .../customer-acquisition-cost-calculator.svg | 0 .../customer-acquisition-cost-calculator.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 ...mer-acquisition-cost-calculator.module.css | 0 .../customer-acquisition-cost-calculator.tsx | 0 .../layout.tsx | 0 .../page.tsx | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../customer-churn-calculator.module.css | 0 .../customer-churn-calculator.tsx | 0 .../customer-churn-calculator/layout.tsx | 0 .../customer-churn-calculator/page.tsx | 0 ...stomer-lifetime-value-calculator.spec.json | 0 .../customer-lifetime-value-calculator.svg | 0 .../art/customer-lifetime-value-calculator.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 ...tomer-lifetime-value-calculator.module.css | 0 .../customer-lifetime-value-calculator.tsx | 0 .../layout.tsx | 0 .../page.tsx | 0 .../dns-change-checker/content/article.mdx | 0 .../dns-change-checker/content/intro.mdx | 0 .../dns-change-checker/content/usage.mdx | 0 .../dns-change-checker-from-url.tsx | 0 .../dns-change-checker.module.css | 0 .../dns-change-checker/dns-change-checker.tsx | 2 +- .../{(dns) => }/dns-change-checker/layout.tsx | 0 .../{(dns) => }/dns-change-checker/page.tsx | 0 .../dns-lookup/content/article.mdx | 0 .../{(dns) => }/dns-lookup/content/intro.mdx | 0 .../{(dns) => }/dns-lookup/content/usage.mdx | 0 .../dns-lookup/dns-lookup-content.module.css | 0 .../dns-lookup/dns-lookup-from-url.tsx | 0 .../dns-lookup/dns-lookup-tool.tsx | 0 .../(tools)/{(dns) => }/dns-lookup/layout.tsx | 0 .../(tools)/{(dns) => }/dns-lookup/page.tsx | 1 + .../{(dns) => }/dns-trace/content/article.mdx | 0 .../{(dns) => }/dns-trace/content/intro.mdx | 0 .../{(dns) => }/dns-trace/content/usage.mdx | 0 .../{(dns) => }/dns-trace/dns-trace-format.ts | 0 .../dns-trace/dns-trace-from-url.tsx | 0 .../{(dns) => }/dns-trace/dns-trace-tool.tsx | 0 .../dns-trace/dns-trace.module.css | 0 .../(tools)/{(dns) => }/dns-trace/layout.tsx | 0 .../(tools)/{(dns) => }/dns-trace/page.tsx | 0 .../dnssec-checker/content/article.mdx | 0 .../dnssec-checker/content/intro.mdx | 0 .../dnssec-checker/content/usage.mdx | 0 .../dnssec-checker-from-url.tsx | 0 .../dnssec-checker/dnssec-checker.module.css | 0 .../dnssec-checker/dnssec-checker.tsx | 2 +- .../{(dns) => }/dnssec-checker/layout.tsx | 0 .../{(dns) => }/dnssec-checker/page.tsx | 0 .../domain-age/content/article.mdx | 0 .../domain-age/content/intro.mdx | 0 .../domain-age/content/usage.mdx | 0 .../domain-age/domain-age-content.module.css | 0 .../domain-age/domain-age-from-url.tsx | 0 .../domain-age/domain-age-tool.module.css | 0 .../domain-age/domain-age-tool.tsx | 2 +- .../{(domain) => }/domain-age/layout.tsx | 0 .../{(domain) => }/domain-age/page.tsx | 1 + .../domain-availability/content/article.mdx | 0 .../domain-availability/content/intro.mdx | 0 .../domain-availability/content/usage.mdx | 0 .../domain-availability-from-url.tsx | 0 .../domain-availability-tool.module.css | 0 .../domain-availability-tool.tsx | 0 .../domain-availability-view.ts | 2 +- .../domain-availability/layout.tsx | 0 .../domain-availability/page.tsx | 1 + .../domain-expiry/content/article.mdx | 0 .../domain-expiry/content/intro.mdx | 0 .../domain-expiry/content/usage.mdx | 0 .../domain-expiry/domain-expiry-from-url.tsx | 0 .../domain-expiry-tool.module.css | 0 .../domain-expiry/domain-expiry-tool.tsx | 2 +- .../{(domain) => }/domain-expiry/layout.tsx | 0 .../{(domain) => }/domain-expiry/page.tsx | 1 + .../domain-lookup/content/article.mdx | 0 .../domain-lookup/content/intro.mdx | 0 .../domain-lookup/content/usage.mdx | 0 .../domain-lookup/domain-lookup-from-url.tsx | 0 .../domain-lookup-tool.module.css | 0 .../domain-lookup/domain-lookup-tool.tsx | 0 .../domain-lookup/domain-lookup-view.ts | 4 +- .../{(domain) => }/domain-lookup/layout.tsx | 0 .../{(domain) => }/domain-lookup/page.tsx | 1 + .../domain-owner/content/article.mdx | 0 .../domain-owner/content/intro.mdx | 0 .../domain-owner/content/usage.mdx | 0 .../domain-owner/domain-owner-from-url.tsx | 0 .../domain-owner/domain-owner-tool.module.css | 0 .../domain-owner/domain-owner-tool.tsx | 0 .../domain-owner/domain-owner-view.ts | 4 +- .../{(domain) => }/domain-owner/layout.tsx | 0 .../{(domain) => }/domain-owner/page.tsx | 1 + .../domain-registrar/content/article.mdx | 0 .../domain-registrar/content/intro.mdx | 0 .../domain-registrar/content/usage.mdx | 0 .../domain-registrar-from-url.tsx | 0 .../domain-registrar-tool.module.css | 0 .../domain-registrar-tool.tsx | 0 .../domain-registrar/domain-registrar-view.ts | 2 +- .../domain-registrar/layout.tsx | 0 .../{(domain) => }/domain-registrar/page.tsx | 1 + .../domain-report/content/article.mdx | 0 .../domain-report/content/intro.mdx | 0 .../domain-report/content/usage.mdx | 0 .../domain-report/domain-report-from-url.tsx | 0 .../domain-report-tool.module.css | 0 .../domain-report/domain-report-tool.tsx | 0 .../domain-report/domain-report-view.ts | 2 +- .../{(domain) => }/domain-report/layout.tsx | 0 .../{(domain) => }/domain-report/page.tsx | 1 + .../drive-reliability/content/article.mdx | 0 .../drive-reliability/content/intro.mdx | 0 .../drive-reliability/content/usage.mdx | 0 .../data/drive-reliability-snapshot.json | 0 .../drive-reliability-from-url.tsx | 0 .../drive-reliability.module.css | 0 .../drive-reliability/drive-reliability.tsx | 0 .../drive-reliability/layout.tsx | 0 .../drive-reliability/page.tsx | 2 +- ...free-trial-conversion-calculator.spec.json | 0 .../art/free-trial-conversion-calculator.svg | 0 .../art/free-trial-conversion-calculator.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 ...e-trial-conversion-calculator-from-url.tsx | 0 ...ree-trial-conversion-calculator.module.css | 0 .../free-trial-conversion-calculator.tsx | 0 .../layout.tsx | 0 .../free-trial-conversion-calculator/page.tsx | 0 .../published-figures.ts | 0 .../art/ltv-cac-calculator.spec.json | 0 .../art/ltv-cac-calculator.svg | 0 .../art/ltv-cac-calculator.ts | 0 .../ltv-cac-calculator/content/article.mdx | 0 .../ltv-cac-calculator/content/intro.mdx | 0 .../ltv-cac-calculator/content/usage.mdx | 0 .../ltv-cac-calculator/layout.tsx | 0 .../ltv-cac-calculator.module.css | 0 .../ltv-cac-calculator/ltv-cac-calculator.tsx | 0 .../{(saas) => }/ltv-cac-calculator/page.tsx | 0 .../mrr-calculator/content/article.mdx | 0 .../mrr-calculator/content/intro.mdx | 0 .../mrr-calculator/content/usage.mdx | 0 .../{(saas) => }/mrr-calculator/layout.tsx | 0 .../mrr-calculator/mrr-calculator.module.css | 0 .../mrr-calculator/mrr-calculator.tsx | 0 .../{(saas) => }/mrr-calculator/page.tsx | 0 .../art/mrr-goal-calculator.spec.json | 0 .../art/mrr-goal-calculator.svg | 0 .../art/mrr-goal-calculator.ts | 0 .../mrr-goal-calculator/content/article.mdx | 0 .../mrr-goal-calculator/content/intro.mdx | 0 .../mrr-goal-calculator/content/usage.mdx | 0 .../mrr-goal-calculator/layout.tsx | 0 .../mrr-goal-calculator.module.css | 0 .../mrr-goal-calculator.tsx | 0 .../{(saas) => }/mrr-goal-calculator/page.tsx | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../mrr-waterfall-calculator/layout.tsx | 0 .../mrr-waterfall-calculator.module.css | 0 .../mrr-waterfall-calculator.tsx | 0 .../mrr-waterfall-calculator/page.tsx | 0 .../content/article.mdx | 0 .../multi-tld-availability/content/intro.mdx | 0 .../multi-tld-availability/content/usage.mdx | 0 .../multi-tld-availability/layout.tsx | 0 .../multi-tld-tool.module.css | 0 .../multi-tld-availability/multi-tld-tool.tsx | 0 .../multi-tld-availability/multi-tld-view.ts | 2 +- .../multi-tld-availability/page.tsx | 1 + .../nameserver-checker/content/article.mdx | 0 .../nameserver-checker/content/intro.mdx | 0 .../nameserver-checker/content/usage.mdx | 0 .../{(dns) => }/nameserver-checker/layout.tsx | 0 .../nameserver-checker-from-url.tsx | 0 .../nameserver-checker-view.ts | 2 +- .../nameserver-checker.module.css | 0 .../nameserver-checker/nameserver-checker.tsx | 2 +- .../{(dns) => }/nameserver-checker/page.tsx | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../layout.tsx | 0 ...et-revenue-retention-calculator.module.css | 0 .../net-revenue-retention-calculator.tsx | 0 .../net-revenue-retention-calculator/page.tsx | 0 .../punycode-converter/content/article.mdx | 0 .../punycode-converter/content/intro.mdx | 0 .../punycode-converter/content/usage.mdx | 0 .../punycode-converter/layout.tsx | 0 .../punycode-converter/page.tsx | 1 + .../punycode-tool.module.css | 0 .../punycode-converter/punycode-tool.tsx | 0 .../punycode-converter/punycode-view.ts | 4 +- .../raid-calculator/content/article.mdx | 0 .../raid-calculator/content/intro.mdx | 0 .../raid-calculator/content/usage.mdx | 0 .../raid-calculator/layout.tsx | 0 .../{(storage) => }/raid-calculator/page.tsx | 2 +- .../raid-calculator-from-url.tsx | 0 .../raid-calculator.module.css | 0 .../raid-calculator/raid-calculator.tsx | 0 .../content/article.mdx | 0 .../raidz-expansion-planner/content/intro.mdx | 0 .../raidz-expansion-planner/content/usage.mdx | 0 .../raidz-expansion-planner/layout.tsx | 0 .../raidz-expansion-planner/page.tsx | 2 +- .../raidz-expansion-planner-from-url.tsx | 0 .../raidz-expansion-planner.module.css | 0 .../raidz-expansion-planner.tsx | 0 .../rebuild-calculator/content/article.mdx | 0 .../rebuild-calculator/content/intro.mdx | 0 .../rebuild-calculator/content/usage.mdx | 0 .../rebuild-calculator/layout.tsx | 0 .../rebuild-calculator/page.tsx | 2 +- .../rebuild-calculator.module.css | 0 .../rebuild-calculator/rebuild-calculator.tsx | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../revenue-churn-calculator/layout.tsx | 0 .../revenue-churn-calculator/page.tsx | 0 .../revenue-churn-calculator.module.css | 0 .../revenue-churn-calculator.tsx | 0 .../saas-gross-margin-calculator.spec.json | 0 .../art/saas-gross-margin-calculator.svg | 0 .../art/saas-gross-margin-calculator.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../saas-gross-margin-calculator/layout.tsx | 0 .../saas-gross-margin-calculator/page.tsx | 0 .../saas-gross-margin-calculator.module.css | 0 .../saas-gross-margin-calculator.tsx | 0 .../art/saas-metrics-calculator.spec.json | 0 .../art/saas-metrics-calculator.svg | 0 .../art/saas-metrics-calculator.ts | 0 .../content/article.mdx | 0 .../saas-metrics-calculator/content/intro.mdx | 0 .../saas-metrics-calculator/content/usage.mdx | 0 .../saas-metrics-calculator/layout.tsx | 0 .../saas-metrics-calculator/page.tsx | 0 .../saas-metrics-calculator.module.css | 0 .../saas-metrics-calculator.tsx | 0 .../shortcuts-cheatsheet-generator.module.css | 4 +- .../shortcuts-cheatsheet-generator.tsx | 17 +- .../shr-calculator/content/article.mdx | 0 .../shr-calculator/content/intro.mdx | 0 .../shr-calculator/content/usage.mdx | 0 .../{(storage) => }/shr-calculator/layout.tsx | 0 .../{(storage) => }/shr-calculator/page.tsx | 2 +- .../shr-calculator-from-url.tsx | 0 .../shr-calculator/shr-calculator.module.css | 0 .../shr-calculator/shr-calculator.tsx | 0 .../shr-calculator/shr-capacity.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../snapraid-mergerfs-planner/layout.tsx | 0 .../snapraid-mergerfs-planner/page.tsx | 2 +- .../snapraid-merfs-engine.ts | 0 .../snapraid-mergerfs-planner.module.css | 0 .../snapraid-mergerfs-planner.tsx | 0 .../soa-checker/content/article.mdx | 0 .../{(dns) => }/soa-checker/content/intro.mdx | 0 .../{(dns) => }/soa-checker/content/usage.mdx | 0 .../{(dns) => }/soa-checker/layout.tsx | 0 .../(tools)/{(dns) => }/soa-checker/page.tsx | 0 .../soa-checker/soa-checker-from-url.tsx | 0 .../soa-checker/soa-checker-view.ts | 6 +- .../soa-checker/soa-checker.module.css | 0 .../{(dns) => }/soa-checker/soa-checker.tsx | 2 +- .../art/startup-runway-calculator.spec.json | 0 .../art/startup-runway-calculator.svg | 0 .../art/startup-runway-calculator.ts | 0 .../content/article.mdx | 0 .../content/intro.mdx | 0 .../content/usage.mdx | 0 .../startup-runway-calculator/layout.tsx | 0 .../startup-runway-calculator/page.tsx | 0 .../startup-runway-calculator.module.css | 0 .../startup-runway-calculator.tsx | 0 .../content/article.mdx | 0 .../storage-growth-planner/content/intro.mdx | 0 .../storage-growth-planner/content/usage.mdx | 0 .../storage-growth-planner/layout.tsx | 0 .../storage-growth-planner/page.tsx | 2 +- .../storage-growth-planner-engine.ts | 0 .../storage-growth-planner-from-url.tsx | 0 .../storage-growth-planner.module.css | 0 .../storage-growth-planner.tsx | 0 .../content/article.mdx | 0 .../storage-layout-advisor/content/intro.mdx | 0 .../storage-layout-advisor/content/usage.mdx | 0 .../storage-layout-advisor/layout.tsx | 0 .../storage-layout-advisor/page.tsx | 2 +- .../storage-layout-advisor-engine.ts | 2 +- .../storage-layout-advisor-from-url.tsx | 0 .../storage-layout-advisor.module.css | 0 .../storage-layout-advisor.tsx | 2 +- .../transfer-readiness/content/article.mdx | 0 .../transfer-readiness/content/intro.mdx | 0 .../transfer-readiness/content/usage.mdx | 0 .../transfer-readiness/layout.tsx | 0 .../transfer-readiness/page.tsx | 1 + .../transfer-readiness-from-url.tsx | 0 .../transfer-readiness-tool.module.css | 0 .../transfer-readiness-tool.tsx | 0 .../transfer-readiness-view.ts | 2 +- .../unraid-calculator/content/article.mdx | 0 .../unraid-calculator/content/intro.mdx | 0 .../unraid-calculator/content/usage.mdx | 0 .../unraid-calculator/layout.tsx | 0 .../unraid-calculator/page.tsx | 2 +- .../unraid-calculator-engine.ts | 8 +- .../unraid-calculator-from-url.tsx | 0 .../unraid-calculator.module.css | 0 .../unraid-calculator/unraid-calculator.tsx | 0 .../content/article.mdx | 0 .../zfs-capacity-calculator/content/intro.mdx | 0 .../zfs-capacity-calculator/content/usage.mdx | 0 .../zfs-capacity-calculator/layout.tsx | 0 .../zfs-capacity-calculator/page.tsx | 2 +- .../zfs-capacity-calculator-from-url.tsx | 0 .../zfs-capacity-calculator.module.css | 0 .../zfs-capacity-calculator.tsx | 0 .../content/article.mdx | 0 .../zfs-padding-calculator/content/intro.mdx | 0 .../zfs-padding-calculator/content/usage.mdx | 0 .../zfs-padding-calculator/layout.tsx | 0 .../zfs-padding-calculator/page.tsx | 2 +- .../zfs-padding-calculator-from-url.tsx | 0 .../zfs-padding-calculator.module.css | 0 .../zfs-padding-calculator.tsx | 0 app/(site)/home.css | 5 - .../keyboard-shortcuts-sidebar.module.css | 21 - .../keyboard-shortcuts-sidebar.tsx | 88 -- app/ui/site/app-shell.module.css | 58 +- app/ui/site/app-shell.tsx | 87 +- .../site/google-analytics-consent.module.css | 14 +- app/ui/site/page-canvas.module.css | 5 + .../tools/dns}/diagnostic-result-ui.tsx | 0 .../tools/dns}/dns-diagnostics.module.css | 0 .../(dns) => ui/tools/dns}/dns-tools.css | 0 .../tools/domain}/domain-lookup-client.tsx | 0 .../tools/domain}/domain-tools.css | 0 app/ui/tools/tool-family-sidebar.tsx | 38 - .../tool-spec.md | 4 +- .../arpu-arpa-calculator/tool-spec.md | 2 +- content_docs/arr-calculator/tool-spec.md | 2 +- .../break-even-mrr-calculator/tool-spec.md | 4 +- .../burn-multiple-calculator/tool-spec.md | 2 +- .../cac-payback-calculator/tool-spec.md | 4 +- content_docs/churn-rate-converter/research.md | 2 +- .../churn-rate-converter/tool-spec.md | 4 +- .../tool-spec.md | 4 +- .../customer-churn-calculator/tool-spec.md | 2 +- .../tool-spec.md | 4 +- content_docs/domain-tools/README.md | 2 +- .../research.md | 2 +- .../tool-spec.md | 2 +- content_docs/keyboard-shortcuts/brief.md | 6 +- content_docs/ltv-cac-calculator/tool-spec.md | 4 +- content_docs/mrr-calculator/tool-spec.md | 2 +- content_docs/mrr-goal-calculator/tool-spec.md | 4 +- .../mrr-waterfall-calculator/tool-spec.md | 2 +- .../tool-spec.md | 2 +- content_docs/raid-calculator/README.md | 2 +- .../revenue-churn-calculator/tool-spec.md | 2 +- .../saas-gross-margin-calculator/tool-spec.md | 2 +- .../saas-metrics-calculator/tool-spec.md | 2 +- .../startup-runway-calculator/tool-spec.md | 4 +- content_docs/tld-directory/README.md | 2 +- lib/card-art.ts | 24 +- lib/registered-site-pages.json | 1 + .../drive-reliability/refresh-snapshot.mjs | 2 +- skills/stack127/page-build/SKILL.md | 2 +- stack127_docs/css-architecture.md | 15 +- stack127_docs/design-system.md | 27 +- stack127_docs/page-families.md | 10 +- stack127_docs/page-publishing.md | 2 +- stack127_docs/repo-structure.md | 2 +- stack127_docs/shared-ui.md | 2 +- .../ceph-capacity-calculator.test.mjs | 2 +- .../drive-reliability.test.mjs | 2 +- .../shr-calculator/shr-capacity.test.mjs | 2 +- .../snapraid-merfs-engine.test.mjs | 2 +- .../storage-growth-planner-engine.test.mjs | 2 +- .../storage-growth-planner-state.test.mjs | 2 +- .../storage-layout-advisor.test.mjs | 2 +- .../unraid-calculator.test.mjs | 2 +- 510 files changed, 469 insertions(+), 1243 deletions(-) delete mode 100644 app/(site)/(catalogs)/layout.tsx create mode 100644 app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/layout.tsx create mode 100644 app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/page.tsx delete mode 100644 app/(site)/(tools)/(dns)/layout.tsx delete mode 100644 app/(site)/(tools)/(domain)/domain-tools-sidebar.tsx delete mode 100644 app/(site)/(tools)/(domain)/layout.tsx delete mode 100644 app/(site)/(tools)/(storage)/layout.tsx delete mode 100644 app/(site)/(tools)/(storage)/storage-tools.module.css rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/annual-plan-discount-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/annual-plan-discount-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/art/annual-plan-discount-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/art/annual-plan-discount-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/art/annual-plan-discount-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/annual-plan-discount-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/arpu-arpa-calculator/arpu-arpa-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/arpu-arpa-calculator/arpu-arpa-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/arpu-arpa-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/arpu-arpa-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/arpu-arpa-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/arpu-arpa-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/arpu-arpa-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/arr-calculator/arr-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/arr-calculator/arr-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/arr-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/arr-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/arr-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/arr-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/arr-calculator/page.tsx (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/backup-321-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/backup-321-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/backup-321-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/backup-321-calculator/page.tsx (94%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/art/break-even-mrr-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/art/break-even-mrr-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/art/break-even-mrr-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/break-even-mrr-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/break-even-mrr-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/break-even-mrr-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/burn-multiple-calculator/burn-multiple-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/burn-multiple-calculator/burn-multiple-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/burn-multiple-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/burn-multiple-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/burn-multiple-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/burn-multiple-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/burn-multiple-calculator/page.tsx (100%) rename app/(site)/(tools)/{(dns) => }/caa-checker/caa-checker-from-url.tsx (100%) rename app/(site)/(tools)/{(dns) => }/caa-checker/caa-checker.module.css (100%) rename app/(site)/(tools)/{(dns) => }/caa-checker/caa-checker.tsx (99%) rename app/(site)/(tools)/{(dns) => }/caa-checker/content/article.mdx (100%) rename app/(site)/(tools)/{(dns) => }/caa-checker/content/intro.mdx (100%) rename app/(site)/(tools)/{(dns) => }/caa-checker/content/usage.mdx (100%) rename app/(site)/(tools)/{(dns) => }/caa-checker/layout.tsx (100%) rename app/(site)/(tools)/{(dns) => }/caa-checker/page.tsx (92%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/art/cac-payback-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/art/cac-payback-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/art/cac-payback-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/cac-payback-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/cac-payback-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/cac-payback-calculator/page.tsx (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/ceph-capacity-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/ceph-capacity-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/ceph-capacity-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/ceph-capacity-engine.ts (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/ceph-capacity-calculator/page.tsx (94%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/art/churn-rate-converter.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/art/churn-rate-converter.svg (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/art/churn-rate-converter.ts (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/churn-rate-converter.module.css (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/churn-rate-converter.tsx (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/churn-rate-converter/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-acquisition-cost-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-churn-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-churn-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-churn-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-churn-calculator/customer-churn-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/customer-churn-calculator/customer-churn-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-churn-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-churn-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/customer-lifetime-value-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/customer-lifetime-value-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/customer-lifetime-value-calculator/page.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/content/article.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/content/intro.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/content/usage.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/dns-change-checker-from-url.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/dns-change-checker.module.css (100%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/dns-change-checker.tsx (99%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/layout.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-change-checker/page.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/content/article.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/content/intro.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/content/usage.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/dns-lookup-content.module.css (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/dns-lookup-from-url.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/dns-lookup-tool.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/layout.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-lookup/page.tsx (96%) rename app/(site)/(tools)/{(dns) => }/dns-trace/content/article.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/content/intro.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/content/usage.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/dns-trace-format.ts (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/dns-trace-from-url.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/dns-trace-tool.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/dns-trace.module.css (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/layout.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dns-trace/page.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/content/article.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/content/intro.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/content/usage.mdx (100%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/dnssec-checker-from-url.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/dnssec-checker.module.css (100%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/dnssec-checker.tsx (99%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/layout.tsx (100%) rename app/(site)/(tools)/{(dns) => }/dnssec-checker/page.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/domain-age-content.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/domain-age-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/domain-age-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/domain-age-tool.tsx (99%) rename app/(site)/(tools)/{(domain) => }/domain-age/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-age/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/domain-availability/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-availability/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-availability/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-availability/domain-availability-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-availability/domain-availability-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-availability/domain-availability-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-availability/domain-availability-view.ts (99%) rename app/(site)/(tools)/{(domain) => }/domain-availability/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-availability/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/domain-expiry-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/domain-expiry-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/domain-expiry-tool.tsx (99%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-expiry/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/domain-lookup-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/domain-lookup-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/domain-lookup-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/domain-lookup-view.ts (98%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-lookup/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/domain-owner/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-owner/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-owner/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-owner/domain-owner-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-owner/domain-owner-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-owner/domain-owner-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-owner/domain-owner-view.ts (99%) rename app/(site)/(tools)/{(domain) => }/domain-owner/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-owner/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/domain-registrar-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/domain-registrar-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/domain-registrar-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/domain-registrar-view.ts (99%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-registrar/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/domain-report/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-report/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-report/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/domain-report/domain-report-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-report/domain-report-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/domain-report/domain-report-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-report/domain-report-view.ts (99%) rename app/(site)/(tools)/{(domain) => }/domain-report/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/domain-report/page.tsx (95%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/data/drive-reliability-snapshot.json (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/drive-reliability-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/drive-reliability.module.css (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/drive-reliability.tsx (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/drive-reliability/page.tsx (94%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/art/free-trial-conversion-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/art/free-trial-conversion-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/art/free-trial-conversion-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/free-trial-conversion-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/free-trial-conversion-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/free-trial-conversion-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/free-trial-conversion-calculator/published-figures.ts (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/art/ltv-cac-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/art/ltv-cac-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/art/ltv-cac-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/ltv-cac-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/ltv-cac-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/ltv-cac-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-calculator/mrr-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/mrr-calculator/mrr-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/art/mrr-goal-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/art/mrr-goal-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/art/mrr-goal-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/mrr-goal-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/mrr-goal-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-goal-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-waterfall-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-waterfall-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-waterfall-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-waterfall-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-waterfall-calculator/mrr-waterfall-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/mrr-waterfall-calculator/mrr-waterfall-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/mrr-waterfall-calculator/page.tsx (100%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/multi-tld-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/multi-tld-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/multi-tld-view.ts (96%) rename app/(site)/(tools)/{(domain) => }/multi-tld-availability/page.tsx (95%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/content/article.mdx (100%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/content/intro.mdx (100%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/content/usage.mdx (100%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/layout.tsx (100%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/nameserver-checker-from-url.tsx (100%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/nameserver-checker-view.ts (99%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/nameserver-checker.module.css (100%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/nameserver-checker.tsx (99%) rename app/(site)/(tools)/{(dns) => }/nameserver-checker/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/net-revenue-retention-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/net-revenue-retention-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/net-revenue-retention-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/net-revenue-retention-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/net-revenue-retention-calculator/net-revenue-retention-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/net-revenue-retention-calculator/net-revenue-retention-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/net-revenue-retention-calculator/page.tsx (100%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/punycode-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/punycode-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/punycode-converter/punycode-view.ts (97%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/page.tsx (93%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/raid-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/raid-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/raid-calculator/raid-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/page.tsx (94%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/raidz-expansion-planner-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/raidz-expansion-planner.module.css (100%) rename app/(site)/(tools)/{(storage) => }/raidz-expansion-planner/raidz-expansion-planner.tsx (100%) rename app/(site)/(tools)/{(storage) => }/rebuild-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/rebuild-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/rebuild-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/rebuild-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/rebuild-calculator/page.tsx (93%) rename app/(site)/(tools)/{(storage) => }/rebuild-calculator/rebuild-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/rebuild-calculator/rebuild-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/revenue-churn-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/revenue-churn-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/revenue-churn-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/revenue-churn-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/revenue-churn-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/revenue-churn-calculator/revenue-churn-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/revenue-churn-calculator/revenue-churn-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/art/saas-gross-margin-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/art/saas-gross-margin-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/art/saas-gross-margin-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/saas-gross-margin-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/saas-gross-margin-calculator/saas-gross-margin-calculator.tsx (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/art/saas-metrics-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/art/saas-metrics-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/art/saas-metrics-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/saas-metrics-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/saas-metrics-calculator/saas-metrics-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/page.tsx (93%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/shr-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/shr-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/shr-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/shr-calculator/shr-capacity.ts (100%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/page.tsx (94%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/snapraid-merfs-engine.ts (100%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/snapraid-mergerfs-planner.module.css (100%) rename app/(site)/(tools)/{(storage) => }/snapraid-mergerfs-planner/snapraid-mergerfs-planner.tsx (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/content/article.mdx (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/content/intro.mdx (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/content/usage.mdx (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/layout.tsx (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/page.tsx (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/soa-checker-from-url.tsx (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/soa-checker-view.ts (96%) rename app/(site)/(tools)/{(dns) => }/soa-checker/soa-checker.module.css (100%) rename app/(site)/(tools)/{(dns) => }/soa-checker/soa-checker.tsx (99%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/art/startup-runway-calculator.spec.json (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/art/startup-runway-calculator.svg (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/art/startup-runway-calculator.ts (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/page.tsx (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/startup-runway-calculator.module.css (100%) rename app/(site)/(tools)/{(saas) => }/startup-runway-calculator/startup-runway-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/page.tsx (94%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/storage-growth-planner-engine.ts (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/storage-growth-planner-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/storage-growth-planner.module.css (100%) rename app/(site)/(tools)/{(storage) => }/storage-growth-planner/storage-growth-planner.tsx (100%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/page.tsx (94%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/storage-layout-advisor-engine.ts (99%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/storage-layout-advisor-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/storage-layout-advisor.module.css (100%) rename app/(site)/(tools)/{(storage) => }/storage-layout-advisor/storage-layout-advisor.tsx (99%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/content/article.mdx (100%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/content/intro.mdx (100%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/content/usage.mdx (100%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/layout.tsx (100%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/page.tsx (95%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/transfer-readiness-from-url.tsx (100%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/transfer-readiness-tool.module.css (100%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/transfer-readiness-tool.tsx (100%) rename app/(site)/(tools)/{(domain) => }/transfer-readiness/transfer-readiness-view.ts (99%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/page.tsx (93%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/unraid-calculator-engine.ts (98%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/unraid-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/unraid-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/unraid-calculator/unraid-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/page.tsx (94%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/zfs-capacity-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/zfs-capacity-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/zfs-capacity-calculator/zfs-capacity-calculator.tsx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/content/article.mdx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/content/intro.mdx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/content/usage.mdx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/layout.tsx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/page.tsx (94%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/zfs-padding-calculator-from-url.tsx (100%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/zfs-padding-calculator.module.css (100%) rename app/(site)/(tools)/{(storage) => }/zfs-padding-calculator/zfs-padding-calculator.tsx (100%) delete mode 100644 app/ui/directories/keyboard-shortcuts-sidebar.module.css delete mode 100644 app/ui/directories/keyboard-shortcuts-sidebar.tsx rename app/{(site)/(tools)/(dns) => ui/tools/dns}/diagnostic-result-ui.tsx (100%) rename app/{(site)/(tools)/(dns) => ui/tools/dns}/dns-diagnostics.module.css (100%) rename app/{(site)/(tools)/(dns) => ui/tools/dns}/dns-tools.css (100%) rename app/{(site)/(tools)/(domain) => ui/tools/domain}/domain-lookup-client.tsx (100%) rename app/{(site)/(tools)/(domain) => ui/tools/domain}/domain-tools.css (100%) delete mode 100644 app/ui/tools/tool-family-sidebar.tsx diff --git a/AGENTS.md b/AGENTS.md index f5b80944..ce6d1363 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -75,7 +75,7 @@ Reporting: - Directory source lives in `app/(site)/(directories)/`, including stable fact pages such as `/tld-directory`. - Course source lives in `app/(site)/(courses)/`. - Home, about, privacy, terms, and labs live in `app/(site)/(site-pages)/`. -- Tool source lives in `app/(site)/(tools)/`. DNS, domain, and storage tools use a shared route-group layout before `/`. +- Tool source lives in `app/(site)/(tools)//`. Every tool uses the same flat folder. Code shared by a tool family lives in `app/ui/tools/`. - `public.stack127_pages` is the only publication registry. - Exact published slugs are indexable and enter the sitemap. Unpublished routes return 404. - Do not add route-owned metadata, robots, canonicals, sitemap dates, or JSON-LD to page files. diff --git a/app/(site)/(catalogs)/layout.tsx b/app/(site)/(catalogs)/layout.tsx deleted file mode 100644 index 7ac28e6f..00000000 --- a/app/(site)/(catalogs)/layout.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import type { ReactNode } from "react"; -import "@/app/(site)/(tools)/(dns)/dns-tools.css"; -import "@/app/(site)/(tools)/(domain)/domain-tools.css"; - -export default function CatalogLayout({ children }: { children: ReactNode }) { - return children; -} diff --git a/app/(site)/(components-ui)/components-ui/examples/page-layout.tsx b/app/(site)/(components-ui)/components-ui/examples/page-layout.tsx index 9b97311b..c584627f 100644 --- a/app/(site)/(components-ui)/components-ui/examples/page-layout.tsx +++ b/app/(site)/(components-ui)/components-ui/examples/page-layout.tsx @@ -25,6 +25,12 @@ const fullLayouts = [ { href: "/about", label: "Site page", detail: "InfoPage with a reading-width article" }, ]; +const sidebarModes = [ + { href: "/components-ui/sidebar-modes/left", label: "Left", detail: "sidebarPosition=\"left\", the default. Filters and lessons. A drawer on small screens." }, + { href: "/components-ui/sidebar-modes/right", label: "Right", detail: "sidebarPosition=\"right\". Related pages and section links. Below the content on small screens." }, + { href: "/components-ui/sidebar-modes/none", label: "None", detail: "sidebarPosition=\"none\". Content only. Reading sections center." }, +]; + export function PageLayoutExamples() { return ( <> @@ -82,7 +88,15 @@ export function PageLayoutExamples() { - + } sidebarPosition="right">\n …\n' }}> +
    + {sidebarModes.map((mode) => ( +
  • {mode.label}{mode.detail}
  • + ))} +
+
+ +
    {fullLayouts.map((layout) => (
  • {layout.label}{layout.detail}
  • diff --git a/app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/layout.tsx b/app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/layout.tsx new file mode 100644 index 00000000..42839fc8 --- /dev/null +++ b/app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/layout.tsx @@ -0,0 +1,7 @@ +import { registryLayout } from "@/lib/registry-layout"; + +const registry = registryLayout("/components-ui/sidebar-modes/[position]"); +export const generateMetadata = registry.generateMetadata; +export function generateStaticParams() { return []; } +export const revalidate = false; +export default registry.Layout; diff --git a/app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/page.tsx b/app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/page.tsx new file mode 100644 index 00000000..50e02d50 --- /dev/null +++ b/app/(site)/(components-ui-modes)/components-ui/sidebar-modes/[position]/page.tsx @@ -0,0 +1,87 @@ +import type { ReactNode } from "react"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { LayoutGrid, PanelLeft, PanelRight, Square } from "lucide-react"; +import { AppShell, SidebarLabel, type SidebarPosition } from "@/app/ui/site/app-shell"; +import { PageCanvas } from "@/app/ui/site/page-canvas"; +import { PageHeader } from "@/app/ui/site/page-header"; +import { PageTitleIcon } from "@/app/ui/site/page-title-icon"; +import { proseClassName } from "@/app/ui/site/prose"; +import { PathnameSidebarList } from "@/app/ui/site/pathname-sidebar-list"; +import { sidebarPanelClassName, sidebarPanelHeadingClassName } from "@/app/ui/site/sidebar-panel"; + +const modes: Record = { + left: { + title: <>Sidebar on the left, + lede: "For options people use to work the page, such as directory filters or course lessons. On small screens it opens from the drawer.", + icon: PanelLeft, + }, + right: { + title: <>Sidebar on the right, + lede: "For secondary help, such as related pages or links to this page's sections. On small screens it sits below the content.", + icon: PanelRight, + }, + none: { + title: <>No sidebar, + lede: "For pages that only need their content. Wide sections fill the page. Reading sections center at the reading width.", + icon: Square, + }, +}; + +const sidebarItems = [ + { href: "/components-ui/sidebar-modes/left", label: "Sidebar on the left", icon: }, + { href: "/components-ui/sidebar-modes/right", label: "Sidebar on the right", icon: }, + { href: "/components-ui/sidebar-modes/none", label: "No sidebar", icon: }, + { href: "/components-ui/page-layout", label: "Back to page layout", icon: }, +]; + +function isSidebarPosition(value: string): value is SidebarPosition { + return value === "left" || value === "right" || value === "none"; +} + +// Development only: shows each AppShell sidebar position with the real shell, outside the gallery's own shell. +export default async function SidebarModePage({ params }: { params: Promise<{ position: string }> }) { + if (process.env.NODE_ENV !== "development") notFound(); + const { position } = await params; + if (!isSidebarPosition(position)) notFound(); + const mode = modes[position]; + + return ( + +
    Sidebar modes
    + + + )} + sidebarLabel="Sidebar modes sidebar" + sidebarPosition={position} + > + + +

    + {mode.title} +

    +

    {mode.lede}

    +
    +

    + This section uses the wide PageCanvas. It fills the main column, so a table or card grid has room. +

    +
    + +
    +

    A reading section

    +

    + This section uses PageCanvas reading. Lines stop at the reading width, so long paragraphs stay easy to follow. + With a sidebar, the section starts at the left edge of the main column. With no sidebar, it centers in the page. +

    +
      + {sidebarItems.map((item) =>
    • {item.label}
    • )} +
    +
    +
    +
    + ); +} diff --git a/app/(site)/(directories)/epp-status-codes/page.tsx b/app/(site)/(directories)/epp-status-codes/page.tsx index 0eb49e6b..f4efdbe2 100644 --- a/app/(site)/(directories)/epp-status-codes/page.tsx +++ b/app/(site)/(directories)/epp-status-codes/page.tsx @@ -4,11 +4,10 @@ import { getRequiredDirectoryPage } from "@/lib/directory-pages"; import { DirectoryPageTitle } from "@/app/ui/directories/directory-page-content"; import { PageMeta } from "@/app/ui/site/page-meta"; import { PageCanvas } from "@/app/ui/site/page-canvas"; -import "@/app/(site)/(tools)/(domain)/domain-tools.css"; +import "@/app/ui/tools/domain/domain-tools.css"; import { AppShell } from "../../../ui/site/app-shell"; -import { DomainToolsSidebar } from "@/app/(site)/(tools)/(domain)/domain-tools-sidebar"; import { STATUS_CODES, STATUS_GROUP_TITLES, type StatusGroup } from "@/lib/domain/status-codes.ts"; -import { StatePill } from "@/app/(site)/(tools)/(domain)/domain-lookup-client"; +import { StatePill } from "@/app/ui/tools/domain/domain-lookup-client"; import { DirectoryTitleIcon } from "@/app/ui/directories/directory-title-icon"; import { PageHeader } from "../../../ui/site/page-header"; import { proseSectionFlowClassName } from "../../../ui/site/prose"; @@ -55,12 +54,7 @@ function SourcePathParagraph({ children, ...props }: ComponentPropsWithoutRef<"p export default async function EppStatusCodesPage() { const directoryPage = await getRequiredDirectoryPage("epp-status-codes"); return ( - } - sidebarLabel="Domain tools sidebar" - > +

    {" "}

    diff --git a/app/(site)/(directories)/keyboard-shortcuts/(index)/page.tsx b/app/(site)/(directories)/keyboard-shortcuts/(index)/page.tsx index d5d94e8e..fb359479 100644 --- a/app/(site)/(directories)/keyboard-shortcuts/(index)/page.tsx +++ b/app/(site)/(directories)/keyboard-shortcuts/(index)/page.tsx @@ -1,15 +1,9 @@ import { AppShell } from "@/app/ui/site/app-shell"; -import { KeyboardShortcutsSidebar } from "@/app/ui/directories/keyboard-shortcuts-sidebar"; import { KeyboardShortcutsDirectory } from "../keyboard-shortcuts-directory"; export default function KeyboardShortcutsDirectoryPage() { return ( - } - sidebarLabel="Shortcut pages" - > + ); diff --git a/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-app-page.tsx b/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-app-page.tsx index a8dfd847..46e5a5a3 100644 --- a/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-app-page.tsx +++ b/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-app-page.tsx @@ -3,7 +3,6 @@ import { getPublishedDirectoryPage, getRequiredDirectoryPage } from "@/lib/direc import { AppShell } from "@/app/ui/site/app-shell"; import type { ReactNode } from "react"; import type { AppShortcuts } from "@/lib/shortcuts/types"; -import { KeyboardShortcutsSidebar } from "@/app/ui/directories/keyboard-shortcuts-sidebar"; import { KeyboardShortcutsReference } from "./keyboard-shortcuts-reference"; export async function KeyboardShortcutsAppPage({ app, intro }: { app: AppShortcuts; intro: ReactNode }) { @@ -14,12 +13,7 @@ export async function KeyboardShortcutsAppPage({ app, intro }: { app: AppShortcu ]); const iconKey = directoryPage.card_icon_key ?? parentPage?.card_icon_key ?? null; return ( - } - sidebarLabel="Shortcut pages" - > + ); diff --git a/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-directory.tsx b/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-directory.tsx index f12a37f5..83fd22cf 100644 --- a/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-directory.tsx +++ b/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts-directory.tsx @@ -5,7 +5,7 @@ import { PageMeta } from "@/app/ui/site/page-meta"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import Link from "next/link"; import { appsInCategory, shortcutAppCatalog, shortcutCategories } from "@/lib/shortcuts"; -import { platformLabels } from "@/lib/shortcuts/types"; +import type { PlatformId } from "@/lib/shortcuts/types"; import { DirectoryTitleIcon } from "@/app/ui/directories/directory-title-icon"; import { PageHeader } from "@/app/ui/site/page-header"; import { EntryHero } from "@/app/ui/site/entry-hero"; @@ -16,6 +16,9 @@ import Intro from "./(index)/content/intro.mdx"; import ShortcutNotWorking from "./(index)/content/shortcut-not-working.mdx"; import WhereShortcutsComeFrom from "./(index)/content/where-shortcuts-come-from.mdx"; +const platformOrder: PlatformId[] = ["windows", "macos", "linux"]; +const platformShortLabels: Record = { windows: "Win", macos: "Mac", linux: "Linux" }; + function categoryId(category: string) { return "category-" + category.toLowerCase().replace(/[^a-z0-9]+/g, "-"); } @@ -41,32 +44,27 @@ export async function KeyboardShortcutsDirectory() { return (

    {category}

    -
    - - - - - - - - - - {apps.map((app) => ( - - - - - - ))} - -
    AppPlatformsShortcuts
    - {app.name} - -
      - {app.platforms.map((platform) =>
    • {platformLabels[platform]}
    • )} -
    -
    {app.shortcutCount}
    -
    +
      + {apps.map((app) => ( +
    • + + {app.name} + {app.shortcutCount} shortcuts + + {platformOrder.map((platform) => ( + + {platformShortLabels[platform]} + + ))} + + +
    • + ))} +
    ); })} diff --git a/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts.module.css b/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts.module.css index d726d494..7812e527 100644 --- a/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts.module.css +++ b/app/(site)/(directories)/keyboard-shortcuts/keyboard-shortcuts.module.css @@ -19,9 +19,28 @@ .table a { color: var(--color-link); font-weight: var(--weight-semibold); text-decoration: none; text-decoration-color: currentColor; text-underline-offset: 3px; } .table a:hover { color: var(--color-link); text-decoration-color: currentColor; } .table a:focus-visible, .nextStep a:focus-visible { outline: 0; box-shadow: var(--focus-ring); } -.platforms { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin: 0; padding: 0; list-style: none; } -.platforms li { white-space: nowrap; } -.count { color: var(--color-text-muted); font-family: var(--font-mono); white-space: nowrap; } +.appGrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-5); margin: 0; padding: 0; list-style: none; } +.appCard { + display: grid; + gap: var(--space-2); + height: 100%; + padding: var(--space-7); + border: 1px solid var(--color-border); + border-radius: var(--radius); + background: var(--color-surface); + color: var(--color-text); + text-decoration: none; + transition: border-color var(--motion-base); +} +.appCard:hover { border-color: var(--color-accent); } +.appCard:hover .appName { text-decoration: underline; text-underline-offset: 3px; } +.appCard:focus-visible { outline: var(--focus-outline); outline-offset: 2px; } +.appName { color: var(--color-link); font-family: var(--font-display); font-size: var(--text-h3); font-weight: var(--weight-bold); letter-spacing: var(--tracking-display); line-height: var(--line-heading); } +.appCount { font-family: var(--font-mono); white-space: nowrap; } +.appCount small { color: var(--color-text-muted); font-size: var(--text-small); } +.appPlatforms { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-4); } +.platform { padding: 0 var(--space-2); border: 1px solid var(--color-border-strong); border-radius: var(--radius); font-family: var(--font-mono); font-size: var(--text-small); line-height: var(--line-body); } +.platformMissing { border-color: var(--color-border); border-style: dashed; color: var(--color-text-muted); text-decoration: line-through; opacity: 0.6; } .referenceTable { table-layout: fixed; } .referenceTable th:first-child, .referenceTable .action { width: 40%; } .referenceTable th, .referenceTable td { padding: var(--space-10); } @@ -73,11 +92,14 @@ .referenceTable tbody tr td + td { margin-top: var(--space-7); } .referenceTable .action { width: auto; } } +@media (max-width: 1100px) { + .appGrid { grid-template-columns: repeat(3, minmax(0, 1fr)); } +} @media (max-width: 760px) { - .directoryTable thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); } - .directoryTable tbody tr { display: grid; grid-template-columns: 1fr auto; padding: var(--space-7); gap: var(--space-3); border-bottom: 1px solid var(--color-border); } - .directoryTable tbody tr:last-child { border-bottom: 0; } - .directoryTable tbody tr td { padding: 0; border: 0; } - .directoryTable tbody tr td:first-child { grid-column: 1 / -1; } - .directoryTable .count::after { content: " shortcuts"; font-family: var(--font-sans); } + .appGrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .appCard { padding: var(--space-5); } + .platform { padding: 0 var(--space-1); } +} +@media (max-width: 360px) { + .appGrid { grid-template-columns: minmax(0, 1fr); } } diff --git a/app/(site)/(directories)/tld-directory/page.tsx b/app/(site)/(directories)/tld-directory/page.tsx index 3692de66..162ac98a 100644 --- a/app/(site)/(directories)/tld-directory/page.tsx +++ b/app/(site)/(directories)/tld-directory/page.tsx @@ -3,9 +3,8 @@ import { getBreadcrumbs } from "@/lib/breadcrumbs"; import { DirectoryPageTitle } from "@/app/ui/directories/directory-page-content"; import { PageMeta } from "@/app/ui/site/page-meta"; import { PageCanvas } from "@/app/ui/site/page-canvas"; -import "@/app/(site)/(tools)/(domain)/domain-tools.css"; +import "@/app/ui/tools/domain/domain-tools.css"; import { AppShell } from "../../../ui/site/app-shell"; -import { DomainToolsSidebar } from "@/app/(site)/(tools)/(domain)/domain-tools-sidebar"; import { TldTable, type TldRow } from "./tld-table"; import directory from "@/lib/domain/data/tld-directory.json" with { type: "json" }; import { DirectoryTitleIcon } from "@/app/ui/directories/directory-title-icon"; @@ -33,12 +32,7 @@ export default async function TldDirectoryPage() { }); return ( - } - sidebarLabel="Domain tools sidebar" - > +

    {" "}

    diff --git a/app/(site)/(directories)/tld-directory/tld-table.tsx b/app/(site)/(directories)/tld-directory/tld-table.tsx index 00c76e67..6fe236ad 100644 --- a/app/(site)/(directories)/tld-directory/tld-table.tsx +++ b/app/(site)/(directories)/tld-directory/tld-table.tsx @@ -1,7 +1,7 @@ "use client"; import { useMemo, useState } from "react"; -import { StatePill } from "@/app/(site)/(tools)/(domain)/domain-lookup-client"; +import { StatePill } from "@/app/ui/tools/domain/domain-lookup-client"; export type TldRow = { tld: string; diff --git a/app/(site)/(site-pages)/(home)/page.tsx b/app/(site)/(site-pages)/(home)/page.tsx index 89254422..0bd6a0e6 100644 --- a/app/(site)/(site-pages)/(home)/page.tsx +++ b/app/(site)/(site-pages)/(home)/page.tsx @@ -20,13 +20,8 @@ import { type Stack127Page, } from "@/lib/page-registry"; import { getRequiredCourse } from "@/lib/course-pages"; -import { AppShell, SidebarLabel } from "@/app/ui/site/app-shell"; +import { AppShell } from "@/app/ui/site/app-shell"; import { EntryHero } from "@/app/ui/site/entry-hero"; -import { SidebarList } from "@/app/ui/site/sidebar-list"; -import { - sidebarPanelClassName, - sidebarPanelHeadingClassName, -} from "@/app/ui/site/sidebar-panel"; import { siteHeroStack127Art } from "@/app/(site)/art/site--hero-stack127"; type HomePageCardRecord = Stack127Page & { @@ -36,9 +31,6 @@ type HomePageCardRecord = Stack127Page & { card_art_key: string | null; }; -/** Legal pages stay in the footer; the explore list is for the real content. */ -const legalSlugs = new Set(["about", "privacy", "terms"]); - /** Labs keeps its card assets and counts in code. */ const codeCards: Record PageCardCount[] }> = { labs: { @@ -48,32 +40,6 @@ const codeCards: Record }, }; -function HomeSidebar({ pages }: { pages: HomePageCardRecord[] }) { - return ( -
    -
    - Explore stack127 -
    - -
    - ); -} - async function cardCounts(page: Stack127Page) { if (page.page_family === "course") { const course = await getRequiredCourse(page.slug); @@ -124,16 +90,6 @@ export default async function Home() { getMainPublishedPages(), getPublishedToolCatalogs(), ]); - const visibleMainPages: HomePageCardRecord[] = [ - ...mainPages.filter(isHomeVisiblePage), - ...toolCatalogs.map((catalog) => ({ - ...catalog.page, - card_name: catalog.card_name, - card_description: catalog.card_description, - card_icon_key: catalog.card_icon_key, - card_art_key: catalog.card_art_key, - })), - ].sort((left, right) => Number(right.sitemap_priority) - Number(left.sitemap_priority) || left.label.localeCompare(right.label)); const featurePages = mainPages.filter((page) => isHomeVisiblePage(page) && isHomeFeaturePage(page)); // One snapshot feeds both the card counts and the freshness marker, so they can't straddle a refresh. const launchSnapshot = featurePages.some((page) => page.slug === "launch-directories") ? await getLaunchDirectorySnapshot() : null; @@ -141,12 +97,7 @@ export default async function Home() { const startItems = startHereItems(new Set([...featurePages.map((page) => page.slug), ...toolCatalogs.map((catalog) => catalog.page.slug)])); return ( - } - sidebarLabel="Home sidebar" - > +

    diff --git a/app/(site)/(tools)/(dns)/layout.tsx b/app/(site)/(tools)/(dns)/layout.tsx deleted file mode 100644 index f0f35a1f..00000000 --- a/app/(site)/(tools)/(dns)/layout.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import type { ReactNode } from "react"; -import "@/app/(site)/(tools)/(dns)/dns-tools.css"; - -export default function DnsToolLayout({ children }: { children: ReactNode }) { - return children; -} diff --git a/app/(site)/(tools)/(domain)/domain-tools-sidebar.tsx b/app/(site)/(tools)/(domain)/domain-tools-sidebar.tsx deleted file mode 100644 index a1cf0d6a..00000000 --- a/app/(site)/(tools)/(domain)/domain-tools-sidebar.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ToolFamilySidebar } from "@/app/ui/tools/tool-family-sidebar"; - -export function DomainToolsSidebar() { - return ; -} diff --git a/app/(site)/(tools)/(domain)/layout.tsx b/app/(site)/(tools)/(domain)/layout.tsx deleted file mode 100644 index b6f5d74b..00000000 --- a/app/(site)/(tools)/(domain)/layout.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import type { ReactNode } from "react"; -import "@/app/(site)/(tools)/(domain)/domain-tools.css"; - -export default function DomainToolLayout({ children }: { children: ReactNode }) { - return children; -} diff --git a/app/(site)/(tools)/(storage)/layout.tsx b/app/(site)/(tools)/(storage)/layout.tsx deleted file mode 100644 index 865fd43f..00000000 --- a/app/(site)/(tools)/(storage)/layout.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import type { ReactNode } from "react"; - -export default function StorageToolLayout({ children }: { children: ReactNode }) { - return children; -} diff --git a/app/(site)/(tools)/(storage)/storage-tools.module.css b/app/(site)/(tools)/(storage)/storage-tools.module.css deleted file mode 100644 index 6e0190d9..00000000 --- a/app/(site)/(tools)/(storage)/storage-tools.module.css +++ /dev/null @@ -1,777 +0,0 @@ -.hubSection { - display: grid; - gap: var(--space-5); -} - -.hubSection h2, -.inventoryHeading h2, -.resultSection h2, -.invalidResult h2 { - font-family: var(--font-display); - font-size: var(--text-h2); - font-weight: var(--weight-bold); - letter-spacing: var(--tracking-display); - line-height: var(--line-heading); - margin: 0; -} - -.toolLink { - align-items: center; - border: 1px solid var(--color-border-strong); - border-radius: var(--radius); - color: var(--color-text); - display: grid; - gap: var(--space-4); - grid-template-columns: auto 1fr auto; - padding: var(--space-6); - text-decoration: none; - transition: border-color var(--motion-fast), background var(--motion-fast); -} - -.toolLink:hover { - background: var(--color-surface-2); - border-color: var(--color-accent-text); -} - -.toolLink strong { - display: block; - font-family: var(--font-display); - font-size: var(--text-body); -} - -.toolLink small { - color: var(--color-text); - display: block; - font-size: var(--text-small); - line-height: var(--line-body); - margin-top: var(--space-2); -} - -.toolForm { - display: grid; - gap: var(--space-7); - padding: var(--space-7); -} - -.fieldset, -.resultUnit { - border: 0; - display: grid; - gap: var(--space-3); - margin: 0; - min-width: 0; - padding: 0; -} - -.fieldset legend { - font-family: var(--font-display); - font-size: var(--text-body); - font-weight: var(--weight-semibold); - margin-bottom: var(--space-3); - padding: 0; -} - -.choiceRow { - display: flex; - flex-wrap: wrap; - gap: var(--space-2); -} - -.choice { - cursor: pointer; - position: relative; -} - -.choice input { - inset: 0; - opacity: 0; - position: absolute; -} - -.choice span { - border: 1px solid var(--color-border-strong); - border-radius: var(--radius); - display: block; - font-size: var(--text-body); - padding: var(--space-2) var(--space-4); - transition: border-color var(--motion-fast), color var(--motion-fast), background var(--motion-fast); -} - -.choice:hover span { - background: var(--color-surface-2); -} - -.choice input:checked + span { - border-color: var(--color-accent-text); - color: var(--color-accent-text); - font-weight: var(--weight-semibold); -} - -.choice input:focus-visible + span { - box-shadow: var(--focus-ring); -} - -.inventoryHeading h2, -.resultSection h2, -.invalidResult h2 { - font-size: var(--text-h3); -} - -.inventoryHeading p, -.topologyNote, -.resultSectionHeading > span, -.resultHeadline > span { - color: var(--color-text-muted); - font-family: var(--font-mono); - font-size: var(--text-small); - line-height: var(--line-body); - margin: 0; -} - -.driveRow label, -.groupSizeControl { - display: grid; - gap: var(--space-1); - min-width: 0; -} - -.groupSizeControl > span { - color: var(--color-text-muted); - font-size: var(--text-small); -} - -.driveRow input, -.driveRow select, -.groupSizeControl select { - background: var(--color-bg); - border: 1px solid var(--color-border-strong); - border-radius: var(--radius); - color: var(--color-text); - font-size: var(--text-body); - min-height: 42px; - padding: var(--space-2) var(--space-3); - width: 100%; -} - -.addButton, -.inventoryCalculate, -.resetButton, -.removeButton { - align-items: center; - border-radius: var(--radius); - cursor: pointer; - display: inline-flex; - font-size: var(--text-body); - font-weight: var(--weight-semibold); - gap: var(--space-2); - justify-content: center; - min-height: 42px; - padding: var(--space-2) var(--space-4); -} - -.inventoryCalculate { - background: var(--color-accent); - border: 1px solid var(--color-accent); - color: var(--color-accent-contrast); - width: 100%; -} - -.addButton, -.resetButton, -.removeButton { - background: var(--color-surface); - border: 1px solid var(--color-border-strong); - color: var(--color-text); -} - -.addButton, -.resetButton { - white-space: nowrap; -} - -.addButton:focus-visible, -.inventoryCalculate:focus-visible, -.resetButton:focus-visible, -.removeButton:focus-visible, -.driveRow input:focus-visible, -.driveRow select:focus-visible, -.groupSizeControl select:focus-visible { - box-shadow: var(--focus-ring); - outline: 0; -} - -.addButton:disabled, -.inventoryCalculate:disabled { - cursor: not-allowed; - opacity: 0.45; -} - -.inventory { - border-top: 1px solid var(--color-border); - display: grid; - gap: var(--space-4); - padding-top: var(--space-6); -} - -.inventoryHeading { - align-items: end; - display: flex; - gap: var(--space-5); - justify-content: space-between; -} - -.inventoryControls { - display: flex; - flex-wrap: wrap; - gap: var(--space-2); - justify-content: flex-end; -} - -.inventoryHeading p { - margin-top: var(--space-1); -} - -.driveTable { - border-block: 1px solid var(--color-border-strong); -} - -.emptyInventory { - color: var(--color-text-muted); - font-size: var(--text-body); - line-height: var(--line-body); - margin: 0; - padding: var(--space-5) 0; - text-align: center; -} - -.driveTableHeader, -.driveRow { - align-items: center; - display: grid; - gap: var(--space-3); - grid-template-columns: 4.5rem minmax(8rem, 1fr) 7rem 42px; -} - -.driveTableHeader { - color: var(--color-text-muted); - font-family: var(--font-mono); - font-size: var(--text-small); - padding: var(--space-2) 0; -} - -.driveRow { - border-top: 1px solid var(--color-border); - min-height: 58px; - padding-block: var(--space-2); -} - -.driveIdentity { - align-items: center; - display: flex; - gap: var(--space-2); -} - -.driveNumber, -.groupTag { - font-family: var(--font-mono); - font-size: var(--text-small); -} - -.driveNumber { - color: var(--color-text-muted); -} - -.groupTag { - color: var(--color-accent-text); -} - -.removeButton { - min-width: 42px; - padding: var(--space-2); -} - -.groupingNote { - color: var(--color-text); - font-size: var(--text-body); - line-height: var(--line-body); - margin: 0; -} - -.groupSizeControl { - max-width: 22rem; -} - -.result, -.invalidResult { - border-top: 1px solid var(--color-border); - display: grid; - gap: var(--space-7); - padding: var(--space-7); -} - -.resultHeader { - align-items: start; - display: flex; - gap: var(--space-5); - justify-content: space-between; -} - -.resultHeadline { - display: grid; - gap: var(--space-2); -} - -.resultHeadline p { - align-items: baseline; - display: flex; - flex-wrap: wrap; - font-size: var(--text-body); - gap: var(--space-3); - line-height: var(--line-heading); - margin: 0; -} - -.resultHeadline strong { - font-family: var(--font-mono); - font-size: var(--text-h2); - font-weight: var(--weight-semibold); -} - -.resultUnit .choiceRow { - flex-wrap: nowrap; -} - -.resultUnit .choice span { - padding-inline: var(--space-3); -} - -.warningText { - color: var(--color-warning-text); - font-size: var(--text-body); - line-height: var(--line-body); - margin: calc(var(--space-3) * -1) 0 0; -} - -.resultSection { - display: grid; - gap: var(--space-4); -} - -.resultSectionHeading { - align-items: baseline; - display: flex; - gap: var(--space-4); - justify-content: space-between; -} - -.capacityBar { - background: var(--color-surface-2); - border: 1px solid var(--color-border-strong); - display: flex; - height: 34px; - overflow: hidden; - width: 100%; -} - -.capacityBar > span { - display: block; - height: 100%; -} - -.capacityUsable { - background: var(--color-text); -} - -.capacityRedundancy { - background: var(--color-border-strong); -} - -.capacityMismatch { - background: var(--color-text-muted); -} - -.capacityValues { - border-block: 1px solid var(--color-border); - margin: 0; -} - -.capacityValues > div { - align-items: center; - border-bottom: 1px solid var(--color-border); - display: grid; - gap: var(--space-5); - grid-template-columns: minmax(9rem, 1fr) minmax(12rem, auto); - padding-block: var(--space-3); -} - -.capacityValues > div:last-child { - border-bottom: 0; -} - -.capacityValues dt, -.capacityValues dd { - margin: 0; -} - -.capacityValues dt { - align-items: center; - display: flex; - font-family: var(--font-display); - font-weight: var(--weight-semibold); - gap: var(--space-3); -} - -.capacityValues dd { - align-items: baseline; - display: grid; - gap: var(--space-5); - grid-template-columns: minmax(7rem, 1fr) 4rem; - text-align: right; -} - -.capacityValues dd strong, -.capacityValues dd span { - font-family: var(--font-mono); -} - -.capacityValues dd span { - color: var(--color-text-muted); - font-size: var(--text-small); -} - -.capacitySwatch { - border: 1px solid var(--color-border-strong); - display: inline-block; - height: 12px; - width: 12px; -} - -.topology { - display: grid; - gap: var(--space-4); -} - -.topologyStrip { - border-block: 1px solid var(--color-border-strong); -} - -.topologyHeading { - align-items: baseline; - display: flex; - flex-wrap: wrap; - gap: var(--space-3); - justify-content: space-between; - padding: var(--space-3) 0; -} - -.topologyHeading strong { - font-family: var(--font-display); - font-size: var(--text-body); -} - -.topologyHeading span { - color: var(--color-text-muted); - font-family: var(--font-mono); - font-size: var(--text-small); -} - -.topologyDrives { - background: var(--color-border); - border-top: 1px solid var(--color-border); - display: grid; - gap: 1px; - grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); -} - -.topologyDrive { - align-items: center; - background: var(--color-surface); - display: flex; - gap: var(--space-3); - min-height: 62px; - padding: var(--space-3); -} - -.topologyDrive svg { - fill: none; - height: 24px; - stroke: currentColor; - stroke-linecap: round; - stroke-linejoin: round; - stroke-width: 1.7; - width: 24px; -} - -.topologyDrive > span { - display: grid; - font-family: var(--font-mono); - font-size: var(--text-small); - gap: var(--space-1); -} - -.topologyDrive small { - color: var(--color-text-muted); - font-size: var(--text-small); -} - -.topologyNote { - color: var(--color-text); -} - -.resultFacts { - border-block: 1px solid var(--color-border-strong); - margin: 0; -} - -.resultFacts > div { - border-bottom: 1px solid var(--color-border); - display: grid; - gap: var(--space-5); - grid-template-columns: 12rem 1fr; - padding-block: var(--space-4); -} - -.resultFacts > div:last-child { - border-bottom: 0; -} - -.resultFacts dt, -.resultFacts dd { - font-size: var(--text-body); - line-height: var(--line-body); - margin: 0; -} - -.resultFacts dt { - font-family: var(--font-display); - font-weight: var(--weight-semibold); -} - -.backupNote, -.invalidResult p, -.invalidResult li, -.methodDetails { - color: var(--color-text); - font-size: var(--text-body); - line-height: var(--line-body); - margin: 0; -} - -.backupNote { - border: 1px solid var(--color-border); - border-radius: var(--radius); - padding: var(--space-4); -} - -.backupNote strong { - color: var(--color-warning-text); -} - -.methodDetails { - border-top: 1px solid var(--color-border); - padding-top: var(--space-5); -} - -.methodDetails summary { - cursor: pointer; - font-family: var(--font-display); - font-weight: var(--weight-semibold); -} - -.methodDetails > div { - display: grid; - gap: var(--space-4); - margin-top: var(--space-4); - max-width: var(--measure-prose); -} - -.methodDetails p, -.methodDetails ul { - margin: 0; -} - -.invalidResult { - gap: var(--space-4); -} - -.invalidResult h2 { - color: var(--color-danger-text); -} - -.invalidResult ul { - margin: 0; - padding-left: var(--space-6); -} - -.comparisonTable { - border: 1.5px solid var(--color-border-strong); - border-collapse: collapse; - font-size: var(--text-body); - min-width: 42rem; - width: 100%; -} - -.comparisonTable th, -.comparisonTable td { - border-bottom: 1px solid var(--color-border); - padding: var(--space-3) var(--space-4); - text-align: left; - vertical-align: top; -} - -.comparisonTable thead th { - border-bottom: 1.5px solid var(--color-border-strong); - font-family: var(--font-display); - font-weight: var(--weight-bold); -} - -.comparisonTable td:nth-child(2), -.comparisonTable td:nth-child(3), -.comparisonTable td:nth-child(5) { - font-family: var(--font-mono); -} - -.comparisonTable tbody tr:last-child > * { - border-bottom: 0; -} - -.reference { - border-top: 1px solid var(--color-border); - display: grid; - gap: var(--space-8); - padding-top: var(--space-10); -} - -.visuallyHidden { - clip: rect(0 0 0 0); - clip-path: inset(50%); - height: 1px; - overflow: hidden; - position: absolute; - white-space: nowrap; - width: 1px; -} - -@media (max-width: 760px) { - .toolForm, - .result, - .invalidResult { - padding: var(--space-5); - } - - .fieldset > .choiceRow { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - } - - .fieldset .choice span { - padding-inline: var(--space-2); - text-align: center; - } - - .driveTableHeader, - .driveRow { - gap: var(--space-2); - grid-template-columns: 2.5rem minmax(0, 1fr) 5.25rem 42px; - } - - .inventoryHeading { - align-items: stretch; - display: grid; - } - - .inventoryControls { - justify-content: stretch; - width: 100%; - } - - .inventoryControls > button { - flex: 1; - } - - .resultHeader { - align-items: start; - } - - .resultHeadline p { - display: grid; - gap: var(--space-1); - } - - .resultSectionHeading { - align-items: start; - flex-direction: column; - gap: var(--space-1); - } - - .capacityValues > div { - gap: var(--space-3); - grid-template-columns: minmax(7rem, 1fr) auto; - } - - .capacityValues dd { - gap: var(--space-3); - grid-template-columns: minmax(6rem, 1fr) 3.5rem; - } - - .topologyDrives { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .resultFacts > div { - gap: var(--space-2); - grid-template-columns: 1fr; - } - - .toolLink { - align-items: start; - } -} - -@media (max-width: 380px) { - .toolForm, - .result, - .invalidResult { - padding: var(--space-4); - } - - .choiceRow, - .driveTableHeader, - .driveRow { - gap: var(--space-1); - } - - .fieldset .choice span { - padding-inline: var(--space-1); - } - - .driveTableHeader, - .driveRow { - grid-template-columns: 2rem minmax(0, 1fr) 4.5rem 42px; - } - - .driveRow input, - .driveRow select { - padding-inline: var(--space-2); - } - - .resultHeader { - display: grid; - } - - .capacityValues > div { - align-items: start; - grid-template-columns: 1fr; - } - - .capacityValues dd { - text-align: left; - } -} - -@media (prefers-reduced-motion: reduce) { - .choice span, - .toolLink { - transition: none; - } -} diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/annual-plan-discount-calculator.module.css b/app/(site)/(tools)/annual-plan-discount-calculator/annual-plan-discount-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/annual-plan-discount-calculator.module.css rename to app/(site)/(tools)/annual-plan-discount-calculator/annual-plan-discount-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/annual-plan-discount-calculator.tsx b/app/(site)/(tools)/annual-plan-discount-calculator/annual-plan-discount-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/annual-plan-discount-calculator.tsx rename to app/(site)/(tools)/annual-plan-discount-calculator/annual-plan-discount-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.spec.json b/app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.spec.json rename to app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.svg b/app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.svg rename to app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.svg diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.ts b/app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.ts rename to app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.ts diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/content/article.mdx b/app/(site)/(tools)/annual-plan-discount-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/content/article.mdx rename to app/(site)/(tools)/annual-plan-discount-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/content/intro.mdx b/app/(site)/(tools)/annual-plan-discount-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/content/intro.mdx rename to app/(site)/(tools)/annual-plan-discount-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/content/usage.mdx b/app/(site)/(tools)/annual-plan-discount-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/content/usage.mdx rename to app/(site)/(tools)/annual-plan-discount-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/layout.tsx b/app/(site)/(tools)/annual-plan-discount-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/layout.tsx rename to app/(site)/(tools)/annual-plan-discount-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/page.tsx b/app/(site)/(tools)/annual-plan-discount-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/annual-plan-discount-calculator/page.tsx rename to app/(site)/(tools)/annual-plan-discount-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/arpu-arpa-calculator/arpu-arpa-calculator.module.css b/app/(site)/(tools)/arpu-arpa-calculator/arpu-arpa-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/arpu-arpa-calculator/arpu-arpa-calculator.module.css rename to app/(site)/(tools)/arpu-arpa-calculator/arpu-arpa-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/arpu-arpa-calculator/arpu-arpa-calculator.tsx b/app/(site)/(tools)/arpu-arpa-calculator/arpu-arpa-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/arpu-arpa-calculator/arpu-arpa-calculator.tsx rename to app/(site)/(tools)/arpu-arpa-calculator/arpu-arpa-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/arpu-arpa-calculator/content/article.mdx b/app/(site)/(tools)/arpu-arpa-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/arpu-arpa-calculator/content/article.mdx rename to app/(site)/(tools)/arpu-arpa-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/arpu-arpa-calculator/content/intro.mdx b/app/(site)/(tools)/arpu-arpa-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/arpu-arpa-calculator/content/intro.mdx rename to app/(site)/(tools)/arpu-arpa-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/arpu-arpa-calculator/content/usage.mdx b/app/(site)/(tools)/arpu-arpa-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/arpu-arpa-calculator/content/usage.mdx rename to app/(site)/(tools)/arpu-arpa-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/arpu-arpa-calculator/layout.tsx b/app/(site)/(tools)/arpu-arpa-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/arpu-arpa-calculator/layout.tsx rename to app/(site)/(tools)/arpu-arpa-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/arpu-arpa-calculator/page.tsx b/app/(site)/(tools)/arpu-arpa-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/arpu-arpa-calculator/page.tsx rename to app/(site)/(tools)/arpu-arpa-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/arr-calculator/arr-calculator.module.css b/app/(site)/(tools)/arr-calculator/arr-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/arr-calculator/arr-calculator.module.css rename to app/(site)/(tools)/arr-calculator/arr-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/arr-calculator/arr-calculator.tsx b/app/(site)/(tools)/arr-calculator/arr-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/arr-calculator/arr-calculator.tsx rename to app/(site)/(tools)/arr-calculator/arr-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/arr-calculator/content/article.mdx b/app/(site)/(tools)/arr-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/arr-calculator/content/article.mdx rename to app/(site)/(tools)/arr-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/arr-calculator/content/intro.mdx b/app/(site)/(tools)/arr-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/arr-calculator/content/intro.mdx rename to app/(site)/(tools)/arr-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/arr-calculator/content/usage.mdx b/app/(site)/(tools)/arr-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/arr-calculator/content/usage.mdx rename to app/(site)/(tools)/arr-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/arr-calculator/layout.tsx b/app/(site)/(tools)/arr-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/arr-calculator/layout.tsx rename to app/(site)/(tools)/arr-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/arr-calculator/page.tsx b/app/(site)/(tools)/arr-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/arr-calculator/page.tsx rename to app/(site)/(tools)/arr-calculator/page.tsx diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/backup-321-calculator-from-url.tsx b/app/(site)/(tools)/backup-321-calculator/backup-321-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/backup-321-calculator/backup-321-calculator-from-url.tsx rename to app/(site)/(tools)/backup-321-calculator/backup-321-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/backup-321-calculator.module.css b/app/(site)/(tools)/backup-321-calculator/backup-321-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/backup-321-calculator/backup-321-calculator.module.css rename to app/(site)/(tools)/backup-321-calculator/backup-321-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/backup-321-calculator.tsx b/app/(site)/(tools)/backup-321-calculator/backup-321-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/backup-321-calculator/backup-321-calculator.tsx rename to app/(site)/(tools)/backup-321-calculator/backup-321-calculator.tsx diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/content/article.mdx b/app/(site)/(tools)/backup-321-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/backup-321-calculator/content/article.mdx rename to app/(site)/(tools)/backup-321-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/content/intro.mdx b/app/(site)/(tools)/backup-321-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/backup-321-calculator/content/intro.mdx rename to app/(site)/(tools)/backup-321-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/content/usage.mdx b/app/(site)/(tools)/backup-321-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/backup-321-calculator/content/usage.mdx rename to app/(site)/(tools)/backup-321-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/layout.tsx b/app/(site)/(tools)/backup-321-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/backup-321-calculator/layout.tsx rename to app/(site)/(tools)/backup-321-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/backup-321-calculator/page.tsx b/app/(site)/(tools)/backup-321-calculator/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/backup-321-calculator/page.tsx rename to app/(site)/(tools)/backup-321-calculator/page.tsx index 13d69699..d4f3b093 100644 --- a/app/(site)/(tools)/(storage)/backup-321-calculator/page.tsx +++ b/app/(site)/(tools)/backup-321-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { ShieldCheck } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { Backup321CalculatorFromUrl } from "./backup-321-calculator-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator.spec.json b/app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator.spec.json rename to app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator.svg b/app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator.svg rename to app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator.svg diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator.ts b/app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator.ts rename to app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator.ts diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/break-even-mrr-calculator.module.css b/app/(site)/(tools)/break-even-mrr-calculator/break-even-mrr-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/break-even-mrr-calculator.module.css rename to app/(site)/(tools)/break-even-mrr-calculator/break-even-mrr-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/break-even-mrr-calculator.tsx b/app/(site)/(tools)/break-even-mrr-calculator/break-even-mrr-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/break-even-mrr-calculator.tsx rename to app/(site)/(tools)/break-even-mrr-calculator/break-even-mrr-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/content/article.mdx b/app/(site)/(tools)/break-even-mrr-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/content/article.mdx rename to app/(site)/(tools)/break-even-mrr-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/content/intro.mdx b/app/(site)/(tools)/break-even-mrr-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/content/intro.mdx rename to app/(site)/(tools)/break-even-mrr-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/content/usage.mdx b/app/(site)/(tools)/break-even-mrr-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/content/usage.mdx rename to app/(site)/(tools)/break-even-mrr-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/layout.tsx b/app/(site)/(tools)/break-even-mrr-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/layout.tsx rename to app/(site)/(tools)/break-even-mrr-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/break-even-mrr-calculator/page.tsx b/app/(site)/(tools)/break-even-mrr-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/break-even-mrr-calculator/page.tsx rename to app/(site)/(tools)/break-even-mrr-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/burn-multiple-calculator/burn-multiple-calculator.module.css b/app/(site)/(tools)/burn-multiple-calculator/burn-multiple-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/burn-multiple-calculator/burn-multiple-calculator.module.css rename to app/(site)/(tools)/burn-multiple-calculator/burn-multiple-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/burn-multiple-calculator/burn-multiple-calculator.tsx b/app/(site)/(tools)/burn-multiple-calculator/burn-multiple-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/burn-multiple-calculator/burn-multiple-calculator.tsx rename to app/(site)/(tools)/burn-multiple-calculator/burn-multiple-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/burn-multiple-calculator/content/article.mdx b/app/(site)/(tools)/burn-multiple-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/burn-multiple-calculator/content/article.mdx rename to app/(site)/(tools)/burn-multiple-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/burn-multiple-calculator/content/intro.mdx b/app/(site)/(tools)/burn-multiple-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/burn-multiple-calculator/content/intro.mdx rename to app/(site)/(tools)/burn-multiple-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/burn-multiple-calculator/content/usage.mdx b/app/(site)/(tools)/burn-multiple-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/burn-multiple-calculator/content/usage.mdx rename to app/(site)/(tools)/burn-multiple-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/burn-multiple-calculator/layout.tsx b/app/(site)/(tools)/burn-multiple-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/burn-multiple-calculator/layout.tsx rename to app/(site)/(tools)/burn-multiple-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/burn-multiple-calculator/page.tsx b/app/(site)/(tools)/burn-multiple-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/burn-multiple-calculator/page.tsx rename to app/(site)/(tools)/burn-multiple-calculator/page.tsx diff --git a/app/(site)/(tools)/(dns)/caa-checker/caa-checker-from-url.tsx b/app/(site)/(tools)/caa-checker/caa-checker-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/caa-checker/caa-checker-from-url.tsx rename to app/(site)/(tools)/caa-checker/caa-checker-from-url.tsx diff --git a/app/(site)/(tools)/(dns)/caa-checker/caa-checker.module.css b/app/(site)/(tools)/caa-checker/caa-checker.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/caa-checker/caa-checker.module.css rename to app/(site)/(tools)/caa-checker/caa-checker.module.css diff --git a/app/(site)/(tools)/(dns)/caa-checker/caa-checker.tsx b/app/(site)/(tools)/caa-checker/caa-checker.tsx similarity index 99% rename from app/(site)/(tools)/(dns)/caa-checker/caa-checker.tsx rename to app/(site)/(tools)/caa-checker/caa-checker.tsx index a19189a6..d9023741 100644 --- a/app/(site)/(tools)/(dns)/caa-checker/caa-checker.tsx +++ b/app/(site)/(tools)/caa-checker/caa-checker.tsx @@ -4,7 +4,7 @@ import { useMemo, useRef, useState, type FormEvent } from "react"; import { UiButton, UiDownloadAction, UiRawOutput, UiTextField } from "@/app/ui/controls"; import { UiActionRow, UiDataTable, UiResultLead, UiStatus } from "@/app/ui/display"; import type { CaaRecord } from "@/lib/dns/diagnostic-types.ts"; -import { diagnosticReportJson } from "@/app/(site)/(tools)/(dns)/diagnostic-result-ui"; +import { diagnosticReportJson } from "@/app/ui/tools/dns/diagnostic-result-ui"; import styles from "./caa-checker.module.css"; type SearchReason = "requested" | "alias" | "parent"; diff --git a/app/(site)/(tools)/(dns)/caa-checker/content/article.mdx b/app/(site)/(tools)/caa-checker/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/caa-checker/content/article.mdx rename to app/(site)/(tools)/caa-checker/content/article.mdx diff --git a/app/(site)/(tools)/(dns)/caa-checker/content/intro.mdx b/app/(site)/(tools)/caa-checker/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/caa-checker/content/intro.mdx rename to app/(site)/(tools)/caa-checker/content/intro.mdx diff --git a/app/(site)/(tools)/(dns)/caa-checker/content/usage.mdx b/app/(site)/(tools)/caa-checker/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/caa-checker/content/usage.mdx rename to app/(site)/(tools)/caa-checker/content/usage.mdx diff --git a/app/(site)/(tools)/(dns)/caa-checker/layout.tsx b/app/(site)/(tools)/caa-checker/layout.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/caa-checker/layout.tsx rename to app/(site)/(tools)/caa-checker/layout.tsx diff --git a/app/(site)/(tools)/(dns)/caa-checker/page.tsx b/app/(site)/(tools)/caa-checker/page.tsx similarity index 92% rename from app/(site)/(tools)/(dns)/caa-checker/page.tsx rename to app/(site)/(tools)/caa-checker/page.tsx index c3781d90..06a554c2 100644 --- a/app/(site)/(tools)/(dns)/caa-checker/page.tsx +++ b/app/(site)/(tools)/caa-checker/page.tsx @@ -4,7 +4,7 @@ import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content import { getRequiredToolPage } from "@/lib/tool-pages"; import { FileKey } from "lucide-react"; import { CaaCheckerFromUrl } from "./caa-checker-from-url"; -import styles from "@/app/(site)/(tools)/(dns)/dns-diagnostics.module.css"; +import styles from "@/app/ui/tools/dns/dns-diagnostics.module.css"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; import Usage from "./content/usage.mdx"; diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator.spec.json b/app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator.spec.json rename to app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator.svg b/app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator.svg rename to app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator.svg diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator.ts b/app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator.ts rename to app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator.ts diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/cac-payback-calculator.module.css b/app/(site)/(tools)/cac-payback-calculator/cac-payback-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/cac-payback-calculator.module.css rename to app/(site)/(tools)/cac-payback-calculator/cac-payback-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/cac-payback-calculator.tsx b/app/(site)/(tools)/cac-payback-calculator/cac-payback-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/cac-payback-calculator.tsx rename to app/(site)/(tools)/cac-payback-calculator/cac-payback-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/content/article.mdx b/app/(site)/(tools)/cac-payback-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/content/article.mdx rename to app/(site)/(tools)/cac-payback-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/content/intro.mdx b/app/(site)/(tools)/cac-payback-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/content/intro.mdx rename to app/(site)/(tools)/cac-payback-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/content/usage.mdx b/app/(site)/(tools)/cac-payback-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/content/usage.mdx rename to app/(site)/(tools)/cac-payback-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/layout.tsx b/app/(site)/(tools)/cac-payback-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/layout.tsx rename to app/(site)/(tools)/cac-payback-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/cac-payback-calculator/page.tsx b/app/(site)/(tools)/cac-payback-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/cac-payback-calculator/page.tsx rename to app/(site)/(tools)/cac-payback-calculator/page.tsx diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-calculator-from-url.tsx b/app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-calculator-from-url.tsx rename to app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-calculator.module.css b/app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-calculator.module.css rename to app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-calculator.tsx b/app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-calculator.tsx rename to app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-calculator.tsx diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-engine.ts b/app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-engine.ts similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-engine.ts rename to app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-engine.ts diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/content/article.mdx b/app/(site)/(tools)/ceph-capacity-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/content/article.mdx rename to app/(site)/(tools)/ceph-capacity-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/content/intro.mdx b/app/(site)/(tools)/ceph-capacity-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/content/intro.mdx rename to app/(site)/(tools)/ceph-capacity-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/content/usage.mdx b/app/(site)/(tools)/ceph-capacity-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/content/usage.mdx rename to app/(site)/(tools)/ceph-capacity-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/layout.tsx b/app/(site)/(tools)/ceph-capacity-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/layout.tsx rename to app/(site)/(tools)/ceph-capacity-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/page.tsx b/app/(site)/(tools)/ceph-capacity-calculator/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/ceph-capacity-calculator/page.tsx rename to app/(site)/(tools)/ceph-capacity-calculator/page.tsx index df042cf1..09a7130f 100644 --- a/app/(site)/(tools)/(storage)/ceph-capacity-calculator/page.tsx +++ b/app/(site)/(tools)/ceph-capacity-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { ServerCog } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { CephCapacityCalculatorFromUrl } from "./ceph-capacity-calculator-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/art/churn-rate-converter.spec.json b/app/(site)/(tools)/churn-rate-converter/art/churn-rate-converter.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/art/churn-rate-converter.spec.json rename to app/(site)/(tools)/churn-rate-converter/art/churn-rate-converter.spec.json diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/art/churn-rate-converter.svg b/app/(site)/(tools)/churn-rate-converter/art/churn-rate-converter.svg similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/art/churn-rate-converter.svg rename to app/(site)/(tools)/churn-rate-converter/art/churn-rate-converter.svg diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/art/churn-rate-converter.ts b/app/(site)/(tools)/churn-rate-converter/art/churn-rate-converter.ts similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/art/churn-rate-converter.ts rename to app/(site)/(tools)/churn-rate-converter/art/churn-rate-converter.ts diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/churn-rate-converter.module.css b/app/(site)/(tools)/churn-rate-converter/churn-rate-converter.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/churn-rate-converter.module.css rename to app/(site)/(tools)/churn-rate-converter/churn-rate-converter.module.css diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/churn-rate-converter.tsx b/app/(site)/(tools)/churn-rate-converter/churn-rate-converter.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/churn-rate-converter.tsx rename to app/(site)/(tools)/churn-rate-converter/churn-rate-converter.tsx diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/content/article.mdx b/app/(site)/(tools)/churn-rate-converter/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/content/article.mdx rename to app/(site)/(tools)/churn-rate-converter/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/content/intro.mdx b/app/(site)/(tools)/churn-rate-converter/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/content/intro.mdx rename to app/(site)/(tools)/churn-rate-converter/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/content/usage.mdx b/app/(site)/(tools)/churn-rate-converter/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/content/usage.mdx rename to app/(site)/(tools)/churn-rate-converter/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/layout.tsx b/app/(site)/(tools)/churn-rate-converter/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/layout.tsx rename to app/(site)/(tools)/churn-rate-converter/layout.tsx diff --git a/app/(site)/(tools)/(saas)/churn-rate-converter/page.tsx b/app/(site)/(tools)/churn-rate-converter/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/churn-rate-converter/page.tsx rename to app/(site)/(tools)/churn-rate-converter/page.tsx diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.spec.json b/app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.spec.json rename to app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.svg b/app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.svg rename to app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.svg diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.ts b/app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.ts rename to app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.ts diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/content/article.mdx b/app/(site)/(tools)/customer-acquisition-cost-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/content/article.mdx rename to app/(site)/(tools)/customer-acquisition-cost-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/content/intro.mdx b/app/(site)/(tools)/customer-acquisition-cost-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/content/intro.mdx rename to app/(site)/(tools)/customer-acquisition-cost-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/content/usage.mdx b/app/(site)/(tools)/customer-acquisition-cost-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/content/usage.mdx rename to app/(site)/(tools)/customer-acquisition-cost-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.module.css b/app/(site)/(tools)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.module.css rename to app/(site)/(tools)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.tsx b/app/(site)/(tools)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.tsx rename to app/(site)/(tools)/customer-acquisition-cost-calculator/customer-acquisition-cost-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/layout.tsx b/app/(site)/(tools)/customer-acquisition-cost-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/layout.tsx rename to app/(site)/(tools)/customer-acquisition-cost-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/page.tsx b/app/(site)/(tools)/customer-acquisition-cost-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/page.tsx rename to app/(site)/(tools)/customer-acquisition-cost-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/customer-churn-calculator/content/article.mdx b/app/(site)/(tools)/customer-churn-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-churn-calculator/content/article.mdx rename to app/(site)/(tools)/customer-churn-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/customer-churn-calculator/content/intro.mdx b/app/(site)/(tools)/customer-churn-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-churn-calculator/content/intro.mdx rename to app/(site)/(tools)/customer-churn-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/customer-churn-calculator/content/usage.mdx b/app/(site)/(tools)/customer-churn-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-churn-calculator/content/usage.mdx rename to app/(site)/(tools)/customer-churn-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/customer-churn-calculator/customer-churn-calculator.module.css b/app/(site)/(tools)/customer-churn-calculator/customer-churn-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/customer-churn-calculator/customer-churn-calculator.module.css rename to app/(site)/(tools)/customer-churn-calculator/customer-churn-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/customer-churn-calculator/customer-churn-calculator.tsx b/app/(site)/(tools)/customer-churn-calculator/customer-churn-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-churn-calculator/customer-churn-calculator.tsx rename to app/(site)/(tools)/customer-churn-calculator/customer-churn-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/customer-churn-calculator/layout.tsx b/app/(site)/(tools)/customer-churn-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-churn-calculator/layout.tsx rename to app/(site)/(tools)/customer-churn-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/customer-churn-calculator/page.tsx b/app/(site)/(tools)/customer-churn-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-churn-calculator/page.tsx rename to app/(site)/(tools)/customer-churn-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.spec.json b/app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.spec.json rename to app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.svg b/app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.svg rename to app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.svg diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.ts b/app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.ts rename to app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.ts diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/content/article.mdx b/app/(site)/(tools)/customer-lifetime-value-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/content/article.mdx rename to app/(site)/(tools)/customer-lifetime-value-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/content/intro.mdx b/app/(site)/(tools)/customer-lifetime-value-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/content/intro.mdx rename to app/(site)/(tools)/customer-lifetime-value-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/content/usage.mdx b/app/(site)/(tools)/customer-lifetime-value-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/content/usage.mdx rename to app/(site)/(tools)/customer-lifetime-value-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.module.css b/app/(site)/(tools)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.module.css rename to app/(site)/(tools)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.tsx b/app/(site)/(tools)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.tsx rename to app/(site)/(tools)/customer-lifetime-value-calculator/customer-lifetime-value-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/layout.tsx b/app/(site)/(tools)/customer-lifetime-value-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/layout.tsx rename to app/(site)/(tools)/customer-lifetime-value-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/page.tsx b/app/(site)/(tools)/customer-lifetime-value-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/page.tsx rename to app/(site)/(tools)/customer-lifetime-value-calculator/page.tsx diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/content/article.mdx b/app/(site)/(tools)/dns-change-checker/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-change-checker/content/article.mdx rename to app/(site)/(tools)/dns-change-checker/content/article.mdx diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/content/intro.mdx b/app/(site)/(tools)/dns-change-checker/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-change-checker/content/intro.mdx rename to app/(site)/(tools)/dns-change-checker/content/intro.mdx diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/content/usage.mdx b/app/(site)/(tools)/dns-change-checker/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-change-checker/content/usage.mdx rename to app/(site)/(tools)/dns-change-checker/content/usage.mdx diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/dns-change-checker-from-url.tsx b/app/(site)/(tools)/dns-change-checker/dns-change-checker-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-change-checker/dns-change-checker-from-url.tsx rename to app/(site)/(tools)/dns-change-checker/dns-change-checker-from-url.tsx diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/dns-change-checker.module.css b/app/(site)/(tools)/dns-change-checker/dns-change-checker.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/dns-change-checker/dns-change-checker.module.css rename to app/(site)/(tools)/dns-change-checker/dns-change-checker.module.css diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/dns-change-checker.tsx b/app/(site)/(tools)/dns-change-checker/dns-change-checker.tsx similarity index 99% rename from app/(site)/(tools)/(dns)/dns-change-checker/dns-change-checker.tsx rename to app/(site)/(tools)/dns-change-checker/dns-change-checker.tsx index 59dfb7ec..86441170 100644 --- a/app/(site)/(tools)/(dns)/dns-change-checker/dns-change-checker.tsx +++ b/app/(site)/(tools)/dns-change-checker/dns-change-checker.tsx @@ -5,7 +5,7 @@ import { UiButton, UiDownloadAction, UiRawOutput, UiSelect, UiTextField, type Ui import { UiActionRow, UiDataTable, UiResultLead, UiStatus } from "@/app/ui/display"; import { CHANGE_RECORD_TYPES, type ChangeRecordType, type DnsSourceAnswer } from "@/lib/dns/diagnostic-types.ts"; import { groupDnsSources } from "@/lib/dns/diagnostic-presentation.ts"; -import { diagnosticReportJson } from "@/app/(site)/(tools)/(dns)/diagnostic-result-ui"; +import { diagnosticReportJson } from "@/app/ui/tools/dns/diagnostic-result-ui"; import styles from "./dns-change-checker.module.css"; type Result = { diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/layout.tsx b/app/(site)/(tools)/dns-change-checker/layout.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-change-checker/layout.tsx rename to app/(site)/(tools)/dns-change-checker/layout.tsx diff --git a/app/(site)/(tools)/(dns)/dns-change-checker/page.tsx b/app/(site)/(tools)/dns-change-checker/page.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-change-checker/page.tsx rename to app/(site)/(tools)/dns-change-checker/page.tsx diff --git a/app/(site)/(tools)/(dns)/dns-lookup/content/article.mdx b/app/(site)/(tools)/dns-lookup/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-lookup/content/article.mdx rename to app/(site)/(tools)/dns-lookup/content/article.mdx diff --git a/app/(site)/(tools)/(dns)/dns-lookup/content/intro.mdx b/app/(site)/(tools)/dns-lookup/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-lookup/content/intro.mdx rename to app/(site)/(tools)/dns-lookup/content/intro.mdx diff --git a/app/(site)/(tools)/(dns)/dns-lookup/content/usage.mdx b/app/(site)/(tools)/dns-lookup/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-lookup/content/usage.mdx rename to app/(site)/(tools)/dns-lookup/content/usage.mdx diff --git a/app/(site)/(tools)/(dns)/dns-lookup/dns-lookup-content.module.css b/app/(site)/(tools)/dns-lookup/dns-lookup-content.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/dns-lookup/dns-lookup-content.module.css rename to app/(site)/(tools)/dns-lookup/dns-lookup-content.module.css diff --git a/app/(site)/(tools)/(dns)/dns-lookup/dns-lookup-from-url.tsx b/app/(site)/(tools)/dns-lookup/dns-lookup-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-lookup/dns-lookup-from-url.tsx rename to app/(site)/(tools)/dns-lookup/dns-lookup-from-url.tsx diff --git a/app/(site)/(tools)/(dns)/dns-lookup/dns-lookup-tool.tsx b/app/(site)/(tools)/dns-lookup/dns-lookup-tool.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-lookup/dns-lookup-tool.tsx rename to app/(site)/(tools)/dns-lookup/dns-lookup-tool.tsx diff --git a/app/(site)/(tools)/(dns)/dns-lookup/layout.tsx b/app/(site)/(tools)/dns-lookup/layout.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-lookup/layout.tsx rename to app/(site)/(tools)/dns-lookup/layout.tsx diff --git a/app/(site)/(tools)/(dns)/dns-lookup/page.tsx b/app/(site)/(tools)/dns-lookup/page.tsx similarity index 96% rename from app/(site)/(tools)/(dns)/dns-lookup/page.tsx rename to app/(site)/(tools)/dns-lookup/page.tsx index 419bd90a..c5a9192a 100644 --- a/app/(site)/(tools)/(dns)/dns-lookup/page.tsx +++ b/app/(site)/(tools)/dns-lookup/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/dns/dns-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(dns)/dns-trace/content/article.mdx b/app/(site)/(tools)/dns-trace/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/content/article.mdx rename to app/(site)/(tools)/dns-trace/content/article.mdx diff --git a/app/(site)/(tools)/(dns)/dns-trace/content/intro.mdx b/app/(site)/(tools)/dns-trace/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/content/intro.mdx rename to app/(site)/(tools)/dns-trace/content/intro.mdx diff --git a/app/(site)/(tools)/(dns)/dns-trace/content/usage.mdx b/app/(site)/(tools)/dns-trace/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/content/usage.mdx rename to app/(site)/(tools)/dns-trace/content/usage.mdx diff --git a/app/(site)/(tools)/(dns)/dns-trace/dns-trace-format.ts b/app/(site)/(tools)/dns-trace/dns-trace-format.ts similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/dns-trace-format.ts rename to app/(site)/(tools)/dns-trace/dns-trace-format.ts diff --git a/app/(site)/(tools)/(dns)/dns-trace/dns-trace-from-url.tsx b/app/(site)/(tools)/dns-trace/dns-trace-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/dns-trace-from-url.tsx rename to app/(site)/(tools)/dns-trace/dns-trace-from-url.tsx diff --git a/app/(site)/(tools)/(dns)/dns-trace/dns-trace-tool.tsx b/app/(site)/(tools)/dns-trace/dns-trace-tool.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/dns-trace-tool.tsx rename to app/(site)/(tools)/dns-trace/dns-trace-tool.tsx diff --git a/app/(site)/(tools)/(dns)/dns-trace/dns-trace.module.css b/app/(site)/(tools)/dns-trace/dns-trace.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/dns-trace.module.css rename to app/(site)/(tools)/dns-trace/dns-trace.module.css diff --git a/app/(site)/(tools)/(dns)/dns-trace/layout.tsx b/app/(site)/(tools)/dns-trace/layout.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/layout.tsx rename to app/(site)/(tools)/dns-trace/layout.tsx diff --git a/app/(site)/(tools)/(dns)/dns-trace/page.tsx b/app/(site)/(tools)/dns-trace/page.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dns-trace/page.tsx rename to app/(site)/(tools)/dns-trace/page.tsx diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/content/article.mdx b/app/(site)/(tools)/dnssec-checker/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dnssec-checker/content/article.mdx rename to app/(site)/(tools)/dnssec-checker/content/article.mdx diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/content/intro.mdx b/app/(site)/(tools)/dnssec-checker/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dnssec-checker/content/intro.mdx rename to app/(site)/(tools)/dnssec-checker/content/intro.mdx diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/content/usage.mdx b/app/(site)/(tools)/dnssec-checker/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/dnssec-checker/content/usage.mdx rename to app/(site)/(tools)/dnssec-checker/content/usage.mdx diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/dnssec-checker-from-url.tsx b/app/(site)/(tools)/dnssec-checker/dnssec-checker-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dnssec-checker/dnssec-checker-from-url.tsx rename to app/(site)/(tools)/dnssec-checker/dnssec-checker-from-url.tsx diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/dnssec-checker.module.css b/app/(site)/(tools)/dnssec-checker/dnssec-checker.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/dnssec-checker/dnssec-checker.module.css rename to app/(site)/(tools)/dnssec-checker/dnssec-checker.module.css diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/dnssec-checker.tsx b/app/(site)/(tools)/dnssec-checker/dnssec-checker.tsx similarity index 99% rename from app/(site)/(tools)/(dns)/dnssec-checker/dnssec-checker.tsx rename to app/(site)/(tools)/dnssec-checker/dnssec-checker.tsx index 400bff85..213e6dac 100644 --- a/app/(site)/(tools)/(dns)/dnssec-checker/dnssec-checker.tsx +++ b/app/(site)/(tools)/dnssec-checker/dnssec-checker.tsx @@ -6,7 +6,7 @@ import { UiButton, UiChoiceGroup, UiDisclosure, UiDownloadAction, UiRawOutput, U import { UiActionRow, UiDataTable, UiKeyValueList, UiResultLead, UiStatus } from "@/app/ui/display"; import { DNSSEC_RECORD_TYPES, type DnssecRecordType, type DnssecSignature, type DnssecVerdict } from "@/lib/dns/dnssec-types.ts"; import type { NormalizedDnsRecord } from "@/lib/dns/types.ts"; -import { diagnosticReportJson } from "@/app/(site)/(tools)/(dns)/diagnostic-result-ui"; +import { diagnosticReportJson } from "@/app/ui/tools/dns/diagnostic-result-ui"; import styles from "./dnssec-checker.module.css"; type Evidence = { diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/layout.tsx b/app/(site)/(tools)/dnssec-checker/layout.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dnssec-checker/layout.tsx rename to app/(site)/(tools)/dnssec-checker/layout.tsx diff --git a/app/(site)/(tools)/(dns)/dnssec-checker/page.tsx b/app/(site)/(tools)/dnssec-checker/page.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/dnssec-checker/page.tsx rename to app/(site)/(tools)/dnssec-checker/page.tsx diff --git a/app/(site)/(tools)/(domain)/domain-age/content/article.mdx b/app/(site)/(tools)/domain-age/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-age/content/article.mdx rename to app/(site)/(tools)/domain-age/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/domain-age/content/intro.mdx b/app/(site)/(tools)/domain-age/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-age/content/intro.mdx rename to app/(site)/(tools)/domain-age/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/domain-age/content/usage.mdx b/app/(site)/(tools)/domain-age/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-age/content/usage.mdx rename to app/(site)/(tools)/domain-age/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/domain-age/domain-age-content.module.css b/app/(site)/(tools)/domain-age/domain-age-content.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-age/domain-age-content.module.css rename to app/(site)/(tools)/domain-age/domain-age-content.module.css diff --git a/app/(site)/(tools)/(domain)/domain-age/domain-age-from-url.tsx b/app/(site)/(tools)/domain-age/domain-age-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-age/domain-age-from-url.tsx rename to app/(site)/(tools)/domain-age/domain-age-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/domain-age/domain-age-tool.module.css b/app/(site)/(tools)/domain-age/domain-age-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-age/domain-age-tool.module.css rename to app/(site)/(tools)/domain-age/domain-age-tool.module.css diff --git a/app/(site)/(tools)/(domain)/domain-age/domain-age-tool.tsx b/app/(site)/(tools)/domain-age/domain-age-tool.tsx similarity index 99% rename from app/(site)/(tools)/(domain)/domain-age/domain-age-tool.tsx rename to app/(site)/(tools)/domain-age/domain-age-tool.tsx index 32f856bb..54229fcb 100644 --- a/app/(site)/(tools)/(domain)/domain-age/domain-age-tool.tsx +++ b/app/(site)/(tools)/domain-age/domain-age-tool.tsx @@ -10,7 +10,7 @@ import { humanDuration, reportJson, useDomainLookup, -} from "@/app/(site)/(tools)/(domain)/domain-lookup-client"; +} from "@/app/ui/tools/domain/domain-lookup-client"; import styles from "./domain-age-tool.module.css"; function sourceHost(fetch: RdapFetch | null) { diff --git a/app/(site)/(tools)/(domain)/domain-age/layout.tsx b/app/(site)/(tools)/domain-age/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-age/layout.tsx rename to app/(site)/(tools)/domain-age/layout.tsx diff --git a/app/(site)/(tools)/(domain)/domain-age/page.tsx b/app/(site)/(tools)/domain-age/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/domain-age/page.tsx rename to app/(site)/(tools)/domain-age/page.tsx index f65f951d..52c5aad5 100644 --- a/app/(site)/(tools)/(domain)/domain-age/page.tsx +++ b/app/(site)/(tools)/domain-age/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/domain-availability/content/article.mdx b/app/(site)/(tools)/domain-availability/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-availability/content/article.mdx rename to app/(site)/(tools)/domain-availability/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/domain-availability/content/intro.mdx b/app/(site)/(tools)/domain-availability/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-availability/content/intro.mdx rename to app/(site)/(tools)/domain-availability/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/domain-availability/content/usage.mdx b/app/(site)/(tools)/domain-availability/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-availability/content/usage.mdx rename to app/(site)/(tools)/domain-availability/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/domain-availability/domain-availability-from-url.tsx b/app/(site)/(tools)/domain-availability/domain-availability-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-availability/domain-availability-from-url.tsx rename to app/(site)/(tools)/domain-availability/domain-availability-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/domain-availability/domain-availability-tool.module.css b/app/(site)/(tools)/domain-availability/domain-availability-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-availability/domain-availability-tool.module.css rename to app/(site)/(tools)/domain-availability/domain-availability-tool.module.css diff --git a/app/(site)/(tools)/(domain)/domain-availability/domain-availability-tool.tsx b/app/(site)/(tools)/domain-availability/domain-availability-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-availability/domain-availability-tool.tsx rename to app/(site)/(tools)/domain-availability/domain-availability-tool.tsx diff --git a/app/(site)/(tools)/(domain)/domain-availability/domain-availability-view.ts b/app/(site)/(tools)/domain-availability/domain-availability-view.ts similarity index 99% rename from app/(site)/(tools)/(domain)/domain-availability/domain-availability-view.ts rename to app/(site)/(tools)/domain-availability/domain-availability-view.ts index a63eee62..3506079c 100644 --- a/app/(site)/(tools)/(domain)/domain-availability/domain-availability-view.ts +++ b/app/(site)/(tools)/domain-availability/domain-availability-view.ts @@ -1,4 +1,4 @@ -import type { DomainRegistration, RdapFetchStatus } from "../../../../../lib/domain/types.ts"; +import type { DomainRegistration, RdapFetchStatus } from "../../../../lib/domain/types.ts"; const releaseStatuses = new Set(["redemption period", "pending delete"]); diff --git a/app/(site)/(tools)/(domain)/domain-availability/layout.tsx b/app/(site)/(tools)/domain-availability/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-availability/layout.tsx rename to app/(site)/(tools)/domain-availability/layout.tsx diff --git a/app/(site)/(tools)/(domain)/domain-availability/page.tsx b/app/(site)/(tools)/domain-availability/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/domain-availability/page.tsx rename to app/(site)/(tools)/domain-availability/page.tsx index 16f53d60..cff5e635 100644 --- a/app/(site)/(tools)/(domain)/domain-availability/page.tsx +++ b/app/(site)/(tools)/domain-availability/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/domain-expiry/content/article.mdx b/app/(site)/(tools)/domain-expiry/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-expiry/content/article.mdx rename to app/(site)/(tools)/domain-expiry/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/domain-expiry/content/intro.mdx b/app/(site)/(tools)/domain-expiry/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-expiry/content/intro.mdx rename to app/(site)/(tools)/domain-expiry/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/domain-expiry/content/usage.mdx b/app/(site)/(tools)/domain-expiry/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-expiry/content/usage.mdx rename to app/(site)/(tools)/domain-expiry/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/domain-expiry/domain-expiry-from-url.tsx b/app/(site)/(tools)/domain-expiry/domain-expiry-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-expiry/domain-expiry-from-url.tsx rename to app/(site)/(tools)/domain-expiry/domain-expiry-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/domain-expiry/domain-expiry-tool.module.css b/app/(site)/(tools)/domain-expiry/domain-expiry-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-expiry/domain-expiry-tool.module.css rename to app/(site)/(tools)/domain-expiry/domain-expiry-tool.module.css diff --git a/app/(site)/(tools)/(domain)/domain-expiry/domain-expiry-tool.tsx b/app/(site)/(tools)/domain-expiry/domain-expiry-tool.tsx similarity index 99% rename from app/(site)/(tools)/(domain)/domain-expiry/domain-expiry-tool.tsx rename to app/(site)/(tools)/domain-expiry/domain-expiry-tool.tsx index 7eff4a23..8a225bc9 100644 --- a/app/(site)/(tools)/(domain)/domain-expiry/domain-expiry-tool.tsx +++ b/app/(site)/(tools)/domain-expiry/domain-expiry-tool.tsx @@ -11,7 +11,7 @@ import { humanDuration, reportJson, useDomainLookup, -} from "@/app/(site)/(tools)/(domain)/domain-lookup-client"; +} from "@/app/ui/tools/domain/domain-lookup-client"; import styles from "./domain-expiry-tool.module.css"; const EXPIRY_PATH = [ diff --git a/app/(site)/(tools)/(domain)/domain-expiry/layout.tsx b/app/(site)/(tools)/domain-expiry/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-expiry/layout.tsx rename to app/(site)/(tools)/domain-expiry/layout.tsx diff --git a/app/(site)/(tools)/(domain)/domain-expiry/page.tsx b/app/(site)/(tools)/domain-expiry/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/domain-expiry/page.tsx rename to app/(site)/(tools)/domain-expiry/page.tsx index f322d5c7..3411dee6 100644 --- a/app/(site)/(tools)/(domain)/domain-expiry/page.tsx +++ b/app/(site)/(tools)/domain-expiry/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/domain-lookup/content/article.mdx b/app/(site)/(tools)/domain-lookup/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup/content/article.mdx rename to app/(site)/(tools)/domain-lookup/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/domain-lookup/content/intro.mdx b/app/(site)/(tools)/domain-lookup/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup/content/intro.mdx rename to app/(site)/(tools)/domain-lookup/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/domain-lookup/content/usage.mdx b/app/(site)/(tools)/domain-lookup/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup/content/usage.mdx rename to app/(site)/(tools)/domain-lookup/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-from-url.tsx b/app/(site)/(tools)/domain-lookup/domain-lookup-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-from-url.tsx rename to app/(site)/(tools)/domain-lookup/domain-lookup-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-tool.module.css b/app/(site)/(tools)/domain-lookup/domain-lookup-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-tool.module.css rename to app/(site)/(tools)/domain-lookup/domain-lookup-tool.module.css diff --git a/app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-tool.tsx b/app/(site)/(tools)/domain-lookup/domain-lookup-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-tool.tsx rename to app/(site)/(tools)/domain-lookup/domain-lookup-tool.tsx diff --git a/app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-view.ts b/app/(site)/(tools)/domain-lookup/domain-lookup-view.ts similarity index 98% rename from app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-view.ts rename to app/(site)/(tools)/domain-lookup/domain-lookup-view.ts index 20d5a265..633f0b15 100644 --- a/app/(site)/(tools)/(domain)/domain-lookup/domain-lookup-view.ts +++ b/app/(site)/(tools)/domain-lookup/domain-lookup-view.ts @@ -1,5 +1,5 @@ -import { lookupStatus } from "../../../../../lib/domain/status-codes.ts"; -import type { DomainRegistration, RdapFetchStatus, RdapSource } from "../../../../../lib/domain/types.ts"; +import { lookupStatus } from "../../../../lib/domain/status-codes.ts"; +import type { DomainRegistration, RdapFetchStatus, RdapSource } from "../../../../lib/domain/types.ts"; export function formatLookupDate(value: string | null) { if (!value) return null; diff --git a/app/(site)/(tools)/(domain)/domain-lookup/layout.tsx b/app/(site)/(tools)/domain-lookup/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup/layout.tsx rename to app/(site)/(tools)/domain-lookup/layout.tsx diff --git a/app/(site)/(tools)/(domain)/domain-lookup/page.tsx b/app/(site)/(tools)/domain-lookup/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/domain-lookup/page.tsx rename to app/(site)/(tools)/domain-lookup/page.tsx index c5fe0b39..da163fb6 100644 --- a/app/(site)/(tools)/(domain)/domain-lookup/page.tsx +++ b/app/(site)/(tools)/domain-lookup/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/domain-owner/content/article.mdx b/app/(site)/(tools)/domain-owner/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-owner/content/article.mdx rename to app/(site)/(tools)/domain-owner/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/domain-owner/content/intro.mdx b/app/(site)/(tools)/domain-owner/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-owner/content/intro.mdx rename to app/(site)/(tools)/domain-owner/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/domain-owner/content/usage.mdx b/app/(site)/(tools)/domain-owner/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-owner/content/usage.mdx rename to app/(site)/(tools)/domain-owner/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/domain-owner/domain-owner-from-url.tsx b/app/(site)/(tools)/domain-owner/domain-owner-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-owner/domain-owner-from-url.tsx rename to app/(site)/(tools)/domain-owner/domain-owner-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/domain-owner/domain-owner-tool.module.css b/app/(site)/(tools)/domain-owner/domain-owner-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-owner/domain-owner-tool.module.css rename to app/(site)/(tools)/domain-owner/domain-owner-tool.module.css diff --git a/app/(site)/(tools)/(domain)/domain-owner/domain-owner-tool.tsx b/app/(site)/(tools)/domain-owner/domain-owner-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-owner/domain-owner-tool.tsx rename to app/(site)/(tools)/domain-owner/domain-owner-tool.tsx diff --git a/app/(site)/(tools)/(domain)/domain-owner/domain-owner-view.ts b/app/(site)/(tools)/domain-owner/domain-owner-view.ts similarity index 99% rename from app/(site)/(tools)/(domain)/domain-owner/domain-owner-view.ts rename to app/(site)/(tools)/domain-owner/domain-owner-view.ts index edf1b99f..da510ae0 100644 --- a/app/(site)/(tools)/(domain)/domain-owner/domain-owner-view.ts +++ b/app/(site)/(tools)/domain-owner/domain-owner-view.ts @@ -1,11 +1,11 @@ -import { declaresRedaction, parseRedactions } from "../../../../../lib/domain/redaction.ts"; +import { declaresRedaction, parseRedactions } from "../../../../lib/domain/redaction.ts"; import type { DomainEntity, DomainRegistration, RdapFetch, RdapFetchStatus, RdapSource, -} from "../../../../../lib/domain/types.ts"; +} from "../../../../lib/domain/types.ts"; const ROLE_LABELS: Record = { registrant: "Registrant", diff --git a/app/(site)/(tools)/(domain)/domain-owner/layout.tsx b/app/(site)/(tools)/domain-owner/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-owner/layout.tsx rename to app/(site)/(tools)/domain-owner/layout.tsx diff --git a/app/(site)/(tools)/(domain)/domain-owner/page.tsx b/app/(site)/(tools)/domain-owner/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/domain-owner/page.tsx rename to app/(site)/(tools)/domain-owner/page.tsx index 7e0f402c..6c907e02 100644 --- a/app/(site)/(tools)/(domain)/domain-owner/page.tsx +++ b/app/(site)/(tools)/domain-owner/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/domain-registrar/content/article.mdx b/app/(site)/(tools)/domain-registrar/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-registrar/content/article.mdx rename to app/(site)/(tools)/domain-registrar/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/domain-registrar/content/intro.mdx b/app/(site)/(tools)/domain-registrar/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-registrar/content/intro.mdx rename to app/(site)/(tools)/domain-registrar/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/domain-registrar/content/usage.mdx b/app/(site)/(tools)/domain-registrar/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-registrar/content/usage.mdx rename to app/(site)/(tools)/domain-registrar/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-from-url.tsx b/app/(site)/(tools)/domain-registrar/domain-registrar-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-from-url.tsx rename to app/(site)/(tools)/domain-registrar/domain-registrar-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-tool.module.css b/app/(site)/(tools)/domain-registrar/domain-registrar-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-tool.module.css rename to app/(site)/(tools)/domain-registrar/domain-registrar-tool.module.css diff --git a/app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-tool.tsx b/app/(site)/(tools)/domain-registrar/domain-registrar-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-tool.tsx rename to app/(site)/(tools)/domain-registrar/domain-registrar-tool.tsx diff --git a/app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-view.ts b/app/(site)/(tools)/domain-registrar/domain-registrar-view.ts similarity index 99% rename from app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-view.ts rename to app/(site)/(tools)/domain-registrar/domain-registrar-view.ts index 26dd61ae..ff5b40b1 100644 --- a/app/(site)/(tools)/(domain)/domain-registrar/domain-registrar-view.ts +++ b/app/(site)/(tools)/domain-registrar/domain-registrar-view.ts @@ -1,4 +1,4 @@ -import type { DomainEntity, DomainRegistration, RdapSource } from "../../../../../lib/domain/types.ts"; +import type { DomainEntity, DomainRegistration, RdapSource } from "../../../../lib/domain/types.ts"; type RegistrarCandidate = { id: string | null; name: string | null; source: RdapSource }; diff --git a/app/(site)/(tools)/(domain)/domain-registrar/layout.tsx b/app/(site)/(tools)/domain-registrar/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-registrar/layout.tsx rename to app/(site)/(tools)/domain-registrar/layout.tsx diff --git a/app/(site)/(tools)/(domain)/domain-registrar/page.tsx b/app/(site)/(tools)/domain-registrar/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/domain-registrar/page.tsx rename to app/(site)/(tools)/domain-registrar/page.tsx index b6e2acb4..303d700e 100644 --- a/app/(site)/(tools)/(domain)/domain-registrar/page.tsx +++ b/app/(site)/(tools)/domain-registrar/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/domain-report/content/article.mdx b/app/(site)/(tools)/domain-report/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-report/content/article.mdx rename to app/(site)/(tools)/domain-report/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/domain-report/content/intro.mdx b/app/(site)/(tools)/domain-report/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-report/content/intro.mdx rename to app/(site)/(tools)/domain-report/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/domain-report/content/usage.mdx b/app/(site)/(tools)/domain-report/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-report/content/usage.mdx rename to app/(site)/(tools)/domain-report/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/domain-report/domain-report-from-url.tsx b/app/(site)/(tools)/domain-report/domain-report-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-report/domain-report-from-url.tsx rename to app/(site)/(tools)/domain-report/domain-report-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/domain-report/domain-report-tool.module.css b/app/(site)/(tools)/domain-report/domain-report-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-report/domain-report-tool.module.css rename to app/(site)/(tools)/domain-report/domain-report-tool.module.css diff --git a/app/(site)/(tools)/(domain)/domain-report/domain-report-tool.tsx b/app/(site)/(tools)/domain-report/domain-report-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-report/domain-report-tool.tsx rename to app/(site)/(tools)/domain-report/domain-report-tool.tsx diff --git a/app/(site)/(tools)/(domain)/domain-report/domain-report-view.ts b/app/(site)/(tools)/domain-report/domain-report-view.ts similarity index 99% rename from app/(site)/(tools)/(domain)/domain-report/domain-report-view.ts rename to app/(site)/(tools)/domain-report/domain-report-view.ts index dbbdaecf..12e41b66 100644 --- a/app/(site)/(tools)/(domain)/domain-report/domain-report-view.ts +++ b/app/(site)/(tools)/domain-report/domain-report-view.ts @@ -1,4 +1,4 @@ -import type { DomainReport, ReportFinding, ReportFindingState } from "../../../../../lib/domain/report.ts"; +import type { DomainReport, ReportFinding, ReportFindingState } from "../../../../lib/domain/report.ts"; function reportDomain(result: DomainReport, fallback = "this domain") { return result.registration?.query.unicode ?? result.delegation?.zone ?? fallback; diff --git a/app/(site)/(tools)/(domain)/domain-report/layout.tsx b/app/(site)/(tools)/domain-report/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-report/layout.tsx rename to app/(site)/(tools)/domain-report/layout.tsx diff --git a/app/(site)/(tools)/(domain)/domain-report/page.tsx b/app/(site)/(tools)/domain-report/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/domain-report/page.tsx rename to app/(site)/(tools)/domain-report/page.tsx index 48f89047..2fe07d7d 100644 --- a/app/(site)/(tools)/(domain)/domain-report/page.tsx +++ b/app/(site)/(tools)/domain-report/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(storage)/drive-reliability/content/article.mdx b/app/(site)/(tools)/drive-reliability/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/content/article.mdx rename to app/(site)/(tools)/drive-reliability/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/drive-reliability/content/intro.mdx b/app/(site)/(tools)/drive-reliability/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/content/intro.mdx rename to app/(site)/(tools)/drive-reliability/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/drive-reliability/content/usage.mdx b/app/(site)/(tools)/drive-reliability/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/content/usage.mdx rename to app/(site)/(tools)/drive-reliability/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/drive-reliability/data/drive-reliability-snapshot.json b/app/(site)/(tools)/drive-reliability/data/drive-reliability-snapshot.json similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/data/drive-reliability-snapshot.json rename to app/(site)/(tools)/drive-reliability/data/drive-reliability-snapshot.json diff --git a/app/(site)/(tools)/(storage)/drive-reliability/drive-reliability-from-url.tsx b/app/(site)/(tools)/drive-reliability/drive-reliability-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/drive-reliability-from-url.tsx rename to app/(site)/(tools)/drive-reliability/drive-reliability-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/drive-reliability/drive-reliability.module.css b/app/(site)/(tools)/drive-reliability/drive-reliability.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/drive-reliability.module.css rename to app/(site)/(tools)/drive-reliability/drive-reliability.module.css diff --git a/app/(site)/(tools)/(storage)/drive-reliability/drive-reliability.tsx b/app/(site)/(tools)/drive-reliability/drive-reliability.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/drive-reliability.tsx rename to app/(site)/(tools)/drive-reliability/drive-reliability.tsx diff --git a/app/(site)/(tools)/(storage)/drive-reliability/layout.tsx b/app/(site)/(tools)/drive-reliability/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/drive-reliability/layout.tsx rename to app/(site)/(tools)/drive-reliability/layout.tsx diff --git a/app/(site)/(tools)/(storage)/drive-reliability/page.tsx b/app/(site)/(tools)/drive-reliability/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/drive-reliability/page.tsx rename to app/(site)/(tools)/drive-reliability/page.tsx index 7739681d..9818a485 100644 --- a/app/(site)/(tools)/(storage)/drive-reliability/page.tsx +++ b/app/(site)/(tools)/drive-reliability/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { HardDrive } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import snapshotData from "./data/drive-reliability-snapshot.json"; import { DriveReliabilityFromUrl } from "./drive-reliability-from-url"; import type { DriveReliabilitySnapshot } from "@/lib/drive-reliability"; diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.spec.json b/app/(site)/(tools)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.spec.json rename to app/(site)/(tools)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.svg b/app/(site)/(tools)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.svg rename to app/(site)/(tools)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.svg diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.ts b/app/(site)/(tools)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.ts rename to app/(site)/(tools)/free-trial-conversion-calculator/art/free-trial-conversion-calculator.ts diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/content/article.mdx b/app/(site)/(tools)/free-trial-conversion-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/content/article.mdx rename to app/(site)/(tools)/free-trial-conversion-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/content/intro.mdx b/app/(site)/(tools)/free-trial-conversion-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/content/intro.mdx rename to app/(site)/(tools)/free-trial-conversion-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/content/usage.mdx b/app/(site)/(tools)/free-trial-conversion-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/content/usage.mdx rename to app/(site)/(tools)/free-trial-conversion-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/free-trial-conversion-calculator-from-url.tsx b/app/(site)/(tools)/free-trial-conversion-calculator/free-trial-conversion-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/free-trial-conversion-calculator-from-url.tsx rename to app/(site)/(tools)/free-trial-conversion-calculator/free-trial-conversion-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/free-trial-conversion-calculator.module.css b/app/(site)/(tools)/free-trial-conversion-calculator/free-trial-conversion-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/free-trial-conversion-calculator.module.css rename to app/(site)/(tools)/free-trial-conversion-calculator/free-trial-conversion-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/free-trial-conversion-calculator.tsx b/app/(site)/(tools)/free-trial-conversion-calculator/free-trial-conversion-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/free-trial-conversion-calculator.tsx rename to app/(site)/(tools)/free-trial-conversion-calculator/free-trial-conversion-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/layout.tsx b/app/(site)/(tools)/free-trial-conversion-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/layout.tsx rename to app/(site)/(tools)/free-trial-conversion-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/page.tsx b/app/(site)/(tools)/free-trial-conversion-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/page.tsx rename to app/(site)/(tools)/free-trial-conversion-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/published-figures.ts b/app/(site)/(tools)/free-trial-conversion-calculator/published-figures.ts similarity index 100% rename from app/(site)/(tools)/(saas)/free-trial-conversion-calculator/published-figures.ts rename to app/(site)/(tools)/free-trial-conversion-calculator/published-figures.ts diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator.spec.json b/app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator.spec.json rename to app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator.svg b/app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator.svg rename to app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator.svg diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator.ts b/app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator.ts rename to app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator.ts diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/content/article.mdx b/app/(site)/(tools)/ltv-cac-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/content/article.mdx rename to app/(site)/(tools)/ltv-cac-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/content/intro.mdx b/app/(site)/(tools)/ltv-cac-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/content/intro.mdx rename to app/(site)/(tools)/ltv-cac-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/content/usage.mdx b/app/(site)/(tools)/ltv-cac-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/content/usage.mdx rename to app/(site)/(tools)/ltv-cac-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/layout.tsx b/app/(site)/(tools)/ltv-cac-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/layout.tsx rename to app/(site)/(tools)/ltv-cac-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/ltv-cac-calculator.module.css b/app/(site)/(tools)/ltv-cac-calculator/ltv-cac-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/ltv-cac-calculator.module.css rename to app/(site)/(tools)/ltv-cac-calculator/ltv-cac-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/ltv-cac-calculator.tsx b/app/(site)/(tools)/ltv-cac-calculator/ltv-cac-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/ltv-cac-calculator.tsx rename to app/(site)/(tools)/ltv-cac-calculator/ltv-cac-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/ltv-cac-calculator/page.tsx b/app/(site)/(tools)/ltv-cac-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/ltv-cac-calculator/page.tsx rename to app/(site)/(tools)/ltv-cac-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-calculator/content/article.mdx b/app/(site)/(tools)/mrr-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-calculator/content/article.mdx rename to app/(site)/(tools)/mrr-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-calculator/content/intro.mdx b/app/(site)/(tools)/mrr-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-calculator/content/intro.mdx rename to app/(site)/(tools)/mrr-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-calculator/content/usage.mdx b/app/(site)/(tools)/mrr-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-calculator/content/usage.mdx rename to app/(site)/(tools)/mrr-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-calculator/layout.tsx b/app/(site)/(tools)/mrr-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-calculator/layout.tsx rename to app/(site)/(tools)/mrr-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-calculator/mrr-calculator.module.css b/app/(site)/(tools)/mrr-calculator/mrr-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-calculator/mrr-calculator.module.css rename to app/(site)/(tools)/mrr-calculator/mrr-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/mrr-calculator/mrr-calculator.tsx b/app/(site)/(tools)/mrr-calculator/mrr-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-calculator/mrr-calculator.tsx rename to app/(site)/(tools)/mrr-calculator/mrr-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-calculator/page.tsx b/app/(site)/(tools)/mrr-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-calculator/page.tsx rename to app/(site)/(tools)/mrr-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator.spec.json b/app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator.spec.json rename to app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator.svg b/app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator.svg rename to app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator.svg diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator.ts b/app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator.ts rename to app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator.ts diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/content/article.mdx b/app/(site)/(tools)/mrr-goal-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/content/article.mdx rename to app/(site)/(tools)/mrr-goal-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/content/intro.mdx b/app/(site)/(tools)/mrr-goal-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/content/intro.mdx rename to app/(site)/(tools)/mrr-goal-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/content/usage.mdx b/app/(site)/(tools)/mrr-goal-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/content/usage.mdx rename to app/(site)/(tools)/mrr-goal-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/layout.tsx b/app/(site)/(tools)/mrr-goal-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/layout.tsx rename to app/(site)/(tools)/mrr-goal-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/mrr-goal-calculator.module.css b/app/(site)/(tools)/mrr-goal-calculator/mrr-goal-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/mrr-goal-calculator.module.css rename to app/(site)/(tools)/mrr-goal-calculator/mrr-goal-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/mrr-goal-calculator.tsx b/app/(site)/(tools)/mrr-goal-calculator/mrr-goal-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/mrr-goal-calculator.tsx rename to app/(site)/(tools)/mrr-goal-calculator/mrr-goal-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-goal-calculator/page.tsx b/app/(site)/(tools)/mrr-goal-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-goal-calculator/page.tsx rename to app/(site)/(tools)/mrr-goal-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-waterfall-calculator/content/article.mdx b/app/(site)/(tools)/mrr-waterfall-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-waterfall-calculator/content/article.mdx rename to app/(site)/(tools)/mrr-waterfall-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-waterfall-calculator/content/intro.mdx b/app/(site)/(tools)/mrr-waterfall-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-waterfall-calculator/content/intro.mdx rename to app/(site)/(tools)/mrr-waterfall-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-waterfall-calculator/content/usage.mdx b/app/(site)/(tools)/mrr-waterfall-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-waterfall-calculator/content/usage.mdx rename to app/(site)/(tools)/mrr-waterfall-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/mrr-waterfall-calculator/layout.tsx b/app/(site)/(tools)/mrr-waterfall-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-waterfall-calculator/layout.tsx rename to app/(site)/(tools)/mrr-waterfall-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-waterfall-calculator/mrr-waterfall-calculator.module.css b/app/(site)/(tools)/mrr-waterfall-calculator/mrr-waterfall-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-waterfall-calculator/mrr-waterfall-calculator.module.css rename to app/(site)/(tools)/mrr-waterfall-calculator/mrr-waterfall-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/mrr-waterfall-calculator/mrr-waterfall-calculator.tsx b/app/(site)/(tools)/mrr-waterfall-calculator/mrr-waterfall-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-waterfall-calculator/mrr-waterfall-calculator.tsx rename to app/(site)/(tools)/mrr-waterfall-calculator/mrr-waterfall-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/mrr-waterfall-calculator/page.tsx b/app/(site)/(tools)/mrr-waterfall-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/mrr-waterfall-calculator/page.tsx rename to app/(site)/(tools)/mrr-waterfall-calculator/page.tsx diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/content/article.mdx b/app/(site)/(tools)/multi-tld-availability/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/multi-tld-availability/content/article.mdx rename to app/(site)/(tools)/multi-tld-availability/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/content/intro.mdx b/app/(site)/(tools)/multi-tld-availability/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/multi-tld-availability/content/intro.mdx rename to app/(site)/(tools)/multi-tld-availability/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/content/usage.mdx b/app/(site)/(tools)/multi-tld-availability/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/multi-tld-availability/content/usage.mdx rename to app/(site)/(tools)/multi-tld-availability/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/layout.tsx b/app/(site)/(tools)/multi-tld-availability/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/multi-tld-availability/layout.tsx rename to app/(site)/(tools)/multi-tld-availability/layout.tsx diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/multi-tld-tool.module.css b/app/(site)/(tools)/multi-tld-availability/multi-tld-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/multi-tld-availability/multi-tld-tool.module.css rename to app/(site)/(tools)/multi-tld-availability/multi-tld-tool.module.css diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/multi-tld-tool.tsx b/app/(site)/(tools)/multi-tld-availability/multi-tld-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/multi-tld-availability/multi-tld-tool.tsx rename to app/(site)/(tools)/multi-tld-availability/multi-tld-tool.tsx diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/multi-tld-view.ts b/app/(site)/(tools)/multi-tld-availability/multi-tld-view.ts similarity index 96% rename from app/(site)/(tools)/(domain)/multi-tld-availability/multi-tld-view.ts rename to app/(site)/(tools)/multi-tld-availability/multi-tld-view.ts index b06a7b2f..bcacfaea 100644 --- a/app/(site)/(tools)/(domain)/multi-tld-availability/multi-tld-view.ts +++ b/app/(site)/(tools)/multi-tld-availability/multi-tld-view.ts @@ -1,4 +1,4 @@ -import type { MultiTldRow } from "../../../../../lib/domain/multi-tld-shared.ts"; +import type { MultiTldRow } from "../../../../lib/domain/multi-tld-shared.ts"; export type MultiTldDisplayRow = (MultiTldRow & { unicodeDomain?: string | null }) | { tld: string; diff --git a/app/(site)/(tools)/(domain)/multi-tld-availability/page.tsx b/app/(site)/(tools)/multi-tld-availability/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/multi-tld-availability/page.tsx rename to app/(site)/(tools)/multi-tld-availability/page.tsx index 74bd3be1..e7433308 100644 --- a/app/(site)/(tools)/(domain)/multi-tld-availability/page.tsx +++ b/app/(site)/(tools)/multi-tld-availability/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/content/article.mdx b/app/(site)/(tools)/nameserver-checker/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/nameserver-checker/content/article.mdx rename to app/(site)/(tools)/nameserver-checker/content/article.mdx diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/content/intro.mdx b/app/(site)/(tools)/nameserver-checker/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/nameserver-checker/content/intro.mdx rename to app/(site)/(tools)/nameserver-checker/content/intro.mdx diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/content/usage.mdx b/app/(site)/(tools)/nameserver-checker/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/nameserver-checker/content/usage.mdx rename to app/(site)/(tools)/nameserver-checker/content/usage.mdx diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/layout.tsx b/app/(site)/(tools)/nameserver-checker/layout.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/nameserver-checker/layout.tsx rename to app/(site)/(tools)/nameserver-checker/layout.tsx diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker-from-url.tsx b/app/(site)/(tools)/nameserver-checker/nameserver-checker-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker-from-url.tsx rename to app/(site)/(tools)/nameserver-checker/nameserver-checker-from-url.tsx diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker-view.ts b/app/(site)/(tools)/nameserver-checker/nameserver-checker-view.ts similarity index 99% rename from app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker-view.ts rename to app/(site)/(tools)/nameserver-checker/nameserver-checker-view.ts index bd992171..1318958c 100644 --- a/app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker-view.ts +++ b/app/(site)/(tools)/nameserver-checker/nameserver-checker-view.ts @@ -1,4 +1,4 @@ -import type { DelegationCheck, NameserverReachability } from "../../../../../lib/dns/diagnostic-types.ts"; +import type { DelegationCheck, NameserverReachability } from "../../../../lib/dns/diagnostic-types.ts"; export type DelegationTone = "success" | "warning" | "danger"; diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker.module.css b/app/(site)/(tools)/nameserver-checker/nameserver-checker.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker.module.css rename to app/(site)/(tools)/nameserver-checker/nameserver-checker.module.css diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker.tsx b/app/(site)/(tools)/nameserver-checker/nameserver-checker.tsx similarity index 99% rename from app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker.tsx rename to app/(site)/(tools)/nameserver-checker/nameserver-checker.tsx index e4274f50..a5ba2c6e 100644 --- a/app/(site)/(tools)/(dns)/nameserver-checker/nameserver-checker.tsx +++ b/app/(site)/(tools)/nameserver-checker/nameserver-checker.tsx @@ -9,7 +9,7 @@ import type { NameserverAddressObservation, NameserverReachability, } from "@/lib/dns/diagnostic-types.ts"; -import { diagnosticReportJson } from "@/app/(site)/(tools)/(dns)/diagnostic-result-ui"; +import { diagnosticReportJson } from "@/app/ui/tools/dns/diagnostic-result-ui"; import { checkedAddressCount, delegationContextNotes, diff --git a/app/(site)/(tools)/(dns)/nameserver-checker/page.tsx b/app/(site)/(tools)/nameserver-checker/page.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/nameserver-checker/page.tsx rename to app/(site)/(tools)/nameserver-checker/page.tsx diff --git a/app/(site)/(tools)/(saas)/net-revenue-retention-calculator/content/article.mdx b/app/(site)/(tools)/net-revenue-retention-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/net-revenue-retention-calculator/content/article.mdx rename to app/(site)/(tools)/net-revenue-retention-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/net-revenue-retention-calculator/content/intro.mdx b/app/(site)/(tools)/net-revenue-retention-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/net-revenue-retention-calculator/content/intro.mdx rename to app/(site)/(tools)/net-revenue-retention-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/net-revenue-retention-calculator/content/usage.mdx b/app/(site)/(tools)/net-revenue-retention-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/net-revenue-retention-calculator/content/usage.mdx rename to app/(site)/(tools)/net-revenue-retention-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/net-revenue-retention-calculator/layout.tsx b/app/(site)/(tools)/net-revenue-retention-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/net-revenue-retention-calculator/layout.tsx rename to app/(site)/(tools)/net-revenue-retention-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/net-revenue-retention-calculator/net-revenue-retention-calculator.module.css b/app/(site)/(tools)/net-revenue-retention-calculator/net-revenue-retention-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/net-revenue-retention-calculator/net-revenue-retention-calculator.module.css rename to app/(site)/(tools)/net-revenue-retention-calculator/net-revenue-retention-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/net-revenue-retention-calculator/net-revenue-retention-calculator.tsx b/app/(site)/(tools)/net-revenue-retention-calculator/net-revenue-retention-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/net-revenue-retention-calculator/net-revenue-retention-calculator.tsx rename to app/(site)/(tools)/net-revenue-retention-calculator/net-revenue-retention-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/net-revenue-retention-calculator/page.tsx b/app/(site)/(tools)/net-revenue-retention-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/net-revenue-retention-calculator/page.tsx rename to app/(site)/(tools)/net-revenue-retention-calculator/page.tsx diff --git a/app/(site)/(tools)/(domain)/punycode-converter/content/article.mdx b/app/(site)/(tools)/punycode-converter/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/punycode-converter/content/article.mdx rename to app/(site)/(tools)/punycode-converter/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/punycode-converter/content/intro.mdx b/app/(site)/(tools)/punycode-converter/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/punycode-converter/content/intro.mdx rename to app/(site)/(tools)/punycode-converter/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/punycode-converter/content/usage.mdx b/app/(site)/(tools)/punycode-converter/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/punycode-converter/content/usage.mdx rename to app/(site)/(tools)/punycode-converter/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/punycode-converter/layout.tsx b/app/(site)/(tools)/punycode-converter/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/punycode-converter/layout.tsx rename to app/(site)/(tools)/punycode-converter/layout.tsx diff --git a/app/(site)/(tools)/(domain)/punycode-converter/page.tsx b/app/(site)/(tools)/punycode-converter/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/punycode-converter/page.tsx rename to app/(site)/(tools)/punycode-converter/page.tsx index 6749b785..0a5900fe 100644 --- a/app/(site)/(tools)/(domain)/punycode-converter/page.tsx +++ b/app/(site)/(tools)/punycode-converter/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/punycode-converter/punycode-tool.module.css b/app/(site)/(tools)/punycode-converter/punycode-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/punycode-converter/punycode-tool.module.css rename to app/(site)/(tools)/punycode-converter/punycode-tool.module.css diff --git a/app/(site)/(tools)/(domain)/punycode-converter/punycode-tool.tsx b/app/(site)/(tools)/punycode-converter/punycode-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/punycode-converter/punycode-tool.tsx rename to app/(site)/(tools)/punycode-converter/punycode-tool.tsx diff --git a/app/(site)/(tools)/(domain)/punycode-converter/punycode-view.ts b/app/(site)/(tools)/punycode-converter/punycode-view.ts similarity index 97% rename from app/(site)/(tools)/(domain)/punycode-converter/punycode-view.ts rename to app/(site)/(tools)/punycode-converter/punycode-view.ts index 18b2a12e..7f8c2a9b 100644 --- a/app/(site)/(tools)/(domain)/punycode-converter/punycode-view.ts +++ b/app/(site)/(tools)/punycode-converter/punycode-view.ts @@ -1,5 +1,5 @@ -import type { LabelResult } from "../../../../../lib/domain/punycode.ts"; -import type { CharacterDetail, ScriptAnalysis } from "../../../../../lib/domain/unicode.ts"; +import type { LabelResult } from "../../../../lib/domain/punycode.ts"; +import type { CharacterDetail, ScriptAnalysis } from "../../../../lib/domain/unicode.ts"; export type AnalysedLabel = { label: LabelResult; diff --git a/app/(site)/(tools)/(storage)/raid-calculator/content/article.mdx b/app/(site)/(tools)/raid-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/raid-calculator/content/article.mdx rename to app/(site)/(tools)/raid-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/raid-calculator/content/intro.mdx b/app/(site)/(tools)/raid-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/raid-calculator/content/intro.mdx rename to app/(site)/(tools)/raid-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/raid-calculator/content/usage.mdx b/app/(site)/(tools)/raid-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/raid-calculator/content/usage.mdx rename to app/(site)/(tools)/raid-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/raid-calculator/layout.tsx b/app/(site)/(tools)/raid-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/raid-calculator/layout.tsx rename to app/(site)/(tools)/raid-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/raid-calculator/page.tsx b/app/(site)/(tools)/raid-calculator/page.tsx similarity index 93% rename from app/(site)/(tools)/(storage)/raid-calculator/page.tsx rename to app/(site)/(tools)/raid-calculator/page.tsx index 8c10b518..485c3071 100644 --- a/app/(site)/(tools)/(storage)/raid-calculator/page.tsx +++ b/app/(site)/(tools)/raid-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { HardDrive } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { RaidCalculatorFromUrl } from "./raid-calculator-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/raid-calculator/raid-calculator-from-url.tsx b/app/(site)/(tools)/raid-calculator/raid-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/raid-calculator/raid-calculator-from-url.tsx rename to app/(site)/(tools)/raid-calculator/raid-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/raid-calculator/raid-calculator.module.css b/app/(site)/(tools)/raid-calculator/raid-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/raid-calculator/raid-calculator.module.css rename to app/(site)/(tools)/raid-calculator/raid-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/raid-calculator/raid-calculator.tsx b/app/(site)/(tools)/raid-calculator/raid-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/raid-calculator/raid-calculator.tsx rename to app/(site)/(tools)/raid-calculator/raid-calculator.tsx diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/content/article.mdx b/app/(site)/(tools)/raidz-expansion-planner/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/content/article.mdx rename to app/(site)/(tools)/raidz-expansion-planner/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/content/intro.mdx b/app/(site)/(tools)/raidz-expansion-planner/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/content/intro.mdx rename to app/(site)/(tools)/raidz-expansion-planner/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/content/usage.mdx b/app/(site)/(tools)/raidz-expansion-planner/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/content/usage.mdx rename to app/(site)/(tools)/raidz-expansion-planner/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/layout.tsx b/app/(site)/(tools)/raidz-expansion-planner/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/layout.tsx rename to app/(site)/(tools)/raidz-expansion-planner/layout.tsx diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/page.tsx b/app/(site)/(tools)/raidz-expansion-planner/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/page.tsx rename to app/(site)/(tools)/raidz-expansion-planner/page.tsx index 8691546e..57d7c4b7 100644 --- a/app/(site)/(tools)/(storage)/raidz-expansion-planner/page.tsx +++ b/app/(site)/(tools)/raidz-expansion-planner/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { ChevronsRight } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { RaidzExpansionPlannerFromUrl } from "./raidz-expansion-planner-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/raidz-expansion-planner-from-url.tsx b/app/(site)/(tools)/raidz-expansion-planner/raidz-expansion-planner-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/raidz-expansion-planner-from-url.tsx rename to app/(site)/(tools)/raidz-expansion-planner/raidz-expansion-planner-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/raidz-expansion-planner.module.css b/app/(site)/(tools)/raidz-expansion-planner/raidz-expansion-planner.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/raidz-expansion-planner.module.css rename to app/(site)/(tools)/raidz-expansion-planner/raidz-expansion-planner.module.css diff --git a/app/(site)/(tools)/(storage)/raidz-expansion-planner/raidz-expansion-planner.tsx b/app/(site)/(tools)/raidz-expansion-planner/raidz-expansion-planner.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/raidz-expansion-planner/raidz-expansion-planner.tsx rename to app/(site)/(tools)/raidz-expansion-planner/raidz-expansion-planner.tsx diff --git a/app/(site)/(tools)/(storage)/rebuild-calculator/content/article.mdx b/app/(site)/(tools)/rebuild-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/rebuild-calculator/content/article.mdx rename to app/(site)/(tools)/rebuild-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/rebuild-calculator/content/intro.mdx b/app/(site)/(tools)/rebuild-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/rebuild-calculator/content/intro.mdx rename to app/(site)/(tools)/rebuild-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/rebuild-calculator/content/usage.mdx b/app/(site)/(tools)/rebuild-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/rebuild-calculator/content/usage.mdx rename to app/(site)/(tools)/rebuild-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/rebuild-calculator/layout.tsx b/app/(site)/(tools)/rebuild-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/rebuild-calculator/layout.tsx rename to app/(site)/(tools)/rebuild-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/rebuild-calculator/page.tsx b/app/(site)/(tools)/rebuild-calculator/page.tsx similarity index 93% rename from app/(site)/(tools)/(storage)/rebuild-calculator/page.tsx rename to app/(site)/(tools)/rebuild-calculator/page.tsx index 1f39542b..a72ff247 100644 --- a/app/(site)/(tools)/(storage)/rebuild-calculator/page.tsx +++ b/app/(site)/(tools)/rebuild-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { HardDrive } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { RebuildCalculator } from "./rebuild-calculator"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/rebuild-calculator/rebuild-calculator.module.css b/app/(site)/(tools)/rebuild-calculator/rebuild-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/rebuild-calculator/rebuild-calculator.module.css rename to app/(site)/(tools)/rebuild-calculator/rebuild-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/rebuild-calculator/rebuild-calculator.tsx b/app/(site)/(tools)/rebuild-calculator/rebuild-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/rebuild-calculator/rebuild-calculator.tsx rename to app/(site)/(tools)/rebuild-calculator/rebuild-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/revenue-churn-calculator/content/article.mdx b/app/(site)/(tools)/revenue-churn-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/revenue-churn-calculator/content/article.mdx rename to app/(site)/(tools)/revenue-churn-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/revenue-churn-calculator/content/intro.mdx b/app/(site)/(tools)/revenue-churn-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/revenue-churn-calculator/content/intro.mdx rename to app/(site)/(tools)/revenue-churn-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/revenue-churn-calculator/content/usage.mdx b/app/(site)/(tools)/revenue-churn-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/revenue-churn-calculator/content/usage.mdx rename to app/(site)/(tools)/revenue-churn-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/revenue-churn-calculator/layout.tsx b/app/(site)/(tools)/revenue-churn-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/revenue-churn-calculator/layout.tsx rename to app/(site)/(tools)/revenue-churn-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/revenue-churn-calculator/page.tsx b/app/(site)/(tools)/revenue-churn-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/revenue-churn-calculator/page.tsx rename to app/(site)/(tools)/revenue-churn-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/revenue-churn-calculator/revenue-churn-calculator.module.css b/app/(site)/(tools)/revenue-churn-calculator/revenue-churn-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/revenue-churn-calculator/revenue-churn-calculator.module.css rename to app/(site)/(tools)/revenue-churn-calculator/revenue-churn-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/revenue-churn-calculator/revenue-churn-calculator.tsx b/app/(site)/(tools)/revenue-churn-calculator/revenue-churn-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/revenue-churn-calculator/revenue-churn-calculator.tsx rename to app/(site)/(tools)/revenue-churn-calculator/revenue-churn-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.spec.json b/app/(site)/(tools)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.spec.json rename to app/(site)/(tools)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.svg b/app/(site)/(tools)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.svg rename to app/(site)/(tools)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.svg diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.ts b/app/(site)/(tools)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.ts rename to app/(site)/(tools)/saas-gross-margin-calculator/art/saas-gross-margin-calculator.ts diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/content/article.mdx b/app/(site)/(tools)/saas-gross-margin-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/content/article.mdx rename to app/(site)/(tools)/saas-gross-margin-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/content/intro.mdx b/app/(site)/(tools)/saas-gross-margin-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/content/intro.mdx rename to app/(site)/(tools)/saas-gross-margin-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/content/usage.mdx b/app/(site)/(tools)/saas-gross-margin-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/content/usage.mdx rename to app/(site)/(tools)/saas-gross-margin-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/layout.tsx b/app/(site)/(tools)/saas-gross-margin-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/layout.tsx rename to app/(site)/(tools)/saas-gross-margin-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/page.tsx b/app/(site)/(tools)/saas-gross-margin-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/page.tsx rename to app/(site)/(tools)/saas-gross-margin-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/saas-gross-margin-calculator.module.css b/app/(site)/(tools)/saas-gross-margin-calculator/saas-gross-margin-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/saas-gross-margin-calculator.module.css rename to app/(site)/(tools)/saas-gross-margin-calculator/saas-gross-margin-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/saas-gross-margin-calculator.tsx b/app/(site)/(tools)/saas-gross-margin-calculator/saas-gross-margin-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-gross-margin-calculator/saas-gross-margin-calculator.tsx rename to app/(site)/(tools)/saas-gross-margin-calculator/saas-gross-margin-calculator.tsx diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/art/saas-metrics-calculator.spec.json b/app/(site)/(tools)/saas-metrics-calculator/art/saas-metrics-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/art/saas-metrics-calculator.spec.json rename to app/(site)/(tools)/saas-metrics-calculator/art/saas-metrics-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/art/saas-metrics-calculator.svg b/app/(site)/(tools)/saas-metrics-calculator/art/saas-metrics-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/art/saas-metrics-calculator.svg rename to app/(site)/(tools)/saas-metrics-calculator/art/saas-metrics-calculator.svg diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/art/saas-metrics-calculator.ts b/app/(site)/(tools)/saas-metrics-calculator/art/saas-metrics-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/art/saas-metrics-calculator.ts rename to app/(site)/(tools)/saas-metrics-calculator/art/saas-metrics-calculator.ts diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/content/article.mdx b/app/(site)/(tools)/saas-metrics-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/content/article.mdx rename to app/(site)/(tools)/saas-metrics-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/content/intro.mdx b/app/(site)/(tools)/saas-metrics-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/content/intro.mdx rename to app/(site)/(tools)/saas-metrics-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/content/usage.mdx b/app/(site)/(tools)/saas-metrics-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/content/usage.mdx rename to app/(site)/(tools)/saas-metrics-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/layout.tsx b/app/(site)/(tools)/saas-metrics-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/layout.tsx rename to app/(site)/(tools)/saas-metrics-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/page.tsx b/app/(site)/(tools)/saas-metrics-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/page.tsx rename to app/(site)/(tools)/saas-metrics-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/saas-metrics-calculator.module.css b/app/(site)/(tools)/saas-metrics-calculator/saas-metrics-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/saas-metrics-calculator.module.css rename to app/(site)/(tools)/saas-metrics-calculator/saas-metrics-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/saas-metrics-calculator/saas-metrics-calculator.tsx b/app/(site)/(tools)/saas-metrics-calculator/saas-metrics-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/saas-metrics-calculator/saas-metrics-calculator.tsx rename to app/(site)/(tools)/saas-metrics-calculator/saas-metrics-calculator.tsx diff --git a/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.module.css b/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.module.css index 8483dc76..7917b6e4 100644 --- a/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.module.css +++ b/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.module.css @@ -1,6 +1,6 @@ .tool { display: grid; grid-template-columns: minmax(280px, 360px) minmax(0, 1fr); min-width: 0; } .controls, .preview { min-width: 0; padding: var(--space-7); } -.controls { border-right: 1px solid var(--color-border); display: grid; gap: var(--space-6); } +.controls { align-content: start; border-right: 1px solid var(--color-border); display: grid; gap: var(--space-6); } .controls h2, .appOptions h3 { font-family: var(--font-display); line-height: var(--line-heading); margin: 0; } .controls h2 { font-size: var(--text-h2); } .appOptions h3 { font-size: var(--text-h3); } @@ -19,7 +19,7 @@ .previewHeading button { min-height: 44px; } .sheetFrame { max-width: 100%; overflow-x: auto; padding-bottom: var(--space-3); } .sheetFrame:focus-visible { outline: var(--focus-outline); outline-offset: 2px; } -.sheet { background: #fff; color: #161616; min-width: 680px; padding: var(--space-8); width: 760px; } +.sheet { background: #fff; color: #161616; max-width: 760px; min-width: 560px; padding: var(--space-8); } .sheet h2, .sheet h3 { font-family: var(--font-display); line-height: var(--line-heading); margin: 0; } .sheet h2 { font-size: var(--text-h2); } .sheet h3 { font-size: var(--text-h3); margin-top: var(--space-8); } diff --git a/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.tsx b/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.tsx index 5052dfd7..0e52cad9 100644 --- a/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.tsx +++ b/app/(site)/(tools)/shortcuts-cheatsheet-generator/shortcuts-cheatsheet-generator.tsx @@ -11,8 +11,8 @@ import styles from "./shortcuts-cheatsheet-generator.module.css"; type Props = { catalog: readonly ShortcutAppSummary[]; initialSlugs: readonly string[] }; -async function loadApp(slug: string, signal?: AbortSignal): Promise { - const response = await fetch(`/api/shortcuts/${encodeURIComponent(slug)}`, { signal }); +async function loadApp(slug: string): Promise { + const response = await fetch(`/api/shortcuts/${encodeURIComponent(slug)}`); if (!response.ok) throw new Error("App shortcuts could not be loaded."); const app = await response.json() as AppShortcuts; if (app.slug !== slug) throw new Error("App shortcuts could not be loaded."); @@ -46,23 +46,24 @@ export function ShortcutsCheatSheetGenerator({ catalog, initialSlugs }: Props) { const [excludedGroups, setExcludedGroups] = useState>>({}); // Loading a shared selection adds records without replacing choices made meanwhile. + // Results that arrive after a remount are ignored rather than aborted mid-request. useEffect(() => { - const controller = new AbortController(); + let cancelled = false; for (const slug of initialSlugs) { - void loadApp(slug, controller.signal) + void loadApp(slug) .then((app) => { - if (!controller.signal.aborted) setLoadedApps((current) => ({ ...current, [slug]: app })); + if (!cancelled) setLoadedApps((current) => ({ ...current, [slug]: app })); }) .catch(() => { - if (controller.signal.aborted) return; + if (cancelled) return; setSelected((current) => { const next = new Set(current); next.delete(slug); return next; }); setLoadError("The app shortcuts could not be loaded. Try selecting the app again."); }) .finally(() => { - if (!controller.signal.aborted) setLoadingSlugs((current) => { const next = new Set(current); next.delete(slug); return next; }); + if (!cancelled) setLoadingSlugs((current) => { const next = new Set(current); next.delete(slug); return next; }); }); } - return () => controller.abort(); + return () => { cancelled = true; }; }, [initialSlugs]); const selectedApps = catalog.flatMap((summary) => { const app = loadedApps[summary.slug]; diff --git a/app/(site)/(tools)/(storage)/shr-calculator/content/article.mdx b/app/(site)/(tools)/shr-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/content/article.mdx rename to app/(site)/(tools)/shr-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/shr-calculator/content/intro.mdx b/app/(site)/(tools)/shr-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/content/intro.mdx rename to app/(site)/(tools)/shr-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/shr-calculator/content/usage.mdx b/app/(site)/(tools)/shr-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/content/usage.mdx rename to app/(site)/(tools)/shr-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/shr-calculator/layout.tsx b/app/(site)/(tools)/shr-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/layout.tsx rename to app/(site)/(tools)/shr-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/shr-calculator/page.tsx b/app/(site)/(tools)/shr-calculator/page.tsx similarity index 93% rename from app/(site)/(tools)/(storage)/shr-calculator/page.tsx rename to app/(site)/(tools)/shr-calculator/page.tsx index 28fc1950..f7bcfdcb 100644 --- a/app/(site)/(tools)/(storage)/shr-calculator/page.tsx +++ b/app/(site)/(tools)/shr-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { HardDrive } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { ShrCalculatorFromUrl } from "./shr-calculator-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/shr-calculator/shr-calculator-from-url.tsx b/app/(site)/(tools)/shr-calculator/shr-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/shr-calculator-from-url.tsx rename to app/(site)/(tools)/shr-calculator/shr-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/shr-calculator/shr-calculator.module.css b/app/(site)/(tools)/shr-calculator/shr-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/shr-calculator.module.css rename to app/(site)/(tools)/shr-calculator/shr-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/shr-calculator/shr-calculator.tsx b/app/(site)/(tools)/shr-calculator/shr-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/shr-calculator.tsx rename to app/(site)/(tools)/shr-calculator/shr-calculator.tsx diff --git a/app/(site)/(tools)/(storage)/shr-calculator/shr-capacity.ts b/app/(site)/(tools)/shr-calculator/shr-capacity.ts similarity index 100% rename from app/(site)/(tools)/(storage)/shr-calculator/shr-capacity.ts rename to app/(site)/(tools)/shr-calculator/shr-capacity.ts diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/content/article.mdx b/app/(site)/(tools)/snapraid-mergerfs-planner/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/content/article.mdx rename to app/(site)/(tools)/snapraid-mergerfs-planner/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/content/intro.mdx b/app/(site)/(tools)/snapraid-mergerfs-planner/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/content/intro.mdx rename to app/(site)/(tools)/snapraid-mergerfs-planner/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/content/usage.mdx b/app/(site)/(tools)/snapraid-mergerfs-planner/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/content/usage.mdx rename to app/(site)/(tools)/snapraid-mergerfs-planner/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/layout.tsx b/app/(site)/(tools)/snapraid-mergerfs-planner/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/layout.tsx rename to app/(site)/(tools)/snapraid-mergerfs-planner/layout.tsx diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/page.tsx b/app/(site)/(tools)/snapraid-mergerfs-planner/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/page.tsx rename to app/(site)/(tools)/snapraid-mergerfs-planner/page.tsx index 33162242..c8f00a9a 100644 --- a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/page.tsx +++ b/app/(site)/(tools)/snapraid-mergerfs-planner/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { HardDrive } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { SnapraidMergerfsPlanner } from "./snapraid-mergerfs-planner"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/snapraid-merfs-engine.ts b/app/(site)/(tools)/snapraid-mergerfs-planner/snapraid-merfs-engine.ts similarity index 100% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/snapraid-merfs-engine.ts rename to app/(site)/(tools)/snapraid-mergerfs-planner/snapraid-merfs-engine.ts diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.module.css b/app/(site)/(tools)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.module.css rename to app/(site)/(tools)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.module.css diff --git a/app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.tsx b/app/(site)/(tools)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.tsx rename to app/(site)/(tools)/snapraid-mergerfs-planner/snapraid-mergerfs-planner.tsx diff --git a/app/(site)/(tools)/(dns)/soa-checker/content/article.mdx b/app/(site)/(tools)/soa-checker/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/soa-checker/content/article.mdx rename to app/(site)/(tools)/soa-checker/content/article.mdx diff --git a/app/(site)/(tools)/(dns)/soa-checker/content/intro.mdx b/app/(site)/(tools)/soa-checker/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/soa-checker/content/intro.mdx rename to app/(site)/(tools)/soa-checker/content/intro.mdx diff --git a/app/(site)/(tools)/(dns)/soa-checker/content/usage.mdx b/app/(site)/(tools)/soa-checker/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(dns)/soa-checker/content/usage.mdx rename to app/(site)/(tools)/soa-checker/content/usage.mdx diff --git a/app/(site)/(tools)/(dns)/soa-checker/layout.tsx b/app/(site)/(tools)/soa-checker/layout.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/soa-checker/layout.tsx rename to app/(site)/(tools)/soa-checker/layout.tsx diff --git a/app/(site)/(tools)/(dns)/soa-checker/page.tsx b/app/(site)/(tools)/soa-checker/page.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/soa-checker/page.tsx rename to app/(site)/(tools)/soa-checker/page.tsx diff --git a/app/(site)/(tools)/(dns)/soa-checker/soa-checker-from-url.tsx b/app/(site)/(tools)/soa-checker/soa-checker-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/soa-checker/soa-checker-from-url.tsx rename to app/(site)/(tools)/soa-checker/soa-checker-from-url.tsx diff --git a/app/(site)/(tools)/(dns)/soa-checker/soa-checker-view.ts b/app/(site)/(tools)/soa-checker/soa-checker-view.ts similarity index 96% rename from app/(site)/(tools)/(dns)/soa-checker/soa-checker-view.ts rename to app/(site)/(tools)/soa-checker/soa-checker-view.ts index b885ac19..c610c96e 100644 --- a/app/(site)/(tools)/(dns)/soa-checker/soa-checker-view.ts +++ b/app/(site)/(tools)/soa-checker/soa-checker-view.ts @@ -1,6 +1,6 @@ -import { negativeCacheTtlSeconds } from "../../../../../lib/dns/diagnostic-presentation.ts"; -import type { SoaRecord } from "../../../../../lib/dns/diagnostic-types.ts"; -import { compareSerials } from "../../../../../lib/dns/serial-arithmetic.ts"; +import { negativeCacheTtlSeconds } from "../../../../lib/dns/diagnostic-presentation.ts"; +import type { SoaRecord } from "../../../../lib/dns/diagnostic-types.ts"; +import { compareSerials } from "../../../../lib/dns/serial-arithmetic.ts"; export type SoaObservation = { server: { hostname: string; address: string }; diff --git a/app/(site)/(tools)/(dns)/soa-checker/soa-checker.module.css b/app/(site)/(tools)/soa-checker/soa-checker.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/soa-checker/soa-checker.module.css rename to app/(site)/(tools)/soa-checker/soa-checker.module.css diff --git a/app/(site)/(tools)/(dns)/soa-checker/soa-checker.tsx b/app/(site)/(tools)/soa-checker/soa-checker.tsx similarity index 99% rename from app/(site)/(tools)/(dns)/soa-checker/soa-checker.tsx rename to app/(site)/(tools)/soa-checker/soa-checker.tsx index 517fcb1e..a0b7942b 100644 --- a/app/(site)/(tools)/(dns)/soa-checker/soa-checker.tsx +++ b/app/(site)/(tools)/soa-checker/soa-checker.tsx @@ -4,7 +4,7 @@ import { useRef, useState, type FormEvent, type ReactNode } from "react"; import { UiButton, UiDisclosure, UiDownloadAction, UiRawOutput, UiTextField } from "@/app/ui/controls"; import { UiDataTable, UiResultLead, UiStatus } from "@/app/ui/display"; import { groupSoaObservations, negativeCacheTtlSeconds } from "@/lib/dns/diagnostic-presentation.ts"; -import { diagnosticReportJson } from "@/app/(site)/(tools)/(dns)/diagnostic-result-ui"; +import { diagnosticReportJson } from "@/app/ui/tools/dns/diagnostic-result-ui"; import { buildSoaComparison, soaDifferenceLabels, diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator.spec.json b/app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator.spec.json similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator.spec.json rename to app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator.spec.json diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator.svg b/app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator.svg similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator.svg rename to app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator.svg diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator.ts b/app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator.ts similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator.ts rename to app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator.ts diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/content/article.mdx b/app/(site)/(tools)/startup-runway-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/content/article.mdx rename to app/(site)/(tools)/startup-runway-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/content/intro.mdx b/app/(site)/(tools)/startup-runway-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/content/intro.mdx rename to app/(site)/(tools)/startup-runway-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/content/usage.mdx b/app/(site)/(tools)/startup-runway-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/content/usage.mdx rename to app/(site)/(tools)/startup-runway-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/layout.tsx b/app/(site)/(tools)/startup-runway-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/layout.tsx rename to app/(site)/(tools)/startup-runway-calculator/layout.tsx diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/page.tsx b/app/(site)/(tools)/startup-runway-calculator/page.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/page.tsx rename to app/(site)/(tools)/startup-runway-calculator/page.tsx diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/startup-runway-calculator.module.css b/app/(site)/(tools)/startup-runway-calculator/startup-runway-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/startup-runway-calculator.module.css rename to app/(site)/(tools)/startup-runway-calculator/startup-runway-calculator.module.css diff --git a/app/(site)/(tools)/(saas)/startup-runway-calculator/startup-runway-calculator.tsx b/app/(site)/(tools)/startup-runway-calculator/startup-runway-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(saas)/startup-runway-calculator/startup-runway-calculator.tsx rename to app/(site)/(tools)/startup-runway-calculator/startup-runway-calculator.tsx diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/content/article.mdx b/app/(site)/(tools)/storage-growth-planner/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/content/article.mdx rename to app/(site)/(tools)/storage-growth-planner/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/content/intro.mdx b/app/(site)/(tools)/storage-growth-planner/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/content/intro.mdx rename to app/(site)/(tools)/storage-growth-planner/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/content/usage.mdx b/app/(site)/(tools)/storage-growth-planner/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/content/usage.mdx rename to app/(site)/(tools)/storage-growth-planner/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/layout.tsx b/app/(site)/(tools)/storage-growth-planner/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/layout.tsx rename to app/(site)/(tools)/storage-growth-planner/layout.tsx diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/page.tsx b/app/(site)/(tools)/storage-growth-planner/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/storage-growth-planner/page.tsx rename to app/(site)/(tools)/storage-growth-planner/page.tsx index 14d161a8..19335690 100644 --- a/app/(site)/(tools)/(storage)/storage-growth-planner/page.tsx +++ b/app/(site)/(tools)/storage-growth-planner/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { Calculator } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { StorageGrowthPlannerFromUrl } from "./storage-growth-planner-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner-engine.ts b/app/(site)/(tools)/storage-growth-planner/storage-growth-planner-engine.ts similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner-engine.ts rename to app/(site)/(tools)/storage-growth-planner/storage-growth-planner-engine.ts diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner-from-url.tsx b/app/(site)/(tools)/storage-growth-planner/storage-growth-planner-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner-from-url.tsx rename to app/(site)/(tools)/storage-growth-planner/storage-growth-planner-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner.module.css b/app/(site)/(tools)/storage-growth-planner/storage-growth-planner.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner.module.css rename to app/(site)/(tools)/storage-growth-planner/storage-growth-planner.module.css diff --git a/app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner.tsx b/app/(site)/(tools)/storage-growth-planner/storage-growth-planner.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner.tsx rename to app/(site)/(tools)/storage-growth-planner/storage-growth-planner.tsx diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/content/article.mdx b/app/(site)/(tools)/storage-layout-advisor/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/content/article.mdx rename to app/(site)/(tools)/storage-layout-advisor/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/content/intro.mdx b/app/(site)/(tools)/storage-layout-advisor/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/content/intro.mdx rename to app/(site)/(tools)/storage-layout-advisor/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/content/usage.mdx b/app/(site)/(tools)/storage-layout-advisor/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/content/usage.mdx rename to app/(site)/(tools)/storage-layout-advisor/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/layout.tsx b/app/(site)/(tools)/storage-layout-advisor/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/layout.tsx rename to app/(site)/(tools)/storage-layout-advisor/layout.tsx diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/page.tsx b/app/(site)/(tools)/storage-layout-advisor/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/page.tsx rename to app/(site)/(tools)/storage-layout-advisor/page.tsx index 26ff65b1..6d614a00 100644 --- a/app/(site)/(tools)/(storage)/storage-layout-advisor/page.tsx +++ b/app/(site)/(tools)/storage-layout-advisor/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { HardDrive } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { StorageLayoutAdvisorFromUrl } from "./storage-layout-advisor-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor-engine.ts b/app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor-engine.ts similarity index 99% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor-engine.ts rename to app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor-engine.ts index 7df9cd88..a031817b 100644 --- a/app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor-engine.ts +++ b/app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor-engine.ts @@ -8,7 +8,7 @@ import { type StorageCalculationResult, type StorageIssue, type StorageCapacityUnit, -} from "../../../../../lib/storage/index.ts"; +} from "../../../../lib/storage/index.ts"; export const STORAGE_LAYOUT_ADVISOR_ID = "storage-layout-advisor" as const; export const ADVISOR_CALCULATION_VERSION = 1 as const; diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor-from-url.tsx b/app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor-from-url.tsx rename to app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor.module.css b/app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor.module.css rename to app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor.module.css diff --git a/app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor.tsx b/app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor.tsx similarity index 99% rename from app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor.tsx rename to app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor.tsx index cf193b91..5e1bc3b1 100644 --- a/app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor.tsx +++ b/app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor.tsx @@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from "react"; import { UiButton, UiChoiceGroup, UiQuantityInput, UiRepeatableList, UiTextField, uiOption } from "@/app/ui/controls"; import { UiActionRow, UiAllocationBar, UiDataTable, UiPrimaryResult, UiStatus } from "@/app/ui/display"; -import { formatBytes } from "../../../../../lib/storage/index.ts"; +import { formatBytes } from "../../../../lib/storage/index.ts"; import { MAX_ADVISOR_DRIVES, advisorDisplayUnits, diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/content/article.mdx b/app/(site)/(tools)/transfer-readiness/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/transfer-readiness/content/article.mdx rename to app/(site)/(tools)/transfer-readiness/content/article.mdx diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/content/intro.mdx b/app/(site)/(tools)/transfer-readiness/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/transfer-readiness/content/intro.mdx rename to app/(site)/(tools)/transfer-readiness/content/intro.mdx diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/content/usage.mdx b/app/(site)/(tools)/transfer-readiness/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(domain)/transfer-readiness/content/usage.mdx rename to app/(site)/(tools)/transfer-readiness/content/usage.mdx diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/layout.tsx b/app/(site)/(tools)/transfer-readiness/layout.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/transfer-readiness/layout.tsx rename to app/(site)/(tools)/transfer-readiness/layout.tsx diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/page.tsx b/app/(site)/(tools)/transfer-readiness/page.tsx similarity index 95% rename from app/(site)/(tools)/(domain)/transfer-readiness/page.tsx rename to app/(site)/(tools)/transfer-readiness/page.tsx index e36858c2..ba91b91e 100644 --- a/app/(site)/(tools)/(domain)/transfer-readiness/page.tsx +++ b/app/(site)/(tools)/transfer-readiness/page.tsx @@ -1,3 +1,4 @@ +import "@/app/ui/tools/domain/domain-tools.css"; import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { PageCanvas } from "@/app/ui/site/page-canvas"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-from-url.tsx b/app/(site)/(tools)/transfer-readiness/transfer-readiness-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-from-url.tsx rename to app/(site)/(tools)/transfer-readiness/transfer-readiness-from-url.tsx diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-tool.module.css b/app/(site)/(tools)/transfer-readiness/transfer-readiness-tool.module.css similarity index 100% rename from app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-tool.module.css rename to app/(site)/(tools)/transfer-readiness/transfer-readiness-tool.module.css diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-tool.tsx b/app/(site)/(tools)/transfer-readiness/transfer-readiness-tool.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-tool.tsx rename to app/(site)/(tools)/transfer-readiness/transfer-readiness-tool.tsx diff --git a/app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-view.ts b/app/(site)/(tools)/transfer-readiness/transfer-readiness-view.ts similarity index 99% rename from app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-view.ts rename to app/(site)/(tools)/transfer-readiness/transfer-readiness-view.ts index eab62611..d6db2aa6 100644 --- a/app/(site)/(tools)/(domain)/transfer-readiness/transfer-readiness-view.ts +++ b/app/(site)/(tools)/transfer-readiness/transfer-readiness-view.ts @@ -1,4 +1,4 @@ -import type { TransferFinding, TransferReadiness } from "../../../../../lib/domain/transfer-readiness.ts"; +import type { TransferFinding, TransferReadiness } from "../../../../lib/domain/transfer-readiness.ts"; const SUBJECT_ORDER = ["client-lock", "server-lock", "pending-transfer", "lifecycle", "registration-lock", "transfer-lock", "expiry", "dnssec", "nameservers"]; const STATE_ORDER: Record = { blocked: 0, risk: 1, unknown: 2, clear: 3 }; diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/content/article.mdx b/app/(site)/(tools)/unraid-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/unraid-calculator/content/article.mdx rename to app/(site)/(tools)/unraid-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/content/intro.mdx b/app/(site)/(tools)/unraid-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/unraid-calculator/content/intro.mdx rename to app/(site)/(tools)/unraid-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/content/usage.mdx b/app/(site)/(tools)/unraid-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/unraid-calculator/content/usage.mdx rename to app/(site)/(tools)/unraid-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/layout.tsx b/app/(site)/(tools)/unraid-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/unraid-calculator/layout.tsx rename to app/(site)/(tools)/unraid-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/page.tsx b/app/(site)/(tools)/unraid-calculator/page.tsx similarity index 93% rename from app/(site)/(tools)/(storage)/unraid-calculator/page.tsx rename to app/(site)/(tools)/unraid-calculator/page.tsx index ebe104d8..f1ef863e 100644 --- a/app/(site)/(tools)/(storage)/unraid-calculator/page.tsx +++ b/app/(site)/(tools)/unraid-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { HardDrive } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { UnraidCalculatorFromUrl } from "./unraid-calculator-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator-engine.ts b/app/(site)/(tools)/unraid-calculator/unraid-calculator-engine.ts similarity index 98% rename from app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator-engine.ts rename to app/(site)/(tools)/unraid-calculator/unraid-calculator-engine.ts index c5b98a1b..cb991014 100644 --- a/app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator-engine.ts +++ b/app/(site)/(tools)/unraid-calculator/unraid-calculator-engine.ts @@ -1,6 +1,6 @@ -import { bytesFromUnit, formatBytes } from "../../../../../lib/storage/bytes.ts"; -import { createStorageCalculationResult, storageValue } from "../../../../../lib/storage/result.ts"; -import { decodeStorageState, encodeStorageState } from "../../../../../lib/storage/state.ts"; +import { bytesFromUnit, formatBytes } from "../../../../lib/storage/bytes.ts"; +import { createStorageCalculationResult, storageValue } from "../../../../lib/storage/result.ts"; +import { decodeStorageState, encodeStorageState } from "../../../../lib/storage/state.ts"; import { MAX_DRIVE_CAPACITY_BYTES, StorageStateError, @@ -9,7 +9,7 @@ import { type StorageIssue, type StorageStateEnvelope, type StorageValue, -} from "../../../../../lib/storage/types.ts"; +} from "../../../../lib/storage/types.ts"; export { bytesFromUnit, MAX_DRIVE_CAPACITY_BYTES }; diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator-from-url.tsx b/app/(site)/(tools)/unraid-calculator/unraid-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator-from-url.tsx rename to app/(site)/(tools)/unraid-calculator/unraid-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator.module.css b/app/(site)/(tools)/unraid-calculator/unraid-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator.module.css rename to app/(site)/(tools)/unraid-calculator/unraid-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator.tsx b/app/(site)/(tools)/unraid-calculator/unraid-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator.tsx rename to app/(site)/(tools)/unraid-calculator/unraid-calculator.tsx diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/content/article.mdx b/app/(site)/(tools)/zfs-capacity-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/content/article.mdx rename to app/(site)/(tools)/zfs-capacity-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/content/intro.mdx b/app/(site)/(tools)/zfs-capacity-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/content/intro.mdx rename to app/(site)/(tools)/zfs-capacity-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/content/usage.mdx b/app/(site)/(tools)/zfs-capacity-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/content/usage.mdx rename to app/(site)/(tools)/zfs-capacity-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/layout.tsx b/app/(site)/(tools)/zfs-capacity-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/layout.tsx rename to app/(site)/(tools)/zfs-capacity-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/page.tsx b/app/(site)/(tools)/zfs-capacity-calculator/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/page.tsx rename to app/(site)/(tools)/zfs-capacity-calculator/page.tsx index 3f0542d6..0bae2b2f 100644 --- a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/page.tsx +++ b/app/(site)/(tools)/zfs-capacity-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { Database } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { ZfsCapacityCalculatorFromUrl } from "./zfs-capacity-calculator-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/zfs-capacity-calculator-from-url.tsx b/app/(site)/(tools)/zfs-capacity-calculator/zfs-capacity-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/zfs-capacity-calculator-from-url.tsx rename to app/(site)/(tools)/zfs-capacity-calculator/zfs-capacity-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/zfs-capacity-calculator.module.css b/app/(site)/(tools)/zfs-capacity-calculator/zfs-capacity-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/zfs-capacity-calculator.module.css rename to app/(site)/(tools)/zfs-capacity-calculator/zfs-capacity-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/zfs-capacity-calculator/zfs-capacity-calculator.tsx b/app/(site)/(tools)/zfs-capacity-calculator/zfs-capacity-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-capacity-calculator/zfs-capacity-calculator.tsx rename to app/(site)/(tools)/zfs-capacity-calculator/zfs-capacity-calculator.tsx diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/content/article.mdx b/app/(site)/(tools)/zfs-padding-calculator/content/article.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/content/article.mdx rename to app/(site)/(tools)/zfs-padding-calculator/content/article.mdx diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/content/intro.mdx b/app/(site)/(tools)/zfs-padding-calculator/content/intro.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/content/intro.mdx rename to app/(site)/(tools)/zfs-padding-calculator/content/intro.mdx diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/content/usage.mdx b/app/(site)/(tools)/zfs-padding-calculator/content/usage.mdx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/content/usage.mdx rename to app/(site)/(tools)/zfs-padding-calculator/content/usage.mdx diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/layout.tsx b/app/(site)/(tools)/zfs-padding-calculator/layout.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/layout.tsx rename to app/(site)/(tools)/zfs-padding-calculator/layout.tsx diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/page.tsx b/app/(site)/(tools)/zfs-padding-calculator/page.tsx similarity index 94% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/page.tsx rename to app/(site)/(tools)/zfs-padding-calculator/page.tsx index d4eb387d..f635fcaf 100644 --- a/app/(site)/(tools)/(storage)/zfs-padding-calculator/page.tsx +++ b/app/(site)/(tools)/zfs-padding-calculator/page.tsx @@ -2,7 +2,7 @@ import { ToolPageShell } from "@/app/ui/tools/tool-page-shell"; import { ToolPageArticle, ToolPageHeader } from "@/app/ui/site/tool-page-content"; import { getRequiredToolPage } from "@/lib/tool-pages"; import { Columns3 } from "lucide-react"; -import { PageCanvas } from "../../../../ui/site/page-canvas"; +import { PageCanvas } from "../../../ui/site/page-canvas"; import { ZfsPaddingCalculatorFromUrl } from "./zfs-padding-calculator-from-url"; import Article from "./content/article.mdx"; import Intro from "./content/intro.mdx"; diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/zfs-padding-calculator-from-url.tsx b/app/(site)/(tools)/zfs-padding-calculator/zfs-padding-calculator-from-url.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/zfs-padding-calculator-from-url.tsx rename to app/(site)/(tools)/zfs-padding-calculator/zfs-padding-calculator-from-url.tsx diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/zfs-padding-calculator.module.css b/app/(site)/(tools)/zfs-padding-calculator/zfs-padding-calculator.module.css similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/zfs-padding-calculator.module.css rename to app/(site)/(tools)/zfs-padding-calculator/zfs-padding-calculator.module.css diff --git a/app/(site)/(tools)/(storage)/zfs-padding-calculator/zfs-padding-calculator.tsx b/app/(site)/(tools)/zfs-padding-calculator/zfs-padding-calculator.tsx similarity index 100% rename from app/(site)/(tools)/(storage)/zfs-padding-calculator/zfs-padding-calculator.tsx rename to app/(site)/(tools)/zfs-padding-calculator/zfs-padding-calculator.tsx diff --git a/app/(site)/home.css b/app/(site)/home.css index 11087ad0..2cd3faaf 100644 --- a/app/(site)/home.css +++ b/app/(site)/home.css @@ -1,8 +1,3 @@ -.home-sidebar-panel { - align-content: start; - gap: var(--space-8); -} - .home-main { display: grid; gap: var(--space-12); diff --git a/app/ui/directories/keyboard-shortcuts-sidebar.module.css b/app/ui/directories/keyboard-shortcuts-sidebar.module.css deleted file mode 100644 index a1393769..00000000 --- a/app/ui/directories/keyboard-shortcuts-sidebar.module.css +++ /dev/null @@ -1,21 +0,0 @@ -.panel { - gap: var(--space-8); -} - -.nav { - display: grid; - gap: var(--space-8); -} - -.group { - display: grid; - gap: var(--space-3); -} - -.groupTitle { - margin: 0; - color: var(--color-text-muted); - font-family: var(--font-mono); - font-size: var(--text-small); - line-height: var(--line-ui); -} diff --git a/app/ui/directories/keyboard-shortcuts-sidebar.tsx b/app/ui/directories/keyboard-shortcuts-sidebar.tsx deleted file mode 100644 index 46ddb5eb..00000000 --- a/app/ui/directories/keyboard-shortcuts-sidebar.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { Keyboard, Printer } from "lucide-react"; -import { SidebarLabel } from "@/app/ui/site/app-shell"; -import { SidebarList } from "@/app/ui/site/sidebar-list"; -import { appsInCategory, shortcutAppCatalog, shortcutCategories } from "@/lib/shortcuts"; -import { sidebarPanelClassName, sidebarPanelHeadingClassName } from "@/app/ui/site/sidebar-panel"; -import styles from "./keyboard-shortcuts-sidebar.module.css"; - -const iconProps = { size: 15, strokeWidth: 2.2 } as const; - -function categorySlug(category: string) { - return category.toLowerCase().replace(/[^a-z0-9]+/g, "-"); -} - -export function KeyboardShortcutsSidebar({ - activePage, - activeSlug, - groups, -}: { - activePage?: "directory" | "generator"; - activeSlug?: string; - groups?: { id: string; title: string }[]; -}) { - const activeApp = activeSlug - ? shortcutAppCatalog.find((app) => app.slug === activeSlug) - : undefined; - - return ( -
    -
    - Keyboard shortcuts -
    - - -
    - ); -} diff --git a/app/ui/site/app-shell.module.css b/app/ui/site/app-shell.module.css index 244ea1c1..07fe3753 100644 --- a/app/ui/site/app-shell.module.css +++ b/app/ui/site/app-shell.module.css @@ -22,6 +22,40 @@ top: var(--top-bar-height); } +/* No sidebar: the main column takes the whole width. */ +.pageNone { + grid-template-columns: minmax(0, 1fr); +} + +/* Right sidebar: the content comes first and the footer stays under the content column. */ +.pageRight { + grid-template-areas: + "main aside" + "footer aside"; + grid-template-columns: minmax(0, 1fr) var(--sidebar-width); + grid-template-rows: 1fr auto; +} + +.pageRight > .main { + grid-area: main; + min-height: 0; +} + +.pageRight > .footer { + grid-area: footer; +} + +.asideRight { + align-self: start; + background: var(--color-bg); + border-left: 1px solid var(--color-border); + grid-area: aside; + height: calc(100vh - var(--top-bar-height)); + overflow-y: auto; + position: sticky; + top: var(--top-bar-height); +} + .sidebarBar, .backdrop, .close { @@ -143,6 +177,24 @@ padding-right: 0; } + /* A right sidebar stacks below the content, above the footer. No drawer. */ + .pageRight { + grid-template-areas: + "main" + "aside" + "footer"; + grid-template-columns: minmax(0, 1fr); + grid-template-rows: auto; + } + + .asideRight { + border-left: 0; + border-top: 1px solid var(--color-border); + height: auto; + overflow: visible; + position: static; + } + .sidebarBar { align-items: center; background: var(--color-bg); @@ -251,6 +303,7 @@ .sidebar, .sidebarBar, .backdrop, + .asideRight, .footer { display: none !important; } @@ -265,7 +318,10 @@ /* Sidebar navigation keeps neutral text and its existing row states. */ .sidebar a[href], .sidebar a[href]:hover, -.sidebar a[href]:focus-visible { +.sidebar a[href]:focus-visible, +.asideRight a[href], +.asideRight a[href]:hover, +.asideRight a[href]:focus-visible { color: var(--color-text); text-decoration: none; } diff --git a/app/ui/site/app-shell.tsx b/app/ui/site/app-shell.tsx index 3b934c22..162286a0 100644 --- a/app/ui/site/app-shell.tsx +++ b/app/ui/site/app-shell.tsx @@ -8,32 +8,89 @@ import { intentPrefetch } from "./intent-prefetch"; import styles from "./app-shell.module.css"; import { sidebarPanelTitleClassName } from "./sidebar-panel"; +/** + * Where the page puts its sidebar. Pick it per page, for what the sidebar does: + * - "left", preferred: navigation and options, such as sibling tools, filters, or course lessons. + * - "right": secondary help, such as related pages or links to the page's sections. + * - "none": the page only needs its content. + */ +export type SidebarPosition = "left" | "right" | "none"; + type AppShellProps = { children?: ReactNode; mainLabel?: string; sidebar?: ReactNode; sidebarLabel?: string; - /** Label shown next to the mobile hamburger, e.g. "Lessons" or "Filters". */ + /** Label shown next to the mobile hamburger, e.g. "Lessons" or "Filters". Left sidebars only. */ menuLabel?: string; + sidebarPosition?: SidebarPosition; }; export function SidebarLabel({ children }: { children: ReactNode }) { return

    {children}

    ; } +function SiteFooter() { + const googleAnalytics = getGoogleAnalyticsConfig(); + + return ( + + ); +} + export function AppShell({ children, mainLabel = "Page content", sidebar, sidebarLabel = "Page sidebar", menuLabel = "Menu", + sidebarPosition = "left", }: AppShellProps) { - const googleAnalytics = getGoogleAnalyticsConfig(); + // A right sidebar is secondary, so it follows the content in reading order. On small + // screens it stacks below the content, above the footer, instead of hiding in a drawer. + if (sidebarPosition === "right") { + return ( +
    +
    +
    +
    {children}
    +
    + + +
    +
    + ); + } return (
    -
    - {sidebar ? ( +
    + {sidebarPosition === "none" ? null : sidebar ? ( {sidebar} @@ -42,27 +99,7 @@ export function AppShell({ )}
    {children}
    - +
    diff --git a/app/ui/site/google-analytics-consent.module.css b/app/ui/site/google-analytics-consent.module.css index 340361cf..c7e5559b 100644 --- a/app/ui/site/google-analytics-consent.module.css +++ b/app/ui/site/google-analytics-consent.module.css @@ -74,9 +74,21 @@ background: var(--color-surface-2); } +/* Keep the banner over the main column when the sidebar is on the right or absent. */ +:global(body:has([data-sidebar-position="right"])) .banner { + left: var(--container-gutter); + right: calc(var(--sidebar-width) + var(--container-gutter)); +} + +:global(body:has([data-sidebar-position="none"])) .banner { + left: var(--container-gutter); +} + @media (max-width: 960px) { - .banner { + .banner, + :global(body:has([data-sidebar-position])) .banner { left: var(--container-gutter); + right: var(--container-gutter); } } diff --git a/app/ui/site/page-canvas.module.css b/app/ui/site/page-canvas.module.css index 596ca769..ac817da3 100644 --- a/app/ui/site/page-canvas.module.css +++ b/app/ui/site/page-canvas.module.css @@ -15,6 +15,11 @@ max-width: calc(var(--measure-prose) + var(--container-gutter) + var(--container-gutter)); } +/* With no sidebar, a reading-width section centers in the page. */ +:global([data-sidebar-position="none"]) .reading { + margin-inline: auto; +} + @media (max-width: 900px) { .grid { gap: var(--space-10); diff --git a/app/(site)/(tools)/(dns)/diagnostic-result-ui.tsx b/app/ui/tools/dns/diagnostic-result-ui.tsx similarity index 100% rename from app/(site)/(tools)/(dns)/diagnostic-result-ui.tsx rename to app/ui/tools/dns/diagnostic-result-ui.tsx diff --git a/app/(site)/(tools)/(dns)/dns-diagnostics.module.css b/app/ui/tools/dns/dns-diagnostics.module.css similarity index 100% rename from app/(site)/(tools)/(dns)/dns-diagnostics.module.css rename to app/ui/tools/dns/dns-diagnostics.module.css diff --git a/app/(site)/(tools)/(dns)/dns-tools.css b/app/ui/tools/dns/dns-tools.css similarity index 100% rename from app/(site)/(tools)/(dns)/dns-tools.css rename to app/ui/tools/dns/dns-tools.css diff --git a/app/(site)/(tools)/(domain)/domain-lookup-client.tsx b/app/ui/tools/domain/domain-lookup-client.tsx similarity index 100% rename from app/(site)/(tools)/(domain)/domain-lookup-client.tsx rename to app/ui/tools/domain/domain-lookup-client.tsx diff --git a/app/(site)/(tools)/(domain)/domain-tools.css b/app/ui/tools/domain/domain-tools.css similarity index 100% rename from app/(site)/(tools)/(domain)/domain-tools.css rename to app/ui/tools/domain/domain-tools.css diff --git a/app/ui/tools/tool-family-sidebar.tsx b/app/ui/tools/tool-family-sidebar.tsx deleted file mode 100644 index 9a282f1e..00000000 --- a/app/ui/tools/tool-family-sidebar.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Globe, ListChecks } from "lucide-react"; -import { SidebarLabel } from "@/app/ui/site/app-shell"; -import { PathnameSidebarList } from "@/app/ui/site/pathname-sidebar-list"; -import { sidebarPanelClassName, sidebarPanelHeadingClassName } from "@/app/ui/site/sidebar-panel"; -import { getPublishedToolCatalog } from "@/lib/tool-catalogs"; -import { cardIcon } from "@/lib/card-icons"; - -export async function ToolFamilySidebar({ - catalogSlug, - label, - className = "", -}: { - catalogSlug: string; - label: string; - className?: string; -}) { - const catalog = await getPublishedToolCatalog(catalogSlug); - const items = catalog?.tools.map((tool) => { - const Icon = cardIcon(tool.card_icon_key); - return { - href: `/${tool.slug}`, - label: tool.card_name, - icon: , - }; - }) ?? []; - if (catalogSlug === "domain-tools") { - items.push( - { href: "/epp-status-codes", label: "Domain status codes", icon: }, - { href: "/tld-directory", label: "TLD directory", icon: }, - ); - } - return ( -
    -
    {label}
    - -
    - ); -} diff --git a/content_docs/annual-plan-discount-calculator/tool-spec.md b/content_docs/annual-plan-discount-calculator/tool-spec.md index 2636ab4a..b8830d02 100644 --- a/content_docs/annual-plan-discount-calculator/tool-spec.md +++ b/content_docs/annual-plan-discount-calculator/tool-spec.md @@ -319,8 +319,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/annual-plan-discount-calculator/page.tsx`, `layout.tsx`, `annual-plan-discount-calculator.tsx`, and `annual-plan-discount-calculator.module.css`. Same shell as `break-even-mrr-calculator`. Header icon `Tag` from `lucide-react`. No SaaS sibling uses it, and it matches the card art. -- `app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.spec.json`, `.svg`, and `.ts`, made with marker-art-draw. A new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs`, and a registration line in `lib/card-art.ts`. Both are shared files that other SaaS planners may also touch. Check `git status` before editing, and wait if someone else has them open. +- `app/(site)/(tools)/annual-plan-discount-calculator/page.tsx`, `layout.tsx`, `annual-plan-discount-calculator.tsx`, and `annual-plan-discount-calculator.module.css`. Same shell as `break-even-mrr-calculator`. Header icon `Tag` from `lucide-react`. No SaaS sibling uses it, and it matches the card art. +- `app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator.spec.json`, `.svg`, and `.ts`, made with marker-art-draw. A new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs`, and a registration line in `lib/card-art.ts`. Both are shared files that other SaaS planners may also touch. Check `git status` before editing, and wait if someone else has them open. No URL-restore wrapper. diff --git a/content_docs/arpu-arpa-calculator/tool-spec.md b/content_docs/arpu-arpa-calculator/tool-spec.md index 81b21d2a..2b23254f 100644 --- a/content_docs/arpu-arpa-calculator/tool-spec.md +++ b/content_docs/arpu-arpa-calculator/tool-spec.md @@ -79,7 +79,7 @@ Keep source values and period labels in client memory only. Do not send them in ### Ownership -- Public URL `/arpu-arpa-calculator`. Put the server page and client workbench in `app/(site)/(tools)/(saas)/arpu-arpa-calculator/`, using the SaaS route-group layout, shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned publication or SEO metadata. +- Public URL `/arpu-arpa-calculator`. Put the server page and client workbench in `app/(site)/(tools)/arpu-arpa-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned publication or SEO metadata. - Keep parsing, validation, fixed-point division, and result-state classification in `lib/arpu-arpa-calculator/engine.ts`, with focused independent examples in `tests/pages/arpu-arpa-calculator/`. The route component owns drafts, formatting, focus, errors, and result presentation. Use its CSS module for layout only and shared UI tokens and components for controls and display. No API or background job is needed. - This spec owns the contract. `public.stack127_tool_pages` owns visible tool and catalog-card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog order. Mark development preview copy as temporary. Any dedicated content script belongs under `scripts/arpu-arpa-calculator/`. diff --git a/content_docs/arr-calculator/tool-spec.md b/content_docs/arr-calculator/tool-spec.md index b0aeb2dd..419488ab 100644 --- a/content_docs/arr-calculator/tool-spec.md +++ b/content_docs/arr-calculator/tool-spec.md @@ -63,7 +63,7 @@ Keep the entered financial value in client component memory only. Do not put it ### Ownership -- Public URL `/arr-calculator`. Put the server page and client workbench in `app/(site)/(tools)/(saas)/arr-calculator/`, using the SaaS route-group layout, shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned publication or SEO metadata. +- Public URL `/arr-calculator`. Put the server page and client workbench in `app/(site)/(tools)/arr-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned publication or SEO metadata. - Keep strict parsing, validation, and cent arithmetic in `lib/arr-calculator/engine.ts`; use focused independent examples in `tests/pages/arr-calculator/`. The route component owns currency formatting, form value, focus, error, and result state. Use a colocated CSS module only for route layout and shared tokens/components for controls and display. No API or background job. - This spec owns the calculation contract. `public.stack127_tool_pages` owns visible page and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog rank. Development preview copy must be clearly temporary. Any dedicated page-update script belongs under `scripts/arr-calculator/`. diff --git a/content_docs/break-even-mrr-calculator/tool-spec.md b/content_docs/break-even-mrr-calculator/tool-spec.md index fd263ed2..47181d02 100644 --- a/content_docs/break-even-mrr-calculator/tool-spec.md +++ b/content_docs/break-even-mrr-calculator/tool-spec.md @@ -264,8 +264,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/break-even-mrr-calculator/page.tsx`, `layout.tsx`, `break-even-mrr-calculator.tsx`, and `break-even-mrr-calculator.module.css`. -- `app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator.ts`, plus its registration line in `lib/tool-catalog-art.ts`. +- `app/(site)/(tools)/break-even-mrr-calculator/page.tsx`, `layout.tsx`, `break-even-mrr-calculator.tsx`, and `break-even-mrr-calculator.module.css`. +- `app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator.ts`, plus its registration line in `lib/tool-catalog-art.ts`. No URL-restore wrapper. diff --git a/content_docs/burn-multiple-calculator/tool-spec.md b/content_docs/burn-multiple-calculator/tool-spec.md index e3396f0f..4a519850 100644 --- a/content_docs/burn-multiple-calculator/tool-spec.md +++ b/content_docs/burn-multiple-calculator/tool-spec.md @@ -78,7 +78,7 @@ These checks are independent arithmetic on figures from one stated period, using ### Ownership -- Public URL `/burn-multiple-calculator`. Place the server page and client workbench in `app/(site)/(tools)/(saas)/burn-multiple-calculator/`, using the SaaS route-group layout, shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned publication or SEO metadata. +- Public URL `/burn-multiple-calculator`. Place the server page and client workbench in `app/(site)/(tools)/burn-multiple-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned publication or SEO metadata. - Keep strict parsing, validation, exact-cent inputs, result classification, and ratio rounding in `lib/burn-multiple-calculator/engine.ts`; use independent arithmetic, parser, bounds, and state-precedence examples in `tests/pages/burn-multiple-calculator/`. The route component owns raw form, focus, error, and result state. Use a colocated CSS module only for composition, with shared controls, display components, and tokens. No API route, dataset, or background job. - This spec owns the contract. `public.stack127_tool_pages` owns the visible title, introduction, instructions, supporting Markdown, version, and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog rank. Mark development preview copy as temporary. A dedicated page-update script, if needed, belongs under `scripts/burn-multiple-calculator/`. diff --git a/content_docs/cac-payback-calculator/tool-spec.md b/content_docs/cac-payback-calculator/tool-spec.md index c1cbc095..40347368 100644 --- a/content_docs/cac-payback-calculator/tool-spec.md +++ b/content_docs/cac-payback-calculator/tool-spec.md @@ -298,8 +298,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/cac-payback-calculator/page.tsx`, `layout.tsx`, `cac-payback-calculator.tsx`, and `cac-payback-calculator.module.css`, following the sibling SaaS routes. -- `app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator.ts`, plus its registration line in `lib/tool-catalog-art.ts`. +- `app/(site)/(tools)/cac-payback-calculator/page.tsx`, `layout.tsx`, `cac-payback-calculator.tsx`, and `cac-payback-calculator.module.css`, following the sibling SaaS routes. +- `app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator.ts`, plus its registration line in `lib/tool-catalog-art.ts`. No URL-restore wrapper. Financial inputs don't go in the URL. diff --git a/content_docs/churn-rate-converter/research.md b/content_docs/churn-rate-converter/research.md index d96b93c1..7b948b84 100644 --- a/content_docs/churn-rate-converter/research.md +++ b/content_docs/churn-rate-converter/research.md @@ -76,7 +76,7 @@ Related searches included monthly-to-annual churn rate calculator Excel or app, | If a constant fraction `p` of the remaining cohort churns each month, monthly retention is `1 − p`. After 12 months retention is `(1 − p)^12`, so annual cohort churn is `1 − (1 − p)^12`. The reverse is `1 − (1 − annual churn)^(1/12)`. These reverse and quarterly formulas follow by taking roots or changing the number of periods. | [ChartMogul customer churn report](https://help.chartmogul.com/article/203-chart-customer-churn-rate) confirms that 5% monthly loss corresponds to about 46% annual loss. [ChartMogul cohort retention](https://help.chartmogul.com/article/159-cohort-customer-retention) states the same 5% example and offers monthly, quarterly, and annual intervals. | Treat the formula as a constant-rate conversion, not as a claim that every real cohort loses the same fraction each month. For a source interval of `s` months and target interval of `t` months, use `target churn = 1 − (1 − source churn)^(t/s)`. | | A 5% monthly rate gives `1 − 0.95^12 = 45.96%` annual churn and 54.04% annual retention. With 100 starting customers, the model expects 45.96 lost and 54.04 retained. | [ChartMogul customer churn report](https://help.chartmogul.com/article/203-chart-customer-churn-rate) | Say “about 46 of 100” and “about 54 remain.” These are expected cohort values, not a promise of an exact integer count. The simple `5% × 12 = 60%` estimate overstates this result. | | Quarterly conversions use three months per quarter and four quarters per year. For quarterly churn `q`, annual churn is `1 − (1 − q)^4`. The monthly equivalent is `1 − (1 − q)^(1/3)`. | Derived from the same retention-factor rule above. ChartMogul lists month, quarter, and year as cohort intervals in its [retention report](https://help.chartmogul.com/article/159-cohort-customer-retention). | Label each input period. For example, 5% quarterly churn equals 1.70% monthly equivalent and 18.55% annualized churn. Do not divide or multiply by 3 or 4. | -| Average customer lifetime `1 ÷ p` is a geometric-model expectation in periods, when each surviving customer has the same churn probability each period. | Existing stack127 model: `lib/customer-lifetime-value-calculator/engine.ts`; explanation in `app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/content/article.mdx`. | Use only for customer churn, keep the rate and lifetime period aligned, and say it is not observed tenure. At 0% churn there is no finite estimate. For revenue churn, do not label `1 ÷ rate` as customer lifetime. | +| Average customer lifetime `1 ÷ p` is a geometric-model expectation in periods, when each surviving customer has the same churn probability each period. | Existing stack127 model: `lib/customer-lifetime-value-calculator/engine.ts`; explanation in `app/(site)/(tools)/customer-lifetime-value-calculator/content/article.mdx`. | Use only for customer churn, keep the rate and lifetime period aligned, and say it is not observed tenure. At 0% churn there is no finite estimate. For revenue churn, do not label `1 ÷ rate` as customer lifetime. | | Gross revenue churn measures lost recurring revenue from cancellations and downgrades. Net revenue churn subtracts expansion. Net churn may be negative when expansion exceeds losses. | [Stripe revenue churn guide](https://stripe.com/resources/more/revenue-churn-101-how-to-calculate-it-and-why-it-matters); [ChartMogul NRR definition](https://help.chartmogul.com/article/138-benchmarks) | A net churn rate of `−1%` means 101% net revenue retention for that period. Repeating that same revenue factor for 12 months gives `1 − 1.01^12 = −12.68%` net annual churn, or 112.68% NRR. This is modeled net revenue growth, not a customer survival probability. Do not attach a customer lifetime or “100 customers lost” result to it. For launch, keep the converter focused on customer churn. | | Directly measured annual churn can differ from an annualized monthly rate. Cohort retention changes with customer age, acquisition period, plan, and reactivation. | [ChartMogul cohort analysis](https://help.chartmogul.com/article/161-cohort-analysis); [ChartMogul customer churn report](https://help.chartmogul.com/article/203-chart-customer-churn-rate) | Prefer an actual year-long cohort or renewal result when the user has one. Call the converted result an equivalent or annualized rate. Keep the assumption visible. | | Contract term and payment schedule are different. A lump-sum annual contract often has one renewal decision per year; an annual contract paid in installments has more payment-failure opportunities. | [ChartMogul billing cycles](https://chartmogul.com/saas-metrics/billing-cycles/) | Do not imply that annual-plan customers face the same monthly cancellation hazard as monthly subscribers. The converter changes rate units; it cannot infer renewal timing or involuntary payment churn. | diff --git a/content_docs/churn-rate-converter/tool-spec.md b/content_docs/churn-rate-converter/tool-spec.md index 5d7f9e52..16303bcd 100644 --- a/content_docs/churn-rate-converter/tool-spec.md +++ b/content_docs/churn-rate-converter/tool-spec.md @@ -277,9 +277,9 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/churn-rate-converter/page.tsx`, `layout.tsx`, `churn-rate-converter.tsx`, and `churn-rate-converter.module.css`. +- `app/(site)/(tools)/churn-rate-converter/page.tsx`, `layout.tsx`, `churn-rate-converter.tsx`, and `churn-rate-converter.module.css`. - Placeholder `content/intro.mdx`, `content/usage.mdx`, and `content/article.mdx`, so the route renders until the writing session replaces them. -- Card art in `app/(site)/(tools)/(saas)/churn-rate-converter/art/`, registered as `churn-rate-converter` in `lib/card-art.ts`. +- Card art in `app/(site)/(tools)/churn-rate-converter/art/`, registered as `churn-rate-converter` in `lib/card-art.ts`. No shared file changes are planned. diff --git a/content_docs/customer-acquisition-cost-calculator/tool-spec.md b/content_docs/customer-acquisition-cost-calculator/tool-spec.md index 85a45d9e..8699df43 100644 --- a/content_docs/customer-acquisition-cost-calculator/tool-spec.md +++ b/content_docs/customer-acquisition-cost-calculator/tool-spec.md @@ -285,8 +285,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/page.tsx`, `layout.tsx`, `customer-acquisition-cost-calculator.tsx`, and `customer-acquisition-cost-calculator.module.css`. -- `app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.spec.json`, `.svg`, and `.ts`, generated with marker-art-draw, plus a new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs` and the registration line in `lib/tool-catalog-art.ts`. Another frontend worker currently has both shared files open, so these two edits wait until that worker is done. +- `app/(site)/(tools)/customer-acquisition-cost-calculator/page.tsx`, `layout.tsx`, `customer-acquisition-cost-calculator.tsx`, and `customer-acquisition-cost-calculator.module.css`. +- `app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator.spec.json`, `.svg`, and `.ts`, generated with marker-art-draw, plus a new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs` and the registration line in `lib/tool-catalog-art.ts`. Another frontend worker currently has both shared files open, so these two edits wait until that worker is done. No URL-restore wrapper. Financial inputs don't go in the URL. diff --git a/content_docs/customer-churn-calculator/tool-spec.md b/content_docs/customer-churn-calculator/tool-spec.md index 0da1993a..0ba4a783 100644 --- a/content_docs/customer-churn-calculator/tool-spec.md +++ b/content_docs/customer-churn-calculator/tool-spec.md @@ -81,7 +81,7 @@ These independent checks use the end-of-period opening-base policy above. ### Ownership -- Public URL `/customer-churn-calculator`. Put the server page and client workbench in `app/(site)/(tools)/(saas)/customer-churn-calculator/`, using the SaaS route-group layout, shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. +- Public URL `/customer-churn-calculator`. Put the server page and client workbench in `app/(site)/(tools)/customer-churn-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. - Put parsing, bounds, and calculation in `lib/customer-churn-calculator/engine.ts`; put focused independent arithmetic and invalid-input checks under `tests/pages/customer-churn-calculator/`. The route component owns raw form values, errors, focus, result state, and rendering. Use shared controls and tokens, adding a colocated CSS module only for layout. No API route, external dataset, or background job is needed. - This spec owns the contract. `public.stack127_tool_pages` owns the visible title, introduction, instructions, supporting Markdown, version, and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog rank. Mark any development preview copy as temporary. If a dedicated page update script is needed, put it under `scripts/customer-churn-calculator/`. diff --git a/content_docs/customer-lifetime-value-calculator/tool-spec.md b/content_docs/customer-lifetime-value-calculator/tool-spec.md index 448da7e2..ac860924 100644 --- a/content_docs/customer-lifetime-value-calculator/tool-spec.md +++ b/content_docs/customer-lifetime-value-calculator/tool-spec.md @@ -307,8 +307,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/page.tsx`, `layout.tsx`, `customer-lifetime-value-calculator.tsx`, and `customer-lifetime-value-calculator.module.css`. -- `app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.spec.json`, `.svg`, and `.ts`, generated with marker-art-draw, plus a new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs` and the registration line in `lib/tool-catalog-art.ts`. Another frontend worker currently has both shared files open, so these two edits wait until that worker is done. +- `app/(site)/(tools)/customer-lifetime-value-calculator/page.tsx`, `layout.tsx`, `customer-lifetime-value-calculator.tsx`, and `customer-lifetime-value-calculator.module.css`. +- `app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator.spec.json`, `.svg`, and `.ts`, generated with marker-art-draw, plus a new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs` and the registration line in `lib/tool-catalog-art.ts`. Another frontend worker currently has both shared files open, so these two edits wait until that worker is done. No URL-restore wrapper. diff --git a/content_docs/domain-tools/README.md b/content_docs/domain-tools/README.md index c287958f..36e6a725 100644 --- a/content_docs/domain-tools/README.md +++ b/content_docs/domain-tools/README.md @@ -55,7 +55,7 @@ A Last Update Checker was planned and then cut for exactly this reason. It read ## Rules - The useful input and result sit above the explanatory content. -- Use the shared Stack127 shell and a `DomainToolsSidebar` following the `DnsToolsSidebar` pattern: a clean list of routes that exist now, with no planned entries, disabled links, or coming-soon labels. +- Render each tool through `ToolPageShell`. Its sidebar lists the published tools in the catalog, with no planned entries, disabled links, or coming-soon labels. - Public explanation is server-rendered. User-requested results are client-rendered and out of search indexing. - Findings and information boxes never use a colored left-edge line. - Never replace technical findings with a health score, a grade, or a single badge for a domain. diff --git a/content_docs/free-trial-conversion-calculator/research.md b/content_docs/free-trial-conversion-calculator/research.md index 304b01f8..537ecf6e 100644 --- a/content_docs/free-trial-conversion-calculator/research.md +++ b/content_docs/free-trial-conversion-calculator/research.md @@ -34,7 +34,7 @@ These sources do not support one blended range. ChartMogul's dated, model-specif The tool's core job is to calculate paid conversions as a share of a stated trial cohort. It can also help a founder estimate new MRR from the cohort if the founder supplies a monthly revenue per new account. It should not claim to predict conversion, diagnose product-market fit, decide whether the company should require payment details, or infer lifetime value from the first paid month. -The route is under the `(saas)` tool group and its registry-backed `layout.tsx` remains. The deleted route page, engine, content, test, research file, and spec are absent. The likely primary catalog is `/saas-tools`, based on the current SaaS tool family and sibling SaaS tool docs. The coordinator should confirm the development row's actual catalog membership during planning or integration. No public vendor offers an official, neutral trial-conversion calculator. The official vendor sources found here are analytics and billing documentation, not standalone calculators. +The route's registry-backed `layout.tsx` remains. The deleted route page, engine, content, test, research file, and spec are absent. The likely primary catalog is `/saas-tools`, based on the current SaaS tool family and sibling SaaS tool docs. The coordinator should confirm the development row's actual catalog membership during planning or integration. No public vendor offers an official, neutral trial-conversion calculator. The official vendor sources found here are analytics and billing documentation, not standalone calculators. Queries tried: diff --git a/content_docs/free-trial-conversion-calculator/tool-spec.md b/content_docs/free-trial-conversion-calculator/tool-spec.md index 13e88de1..89b6c329 100644 --- a/content_docs/free-trial-conversion-calculator/tool-spec.md +++ b/content_docs/free-trial-conversion-calculator/tool-spec.md @@ -331,7 +331,7 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/free-trial-conversion-calculator/page.tsx`. Keep `layout.tsx` as it is. +- `app/(site)/(tools)/free-trial-conversion-calculator/page.tsx`. Keep `layout.tsx` as it is. - `free-trial-conversion-calculator.tsx`, the client tool. It calls only the engine contract. - `free-trial-conversion-calculator-from-url.tsx`, the `useInitialQuery()` wrapper, as on `dns-lookup`. - `free-trial-conversion-calculator.module.css`, for the result's two-column top only. diff --git a/content_docs/keyboard-shortcuts/brief.md b/content_docs/keyboard-shortcuts/brief.md index c1dc32ac..1325bb11 100644 --- a/content_docs/keyboard-shortcuts/brief.md +++ b/content_docs/keyboard-shortcuts/brief.md @@ -14,8 +14,8 @@ The former `/shortcuts` hub and its 26 original reference pages permanently redi ## Show vs say -The dotted header uses one small key-sequence drawing to identify the collection. One section per category keeps the catalog easy to scan. Each section uses a table for the repeated -app, platform, and count fields. Each app reference uses grouped tables for actions and platform keys, +The dotted header uses one small key-sequence drawing to identify the collection. One section per category keeps the catalog easy to scan. Each section shows its apps as compact +cards with the name, shortcut count, and Win, Mac, and Linux labels. A platform the app doesn't support shows faded and struck through. Each app reference uses grouped tables for actions and platform keys, with short notes only where a mode or sequence needs explanation. The printable sheet remains a separate tool. Charts, screenshots, provenance labels, and decorative copy do not belong here. @@ -28,4 +28,4 @@ through `public.stack127_pages`. ## Approved keycap and layout treatment -Use the raised-edge keycaps selected from the removed preview. Render real keyboard text on the server, with plus signs inside chords and plain words between sequence steps. Each reference table has two columns, action and shortcuts. Merge identical platform bindings only when alternatives and caveats also match. Keep platform notes and unknown bindings visible. Stack the cells on small screens. Put group links in the existing sidebar, and keep category navigation there on the directory too. Category headings replace generic descriptions. +Use the raised-edge keycaps selected from the removed preview. Render real keyboard text on the server, with plus signs inside chords and plain words between sequence steps. Each reference table has two columns, action and shortcuts. Merge identical platform bindings only when alternatives and caveats also match. Keep platform notes and unknown bindings visible. Stack the cells on small screens. The directory and app pages have no sidebar. Category headings replace generic descriptions. diff --git a/content_docs/ltv-cac-calculator/tool-spec.md b/content_docs/ltv-cac-calculator/tool-spec.md index c2dc5f53..08689a66 100644 --- a/content_docs/ltv-cac-calculator/tool-spec.md +++ b/content_docs/ltv-cac-calculator/tool-spec.md @@ -274,8 +274,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/ltv-cac-calculator/page.tsx`, `layout.tsx`, `ltv-cac-calculator.tsx`, and `ltv-cac-calculator.module.css`. -- `app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator.spec.json`, `.svg`, and `.ts`, generated with marker-art-draw, plus a new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs` and the registration line in `lib/tool-catalog-art.ts`. Another frontend worker currently has both shared files open, so these two edits wait until that worker is done. +- `app/(site)/(tools)/ltv-cac-calculator/page.tsx`, `layout.tsx`, `ltv-cac-calculator.tsx`, and `ltv-cac-calculator.module.css`. +- `app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator.spec.json`, `.svg`, and `.ts`, generated with marker-art-draw, plus a new `toolSpot` motif in `scripts/stack127/marker-art/figures.mjs` and the registration line in `lib/tool-catalog-art.ts`. Another frontend worker currently has both shared files open, so these two edits wait until that worker is done. No URL-restore wrapper. diff --git a/content_docs/mrr-calculator/tool-spec.md b/content_docs/mrr-calculator/tool-spec.md index 7ec35785..e99c4069 100644 --- a/content_docs/mrr-calculator/tool-spec.md +++ b/content_docs/mrr-calculator/tool-spec.md @@ -66,7 +66,7 @@ All figures and plan names stay in client component memory. Do not send them in ### Ownership -- Public URL `/mrr-calculator`. Put the server page and interactive workbench in `app/(site)/(tools)/(saas)/mrr-calculator/`, using the existing SaaS route-group layout, tool-page loader, shared shell, `PageCanvas`, header, and database Markdown renderer. No route-owned SEO or publication metadata. +- Public URL `/mrr-calculator`. Put the server page and interactive workbench in `app/(site)/(tools)/mrr-calculator/`, using the existing tool-page loader, shared shell, `PageCanvas`, header, and database Markdown renderer. No route-owned SEO or publication metadata. - Keep parsing, validation, and arithmetic in `lib/mrr-calculator/engine.ts`; focused independent arithmetic and invalid-input checks belong in `tests/pages/mrr-calculator/`. The route component owns row IDs, form state, focus, and result state. Use a colocated CSS module for the row grid only and shared tokens/components for controls and output. No API, dataset, or background job. - This spec owns the contract. `public.stack127_tool_pages` owns visible page and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog rank. Mark any development preview copy as temporary. If a dedicated page-update script is needed, place it under `scripts/mrr-calculator/`. diff --git a/content_docs/mrr-goal-calculator/tool-spec.md b/content_docs/mrr-goal-calculator/tool-spec.md index 695f0c83..4c882732 100644 --- a/content_docs/mrr-goal-calculator/tool-spec.md +++ b/content_docs/mrr-goal-calculator/tool-spec.md @@ -408,8 +408,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/mrr-goal-calculator/page.tsx`, `layout.tsx`, `mrr-goal-calculator.tsx`, and `mrr-goal-calculator.module.css`. -- `app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator.{spec.json,svg,ts}`, plus its line in `lib/card-art.ts`. +- `app/(site)/(tools)/mrr-goal-calculator/page.tsx`, `layout.tsx`, `mrr-goal-calculator.tsx`, and `mrr-goal-calculator.module.css`. +- `app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator.{spec.json,svg,ts}`, plus its line in `lib/card-art.ts`. No URL-restore wrapper. diff --git a/content_docs/mrr-waterfall-calculator/tool-spec.md b/content_docs/mrr-waterfall-calculator/tool-spec.md index 3fb89642..94432897 100644 --- a/content_docs/mrr-waterfall-calculator/tool-spec.md +++ b/content_docs/mrr-waterfall-calculator/tool-spec.md @@ -73,7 +73,7 @@ Keep month and financial figures in client component memory only. Do not put inp ### Ownership -- Public URL `/mrr-waterfall-calculator`. Put the server page and client workbench in `app/(site)/(tools)/(saas)/mrr-waterfall-calculator/`, using the SaaS route-group layout, shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. +- Public URL `/mrr-waterfall-calculator`. Put the server page and client workbench in `app/(site)/(tools)/mrr-waterfall-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. - Put strict parsing, validation, integer-cent calculations, and ordered bridge data in `lib/mrr-waterfall-calculator/engine.ts`; focused independent arithmetic and invalid-input checks belong in `tests/pages/mrr-waterfall-calculator/`. The route component owns raw form values, focus, status, and rendered result. Use a colocated CSS module for the waterfall and field layout, with shared tokens and controls. No API, maintained data source, or job. - This spec owns the contract. `public.stack127_tool_pages` owns page title, intro, instructions, supporting Markdown, version, and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog rank. Mark any development preview copy as temporary. Any dedicated page-update script belongs under `scripts/mrr-waterfall-calculator/`. diff --git a/content_docs/net-revenue-retention-calculator/tool-spec.md b/content_docs/net-revenue-retention-calculator/tool-spec.md index 78ec5869..1a8e3102 100644 --- a/content_docs/net-revenue-retention-calculator/tool-spec.md +++ b/content_docs/net-revenue-retention-calculator/tool-spec.md @@ -86,7 +86,7 @@ These examples are independent arithmetic checks for the builder. ### Ownership -- Public URL `/net-revenue-retention-calculator`. Put the server page and client workbench in `app/(site)/(tools)/(saas)/net-revenue-retention-calculator/`, using the SaaS route-group layout, shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. +- Public URL `/net-revenue-retention-calculator`. Put the server page and client workbench in `app/(site)/(tools)/net-revenue-retention-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. - Put strict parsing, validation, integer-cent calculation, and percentage formatting data in `lib/net-revenue-retention-calculator/engine.ts`. Focused independent examples and invalid-input tests belong in `tests/pages/net-revenue-retention-calculator/`. The route component owns raw form values, errors, focus, status, and rendering. Use a colocated CSS module for layout with shared tokens and controls. No API, external data source, or background job is needed. - This spec owns the contract. `public.stack127_tool_pages` owns title, introduction, instructions, supporting Markdown, version, and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog rank. Mark any development preview content as temporary. Any dedicated page-update script belongs under `scripts/net-revenue-retention-calculator/`. diff --git a/content_docs/raid-calculator/README.md b/content_docs/raid-calculator/README.md index be10a69e..84a4d8ff 100644 --- a/content_docs/raid-calculator/README.md +++ b/content_docs/raid-calculator/README.md @@ -8,7 +8,7 @@ The page uses the shared engine in `lib/storage/` and the version 1 formula cont ## Page-owned files -- Route and client UI: `app/(site)/(tools)/(storage)/raid-calculator/` +- Route and client UI: `app/(site)/(tools)/raid-calculator/` - Calculation adapter: `lib/storage/raid.ts` - Formula and page tests: `tests/pages/raid-calculator/` - Ownership manifest: `tests/pages/raid-calculator/page.json` diff --git a/content_docs/revenue-churn-calculator/tool-spec.md b/content_docs/revenue-churn-calculator/tool-spec.md index d6b89780..26a5bc41 100644 --- a/content_docs/revenue-churn-calculator/tool-spec.md +++ b/content_docs/revenue-churn-calculator/tool-spec.md @@ -91,7 +91,7 @@ These checks use opening-customer amounts after the attribution above, not raw m ### Ownership -- Public URL `/revenue-churn-calculator`. Put the server page and client workbench in `app/(site)/(tools)/(saas)/revenue-churn-calculator/`, using the shared SaaS route-group layout, shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. +- Public URL `/revenue-churn-calculator`. Put the server page and client workbench in `app/(site)/(tools)/revenue-churn-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Add no route-owned publication or SEO metadata. - Put strict parsing, validation, integer-cent calculation, and percentage formatting data in `lib/revenue-churn-calculator/engine.ts`; focused independent arithmetic, attribution-boundary, and invalid-input checks belong under `tests/pages/revenue-churn-calculator/`. The route component owns raw values, errors, focus, status, and result rendering. Use shared controls and tokens, with a colocated CSS module only for layout. No API route, maintained dataset, account, or background job is needed. - This spec owns the contract. `public.stack127_tool_pages` owns title, introduction, instructions, supporting Markdown, version, and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog placement. Mark development preview copy as temporary. A dedicated update script, if needed, belongs under `scripts/revenue-churn-calculator/`. diff --git a/content_docs/saas-gross-margin-calculator/tool-spec.md b/content_docs/saas-gross-margin-calculator/tool-spec.md index 033be4bb..74d2afa0 100644 --- a/content_docs/saas-gross-margin-calculator/tool-spec.md +++ b/content_docs/saas-gross-margin-calculator/tool-spec.md @@ -83,7 +83,7 @@ Do not send entered period labels, scope names, or financial values to a server, ### Ownership -- Public URL `/saas-gross-margin-calculator`. Put its server page and client workbench in `app/(site)/(tools)/(saas)/saas-gross-margin-calculator/`, using the SaaS route-group layout, shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned SEO or publication metadata. +- Public URL `/saas-gross-margin-calculator`. Put its server page and client workbench in `app/(site)/(tools)/saas-gross-margin-calculator/`, using the shared shell, `PageCanvas`, tool-page loader, and database Markdown renderer. Do not add route-owned SEO or publication metadata. - Keep strict parsing, validation, exact-cent calculations, and undefined-ratio classification in `lib/saas-gross-margin-calculator/engine.ts`; put focused independent examples in `tests/pages/saas-gross-margin-calculator/`. The route owns raw form, focus, error, and result state. Use a colocated CSS module for layout, with shared controls and tokens. No API route, maintained dataset, or background job is needed. - This spec owns the contract. `public.stack127_tool_pages` owns visible title, introduction, instructions, supporting Markdown, version, and card copy; `public.stack127_pages` owns publication and SEO; `public.stack127_tool_catalog_memberships` owns catalog placement. Mark any development preview copy as temporary. A dedicated update script, if needed, belongs under `scripts/saas-gross-margin-calculator/`. diff --git a/content_docs/saas-metrics-calculator/tool-spec.md b/content_docs/saas-metrics-calculator/tool-spec.md index 597fe421..35936fc5 100644 --- a/content_docs/saas-metrics-calculator/tool-spec.md +++ b/content_docs/saas-metrics-calculator/tool-spec.md @@ -104,7 +104,7 @@ These arithmetic checks are calculated from the stated figures, independently of ### Ownership -- Public URL `/saas-metrics-calculator`. Put the server page and interactive component in `app/(site)/(tools)/(saas)/saas-metrics-calculator/`; the new SaaS route group may share its eventual catalog sidebar layout with later SaaS tools. The page uses the existing tool-page loader, shared shell, `PageCanvas`, header, and database Markdown renderer. No route-owned metadata. +- Public URL `/saas-metrics-calculator`. Put the server page and interactive component in `app/(site)/(tools)/saas-metrics-calculator/`. The page uses the existing tool-page loader, shared shell, `PageCanvas`, header, and database Markdown renderer. No route-owned metadata. - Pure parser, validation, and formulas: `lib/saas-metrics-calculator/engine.ts`. Focused arithmetic and invalid-input checks: `tests/pages/saas-metrics-calculator/saas-metrics-calculator.test.mjs`. - Route component owns form and result state. Reuse shared controls and tokens; add a colocated CSS module only where layout needs it. No API route, external dataset, or scheduled job. - Use the existing development tool-page and catalog update scripts. If a dedicated one-off script becomes necessary, place it under `scripts/saas-metrics-calculator/`. diff --git a/content_docs/startup-runway-calculator/tool-spec.md b/content_docs/startup-runway-calculator/tool-spec.md index 6d079073..01828678 100644 --- a/content_docs/startup-runway-calculator/tool-spec.md +++ b/content_docs/startup-runway-calculator/tool-spec.md @@ -388,8 +388,8 @@ Sol builds the backend: Opus builds the frontend: -- `app/(site)/(tools)/(saas)/startup-runway-calculator/page.tsx`, `layout.tsx`, `startup-runway-calculator.tsx`, and `startup-runway-calculator.module.css`. -- `app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator.{spec.json,svg,ts}`, plus its line in `lib/card-art.ts`. Other agents are adding lines there for sibling tools, so the coordinator should order those edits. +- `app/(site)/(tools)/startup-runway-calculator/page.tsx`, `layout.tsx`, `startup-runway-calculator.tsx`, and `startup-runway-calculator.module.css`. +- `app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator.{spec.json,svg,ts}`, plus its line in `lib/card-art.ts`. Other agents are adding lines there for sibling tools, so the coordinator should order those edits. No URL-restore wrapper. diff --git a/content_docs/tld-directory/README.md b/content_docs/tld-directory/README.md index 7e273714..c2806cea 100644 --- a/content_docs/tld-directory/README.md +++ b/content_docs/tld-directory/README.md @@ -18,7 +18,7 @@ It also documents our own coverage. The RDAP column is exactly the gap other pag ## Shape -A filterable table of TLDs, following the patterns already established by `/self-host-apps` rather than inventing a new directory layout. Reuse the shell, the sidebar, the card and table styling, and the filter behavior that page already has. +A filterable table of TLDs, following the patterns already established by `/self-host-apps` rather than inventing a new directory layout. Reuse the shell, the card and table styling, and the filter behavior that page already has. Columns: diff --git a/lib/card-art.ts b/lib/card-art.ts index 9b91d869..9e009872 100644 --- a/lib/card-art.ts +++ b/lib/card-art.ts @@ -67,18 +67,18 @@ import { transferReadinessArt } from "@/app/ui/art/transfer-readiness"; import { unraidArt } from "@/app/ui/art/unraid"; import { zfsCapacityArt } from "@/app/ui/art/zfs-capacity"; import { zfsPaddingArt } from "@/app/ui/art/zfs-padding"; -import { annualPlanDiscountCalculatorArt } from "@/app/(site)/(tools)/(saas)/annual-plan-discount-calculator/art/annual-plan-discount-calculator"; -import { breakEvenMrrCalculatorArt } from "@/app/(site)/(tools)/(saas)/break-even-mrr-calculator/art/break-even-mrr-calculator"; -import { cacPaybackCalculatorArt } from "@/app/(site)/(tools)/(saas)/cac-payback-calculator/art/cac-payback-calculator"; -import { churnRateConverterArt } from "@/app/(site)/(tools)/(saas)/churn-rate-converter/art/churn-rate-converter"; -import { customerAcquisitionCostCalculatorArt } from "@/app/(site)/(tools)/(saas)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator"; -import { customerLifetimeValueCalculatorArt } from "@/app/(site)/(tools)/(saas)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator"; -import { freeTrialConversionCalculatorArt } from "@/app/(site)/(tools)/(saas)/free-trial-conversion-calculator/art/free-trial-conversion-calculator"; -import { ltvCacCalculatorArt } from "@/app/(site)/(tools)/(saas)/ltv-cac-calculator/art/ltv-cac-calculator"; -import { mrrGoalCalculatorArt } from "@/app/(site)/(tools)/(saas)/mrr-goal-calculator/art/mrr-goal-calculator"; -import { saasGrossMarginCalculatorArt } from "@/app/(site)/(tools)/(saas)/saas-gross-margin-calculator/art/saas-gross-margin-calculator"; -import { saasMetricsCalculatorArt } from "@/app/(site)/(tools)/(saas)/saas-metrics-calculator/art/saas-metrics-calculator"; -import { startupRunwayCalculatorArt } from "@/app/(site)/(tools)/(saas)/startup-runway-calculator/art/startup-runway-calculator"; +import { annualPlanDiscountCalculatorArt } from "@/app/(site)/(tools)/annual-plan-discount-calculator/art/annual-plan-discount-calculator"; +import { breakEvenMrrCalculatorArt } from "@/app/(site)/(tools)/break-even-mrr-calculator/art/break-even-mrr-calculator"; +import { cacPaybackCalculatorArt } from "@/app/(site)/(tools)/cac-payback-calculator/art/cac-payback-calculator"; +import { churnRateConverterArt } from "@/app/(site)/(tools)/churn-rate-converter/art/churn-rate-converter"; +import { customerAcquisitionCostCalculatorArt } from "@/app/(site)/(tools)/customer-acquisition-cost-calculator/art/customer-acquisition-cost-calculator"; +import { customerLifetimeValueCalculatorArt } from "@/app/(site)/(tools)/customer-lifetime-value-calculator/art/customer-lifetime-value-calculator"; +import { freeTrialConversionCalculatorArt } from "@/app/(site)/(tools)/free-trial-conversion-calculator/art/free-trial-conversion-calculator"; +import { ltvCacCalculatorArt } from "@/app/(site)/(tools)/ltv-cac-calculator/art/ltv-cac-calculator"; +import { mrrGoalCalculatorArt } from "@/app/(site)/(tools)/mrr-goal-calculator/art/mrr-goal-calculator"; +import { saasGrossMarginCalculatorArt } from "@/app/(site)/(tools)/saas-gross-margin-calculator/art/saas-gross-margin-calculator"; +import { saasMetricsCalculatorArt } from "@/app/(site)/(tools)/saas-metrics-calculator/art/saas-metrics-calculator"; +import { startupRunwayCalculatorArt } from "@/app/(site)/(tools)/startup-runway-calculator/art/startup-runway-calculator"; import { siteSpotDnsToolsArt } from "@/app/(site)/art/site--spot-dns-tools"; import { siteSpotDockerignoreArt } from "@/app/(site)/art/site--spot-dockerignore"; import { siteSpotDomainToolsArt } from "@/app/(site)/art/site--spot-domain-tools"; diff --git a/lib/registered-site-pages.json b/lib/registered-site-pages.json index 4d3501df..f473c59d 100644 --- a/lib/registered-site-pages.json +++ b/lib/registered-site-pages.json @@ -19,6 +19,7 @@ "/components-ui", "/components-ui/[section]", "/components-ui/charts", + "/components-ui/sidebar-modes/[position]", "/customer-acquisition-cost-calculator", "/customer-churn-calculator", "/customer-lifetime-value-calculator", diff --git a/scripts/drive-reliability/refresh-snapshot.mjs b/scripts/drive-reliability/refresh-snapshot.mjs index 8db9d865..ad0314e3 100644 --- a/scripts/drive-reliability/refresh-snapshot.mjs +++ b/scripts/drive-reliability/refresh-snapshot.mjs @@ -5,7 +5,7 @@ import path from "node:path"; import process from "node:process"; const root = process.cwd(); -const target = path.join(root, "app/(site)/(tools)/(storage)/drive-reliability/data/drive-reliability-snapshot.json"); +const target = path.join(root, "app/(site)/(tools)/drive-reliability/data/drive-reliability-snapshot.json"); const allowedSource = "https://www.backblaze.com/"; function fail(message) { diff --git a/skills/stack127/page-build/SKILL.md b/skills/stack127/page-build/SKILL.md index 8fc94774..225bca66 100644 --- a/skills/stack127/page-build/SKILL.md +++ b/skills/stack127/page-build/SKILL.md @@ -10,7 +10,7 @@ Read `AGENTS.md`, `stack127_docs/writing-style.md`, `stack127_docs/page-content. ## Work 1. Confirm the route family, flat public URL, publication state, indexing setting, and data source. Use `registry.is_indexable: false` for thin child pages, filtered views with their own paths, or public pages still being improved. Keep them published when people should be able to use them. -2. Check the shared components and `/components-ui` gallery in development before creating local UI. Implement the page with the shared shell, `PageCanvas`, tokens, components, metadata system, and server-rendered content. Write the page's content as MDX in `content/` beside the route and import it, as `stack127_docs/page-content.md` describes. Tools, directories, and catalogs have no database-content fallback. +2. Check the shared components and `/components-ui` gallery in development before creating local UI. Pick the sidebar position for this page: `left` for navigation and options, `right` for related pages or section links, or `none` when the page only needs its content. Prefer `left`. See Sidebars in `stack127_docs/design-system.md`. Implement the page with the shared shell, `PageCanvas`, tokens, components, metadata system, and server-rendered content. Write the page's content as MDX in `content/` beside the route and import it, as `stack127_docs/page-content.md` describes. Tools, directories, and catalogs have no database-content fallback. 3. Keep the page static and on-demand revalidated, as `stack127_docs/caching.md` describes. No `force-dynamic`, no timed `revalidate`, and no server `searchParams`, `headers()`, or `cookies()`. URL-dependent parts are client components. A new data source gets a cache tag and pipeline coverage. 4. Keep page styles beside the page or component. Do not add page selectors to `app/globals.css`. 5. Add a focused test only for calculations, parsers, data transforms, or a failure that could return a wrong answer. Do not test prose, documentation, skill wording, hashes, file inventories, or incidental markup. diff --git a/stack127_docs/css-architecture.md b/stack127_docs/css-architecture.md index 325b142d..52ec198b 100644 --- a/stack127_docs/css-architecture.md +++ b/stack127_docs/css-architecture.md @@ -25,9 +25,10 @@ Sidebar titles use the shared `SidebarLabel` component from `app/ui/site/app-she ### Family stylesheets -A route family with several components that work together may use one family stylesheet. It sits with the family and is imported by the family's layout. Current examples: +A route family with several components that work together may use one family stylesheet. It sits with the family and is imported by the layout or pages that use it. Current examples: -- `app/(site)/(tools)/(dns)/dns-tools.css` +- `app/ui/tools/dns/dns-tools.css` +- `app/ui/tools/domain/domain-tools.css` - `app/ui/directories/directory.css` - `app/(site)/(courses)/self-hosting-for-beginners/course.css` - `app/(site)/(directories)/software-licenses-for-self-hosting/software-licenses.css` @@ -36,17 +37,17 @@ Prefer CSS Modules for new components and new single-page work. Use a family sty ### Tool styles -Flat tool pages live under `app/(site)/(tools)/`. The `(tools)` and family route groups never appear in a public URL. +Flat tool pages live under `app/(site)/(tools)//`. The `(tools)` route group never appears in a public URL. -- DNS and domain family layouts import their shared styles. +- Each tool page that uses the DNS or domain family stylesheet imports it first, before its other styles. - Storage tools use CSS Modules. -- Unrelated tools don't inherit DNS or domain CSS. +- Unrelated tools and catalogs don't load DNS or domain CSS. ## Building a page -1. Use `AppShell` with `PageCanvas` for each outer content section. `EntryHero` already includes a canvas. Use the shared navigation, sidebar-panel, prose, media, and code-block components where they fit. +1. Use `AppShell` with `PageCanvas` for each outer content section. Set `sidebarPosition` to `left`, `right`, or `none`, as the Sidebars section of [design-system.md](design-system.md) describes. `EntryHero` already includes a canvas. Use the shared navigation, sidebar-panel, prose, media, and code-block components where they fit. 2. Put the page's other styles in its route folder or beside its component. -3. Import family CSS from the nearest route layout. Import a CSS Module directly from the component that owns it. +3. Import family CSS from the layout or pages that use it, not from a layout that also serves unrelated pages. Import a CSS Module directly from the component that owns it. 4. Use semantic tokens from `globals.css`. Don't create another global token layer in a page file. Every bounded UI shape uses the shared 2px `--radius` token. 5. Keep reading copy inside the prose primitive. Keep controls, tables, metadata, and tool results on the compact UI scale. 6. Check the page in both themes, at desktop and mobile width. diff --git a/stack127_docs/design-system.md b/stack127_docs/design-system.md index 494b7b30..0c3d1848 100644 --- a/stack127_docs/design-system.md +++ b/stack127_docs/design-system.md @@ -208,19 +208,24 @@ Results read like an answer, in this order: ### Sidebars -Every page keeps the sidebar. It holds the page's side space, so the main column stays at a readable width instead of stretching across the screen. +Each page picks where its sidebar goes with the `sidebarPosition` prop on `AppShell`. Choose it page by page, for what the sidebar does on that page. A parent page and its child pages can use different positions. -A sidebar has one of three jobs: +| Position | Use it for | Small screens | +| --- | --- | --- | +| `left`, the default | Navigation and options: sibling tools, other catalogs, directory filters, sort and view controls, course lessons | Opens from the drawer. Its label names the job, for example "Filters" or "Lessons". | +| `right` | Secondary help: related pages, links to the page's sections | Sits below the content, above the footer. No drawer. | +| `none` | Pages that only need their content | Nothing extra. | -| Job | Examples | -| --- | --- | -| Options | Directory filters, sort, and view controls | -| Moving between related pages | Tool family lists, catalog lists, course lessons, shortcut apps | -| Jumping to page sections | Anchored sections of a long directory page | +A sidebar is never required. If a page has nothing useful for one, use `none`. Don't add links or text only to fill the space. + +Don't put reading content in any sidebar. That includes "about this page" paragraphs, method notes, disclaimers, and summaries. Those belong in the main column. + +Width follows the position: -Don't put reading content in the sidebar. That includes "about this page" paragraphs, method notes, disclaimers, and summaries. Those belong in the main column. If a page has nothing for these jobs, link to related pages instead of adding filler. +- With a sidebar, the main column fills the rest of the page. Wide and reading sections both start at its left edge. +- With `none`, the main column takes the whole width. Wide sections such as tables, card grids, and tool workbenches fill it. `PageCanvas reading` sections center at the reading width. -On small screens, the sidebar opens from the existing drawer. Its label names the job, for example "Filters", "Lessons", or "Sections". +The sidebar position previews at `/components-ui/sidebar-modes/left`, `/right`, and `/none` in development. Sidebars that list things use `SidebarList` from `app/ui/site/sidebar-list.tsx`. It has small rows, optional mono numbers and counts, and a `--color-surface-2` active fill with an accent-ink leading cell. @@ -232,11 +237,11 @@ Sidebars that list things use `SidebarList` from `app/ui/site/sidebar-list.tsx`. Don't hand-roll another sidebar link list. -Tool catalog sidebars link between published tool catalogs and mark the current one. Individual tools belong in the catalog's main cards, not in a duplicate sidebar list. Individual tool pages keep their family tool navigation. +Tool catalog sidebars link between published tool catalogs and mark the current one. Individual tools belong in the catalog's main cards, not in a duplicate sidebar list. Individual tool pages list the other tools in their catalog. Tool pages and catalogs use `left`. ### Homepage -The homepage lists published tool catalogs, selected directories, the self-hosting course, and Labs. Hardware directories stay published but are off the homepage cards and sidebar. The homepage doesn't list individual tools or directory child pages. Card names and descriptions come from each family's page table. +The homepage lists published tool catalogs, selected directories, the self-hosting course, and Labs. Hardware directories stay published but are off the homepage cards. The homepage uses `none` and doesn't list individual tools or directory child pages. Card names and descriptions come from each family's page table. Each card shows a meaningful count from its destination's data. A new homepage collection needs an identity icon, a metric, and a marker spot. diff --git a/stack127_docs/page-families.md b/stack127_docs/page-families.md index f976bb6f..b8a43194 100644 --- a/stack127_docs/page-families.md +++ b/stack127_docs/page-families.md @@ -39,9 +39,9 @@ The group names organize the repository. They never appear in public URLs. ## Shared structure -- Every page uses the shared site navigation and `AppShell`, including its sidebar. The sidebar holds options, links between related pages, or links to page sections. It never holds reading content. See Sidebars in [design-system.md](design-system.md). +- Every page uses the shared site navigation and `AppShell`. Each page picks its sidebar position: `left` for navigation and options, `right` for related pages and section links, or `none`. Prefer `left`. A sidebar never holds reading content. See Sidebars in [design-system.md](design-system.md). - All page families use `PageCanvas` and the same responsive gutters. -- Text-led pages use its 760px reading width. Directories, tool workbenches, tables, and card grids stay wide. Both widths start at the same left edge. +- Text-led pages use its 760px reading width. Directories, tool workbenches, tables, and card grids stay wide. With a sidebar, both widths start at the same left edge. With no sidebar, reading sections center. - `EntryHero` uses the canvas inside it, so entry headers and body sections line up. Don't nest canvases. - Visible titles and introductions use `PageHeader`. - Reading content uses the classes exported by `app/ui/site/prose.ts`, so heading and paragraph rhythm comes from one place. @@ -79,8 +79,8 @@ Directory routes live under `app/(site)/(directories)/`. Shared directory contro - Use the shared directory header, controls, spacing, filter components, `Pagination`, `DetailDialog`, and `StatePanel` where they fit. - Use cards when each result has several facts and its own identity. - Use a table when people compare the same short fields across many rows. -- Use prose for explanation and anchored sections for scanning a long page. Put section links in the sidebar. -- Keep filters in the sidebar on wide screens and in the existing drawer on small screens. +- Use prose for explanation and anchored sections for scanning a long page. Put section links in a right sidebar. +- Keep filters in a left sidebar on wide screens and in the existing drawer on small screens. A directory with no filters or sections doesn't need a sidebar. - Don't show crawler records, import state, editorial status, or other maintenance details. The page is static and shows the default view: first page, default sort, no filters. Filters, search, sort, and pagination run in a client component, and their query URLs stay `noindex`. A view worth indexing, such as a category, gets its own path. Read `stack127_docs/caching.md`. @@ -114,7 +114,7 @@ Tools help someone answer one concrete question. The page order: Tool routes live under `app/(site)/(tools)/`. The interactive part and the page content stay in code: the introduction, usage, and article are MDX files beside the route. The title, version, and card fields live in `public.stack127_tool_pages`. Read `stack127_docs/tool-pages.md` before you change tool content or a tool version. -DNS, domain, and storage tools sit under route groups inside `(tools)`. Each group layout owns its sidebar and shell, so moving between tools in that family replaces only the page content. Code shared by one group, such as DNS diagnostics or the domain tools sidebar, lives in that group folder. Shared tool shells live in `app/ui/tools/`. +Every tool sits in its own flat folder, `app/(site)/(tools)//`. There are no tool family route groups. Each tool page renders its shell and left sidebar through `ToolPageShell`. Code shared by a tool family, such as DNS diagnostics or the domain lookup client, lives in `app/ui/tools//`. Shared tool shells live in `app/ui/tools/`. The tool page is static. Values from a shared link are read in a small client wrapper with `useInitialQuery()` from `app/ui/tools/use-initial-query.ts`, never from the server page. Read `stack127_docs/caching.md`. diff --git a/stack127_docs/page-publishing.md b/stack127_docs/page-publishing.md index 5366b722..f868fc2b 100644 --- a/stack127_docs/page-publishing.md +++ b/stack127_docs/page-publishing.md @@ -68,7 +68,7 @@ A manifest describes one batch of pages. All pages in a batch succeed or fail to { "slug": "domain-tools", "display_order": 11 } ], "requirements": { - "route": "app/(site)/(tools)/(dns)/dns-lookup/page.tsx", + "route": "app/(site)/(tools)/dns-lookup/page.tsx", "assets": ["lib/card-art.ts"], "checks": [], "smoke": [{ "path": "/dns-lookup", "text": "DNS lookup" }] diff --git a/stack127_docs/repo-structure.md b/stack127_docs/repo-structure.md index 6b78ca6d..6191a160 100644 --- a/stack127_docs/repo-structure.md +++ b/stack127_docs/repo-structure.md @@ -30,7 +30,7 @@ Shared components live in `app/ui/`, grouped by use. Page data and one-off inter | --- | --- | | Catalogs | Only the catalog route. Tool code never lives here. | | Directories | Directory routes, including stable fact pages such as `/epp-status-codes` and `/tld-directory`. | -| Tools | Tool routes. Code shared by one tool group lives in that group folder, such as `(tools)/(dns)/`. | +| Tools | Tool routes, one flat folder per tool. Code shared by a tool family lives in `app/ui/tools//`, such as `app/ui/tools/dns/`. | See [page-families.md](page-families.md) for each family's page table. diff --git a/stack127_docs/shared-ui.md b/stack127_docs/shared-ui.md index 026c76b4..92a8619b 100644 --- a/stack127_docs/shared-ui.md +++ b/stack127_docs/shared-ui.md @@ -42,7 +42,7 @@ import { UiDataTable } from "@/app/ui/display"; import { Callout } from "@/app/ui/callout"; ``` -The gallery is the component library. It groups components by what they do, not by the page family that first used them, because any page can use any component. Its sidebar links one page per section: text and choices, numbers and sliders, actions and forms, file uploads, filters and sorting, results, tables, charts, cards, content, prose, media and art, feedback and dialogs, navigation, and page layout. `/components-ui` lists every section and its components. Page layout links to real pages for full layouts. The TypeScript props beside each component are the full API. The table above helps you pick the right one. +The gallery is the component library. It groups components by what they do, not by the page family that first used them, because any page can use any component. Its sidebar links one page per section: text and choices, numbers and sliders, actions and forms, file uploads, filters and sorting, results, tables, charts, cards, content, prose, media and art, feedback and dialogs, navigation, and page layout. `/components-ui` lists every section and its components. Page layout links to real pages for full layouts, and to `/components-ui/sidebar-modes/left`, `/right`, and `/none`, which show the real shell with each sidebar position. The TypeScript props beside each component are the full API. The table above helps you pick the right one. To add a component to the gallery, add an `Example` to the matching file in `app/(site)/(components-ui)/components-ui/examples/` and add its name to that section in `sections.ts`. Add a new section only when no existing type fits. diff --git a/tests/pages/ceph-capacity-calculator/ceph-capacity-calculator.test.mjs b/tests/pages/ceph-capacity-calculator/ceph-capacity-calculator.test.mjs index 0d32360e..523b5d28 100644 --- a/tests/pages/ceph-capacity-calculator/ceph-capacity-calculator.test.mjs +++ b/tests/pages/ceph-capacity-calculator/ceph-capacity-calculator.test.mjs @@ -12,7 +12,7 @@ import { parseCapacityBytes, serializeCephInput, validateCephInput, -} from "../../../app/(site)/(tools)/(storage)/ceph-capacity-calculator/ceph-capacity-engine.ts"; +} from "../../../app/(site)/(tools)/ceph-capacity-calculator/ceph-capacity-engine.ts"; const TB = 1_000_000_000_000n; const GB = 1_000_000_000n; diff --git a/tests/pages/drive-reliability/drive-reliability.test.mjs b/tests/pages/drive-reliability/drive-reliability.test.mjs index 003cac43..41c638b8 100644 --- a/tests/pages/drive-reliability/drive-reliability.test.mjs +++ b/tests/pages/drive-reliability/drive-reliability.test.mjs @@ -16,7 +16,7 @@ import { const snapshotPath = path.resolve( import.meta.dirname, - "../../../app/(site)/(tools)/(storage)/drive-reliability/data/drive-reliability-snapshot.json", + "../../../app/(site)/(tools)/drive-reliability/data/drive-reliability-snapshot.json", ); function snapshot() { diff --git a/tests/pages/shr-calculator/shr-capacity.test.mjs b/tests/pages/shr-calculator/shr-capacity.test.mjs index 63647b7c..4fdef4f4 100644 --- a/tests/pages/shr-calculator/shr-capacity.test.mjs +++ b/tests/pages/shr-calculator/shr-capacity.test.mjs @@ -8,7 +8,7 @@ import { encodeShrState, calculateShrCapacity, parseCapacity, -} from "../../../app/(site)/(tools)/(storage)/shr-calculator/shr-capacity.ts"; +} from "../../../app/(site)/(tools)/shr-calculator/shr-capacity.ts"; const GB = 1_000_000_000n; const TB = 1_000_000_000_000n; diff --git a/tests/pages/snapraid-mergerfs-planner/snapraid-merfs-engine.test.mjs b/tests/pages/snapraid-mergerfs-planner/snapraid-merfs-engine.test.mjs index 087beae4..7f239144 100644 --- a/tests/pages/snapraid-mergerfs-planner/snapraid-merfs-engine.test.mjs +++ b/tests/pages/snapraid-mergerfs-planner/snapraid-merfs-engine.test.mjs @@ -5,7 +5,7 @@ import { STANDARD_EXCLUDES, buildSnapraidMergerfsPlan, parseCapacity, -} from "../../../app/(site)/(tools)/(storage)/snapraid-mergerfs-planner/snapraid-merfs-engine.ts"; +} from "../../../app/(site)/(tools)/snapraid-mergerfs-planner/snapraid-merfs-engine.ts"; const baseline = () => ({ data: [ diff --git a/tests/pages/storage-growth-planner/storage-growth-planner-engine.test.mjs b/tests/pages/storage-growth-planner/storage-growth-planner-engine.test.mjs index c1feb0c7..54d651a9 100644 --- a/tests/pages/storage-growth-planner/storage-growth-planner-engine.test.mjs +++ b/tests/pages/storage-growth-planner/storage-growth-planner-engine.test.mjs @@ -9,7 +9,7 @@ import { formatCapacity, formatMoney, validateStorageGrowthInput, -} from "../../../app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner-engine.ts"; +} from "../../../app/(site)/(tools)/storage-growth-planner/storage-growth-planner-engine.ts"; const TB = 1_000_000_000_000n; diff --git a/tests/pages/storage-growth-planner/storage-growth-planner-state.test.mjs b/tests/pages/storage-growth-planner/storage-growth-planner-state.test.mjs index e009a8ed..9ac7b9ca 100644 --- a/tests/pages/storage-growth-planner/storage-growth-planner-state.test.mjs +++ b/tests/pages/storage-growth-planner/storage-growth-planner-state.test.mjs @@ -5,7 +5,7 @@ import { calculateStorageGrowthPlan, decodeStorageGrowthState, encodeStorageGrowthState, -} from "../../../app/(site)/(tools)/(storage)/storage-growth-planner/storage-growth-planner-engine.ts"; +} from "../../../app/(site)/(tools)/storage-growth-planner/storage-growth-planner-engine.ts"; test("FF-006 shares normalized inputs only and round-trips safely", () => { const encoded = encodeStorageGrowthState(DEFAULT_STORAGE_GROWTH_INPUT); diff --git a/tests/pages/storage-layout-advisor/storage-layout-advisor.test.mjs b/tests/pages/storage-layout-advisor/storage-layout-advisor.test.mjs index fd3a86fd..231372fd 100644 --- a/tests/pages/storage-layout-advisor/storage-layout-advisor.test.mjs +++ b/tests/pages/storage-layout-advisor/storage-layout-advisor.test.mjs @@ -12,7 +12,7 @@ import { decodeStorageLayoutAdvisorState, encodeStorageLayoutAdvisorState, validateStorageLayoutAdvisorInput, -} from "../../../app/(site)/(tools)/(storage)/storage-layout-advisor/storage-layout-advisor-engine.ts"; +} from "../../../app/(site)/(tools)/storage-layout-advisor/storage-layout-advisor-engine.ts"; const TB = 1_000_000_000_000n; const TiB = 1_099_511_627_776n; diff --git a/tests/pages/unraid-calculator/unraid-calculator.test.mjs b/tests/pages/unraid-calculator/unraid-calculator.test.mjs index d84598ae..02fe4309 100644 --- a/tests/pages/unraid-calculator/unraid-calculator.test.mjs +++ b/tests/pages/unraid-calculator/unraid-calculator.test.mjs @@ -11,7 +11,7 @@ import { encodeUnraidState, parseUnraidCapacity, validateUnraidCalculatorInput, -} from "../../../app/(site)/(tools)/(storage)/unraid-calculator/unraid-calculator-engine.ts"; +} from "../../../app/(site)/(tools)/unraid-calculator/unraid-calculator-engine.ts"; const GB = 1_000_000_000n; const TB = 1_000_000_000_000n;