create-mithaq 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/LICENSES/payload.txt +22 -0
- package/LICENSES/ponytail.txt +21 -0
- package/index.js +127 -0
- package/package.json +19 -4
- package/template/apps/asas-platform/components.json +25 -0
- package/template/apps/asas-platform/gitignore +3 -0
- package/template/apps/asas-platform/package.json +55 -0
- package/template/apps/asas-platform/public/favicon.svg +1 -0
- package/template/apps/asas-platform/src/api.ts +147 -0
- package/template/apps/asas-platform/src/auth-frame.tsx +150 -0
- package/template/apps/asas-platform/src/components/mithaq/cells.tsx +112 -0
- package/template/apps/asas-platform/src/components/mithaq/controls.tsx +650 -0
- package/template/apps/asas-platform/src/components/mithaq/field-shell.tsx +53 -0
- package/template/apps/asas-platform/src/components/mithaq/filter-operators.ts +108 -0
- package/template/apps/asas-platform/src/components/mithaq/form.tsx +1467 -0
- package/template/apps/asas-platform/src/components/mithaq/list-columns.tsx +108 -0
- package/template/apps/asas-platform/src/components/mithaq/list-filters.tsx +368 -0
- package/template/apps/asas-platform/src/components/mithaq/list-pagination.tsx +153 -0
- package/template/apps/asas-platform/src/components/mithaq/list-query.ts +432 -0
- package/template/apps/asas-platform/src/components/mithaq/list-selection.tsx +74 -0
- package/template/apps/asas-platform/src/components/mithaq/list.tsx +865 -0
- package/template/apps/asas-platform/src/components/mithaq/nav.tsx +871 -0
- package/template/apps/asas-platform/src/components/mithaq/nodes.tsx +1024 -0
- package/template/apps/asas-platform/src/components/mithaq/relationship-cell.tsx +127 -0
- package/template/apps/asas-platform/src/components/mithaq/relationship-control.tsx +400 -0
- package/template/apps/asas-platform/src/components/mithaq/rich-text-nodes.ts +6 -0
- package/template/apps/asas-platform/src/components/mithaq/rich-text.tsx +1083 -0
- package/template/apps/asas-platform/src/components/mithaq/upload.tsx +686 -0
- package/template/apps/asas-platform/src/components/ui/accordion.tsx +74 -0
- package/template/apps/asas-platform/src/components/ui/alert-dialog.tsx +185 -0
- package/template/apps/asas-platform/src/components/ui/avatar.tsx +106 -0
- package/template/apps/asas-platform/src/components/ui/badge.tsx +48 -0
- package/template/apps/asas-platform/src/components/ui/breadcrumb.tsx +124 -0
- package/template/apps/asas-platform/src/components/ui/button-group.tsx +87 -0
- package/template/apps/asas-platform/src/components/ui/button.tsx +55 -0
- package/template/apps/asas-platform/src/components/ui/calendar.tsx +223 -0
- package/template/apps/asas-platform/src/components/ui/card.tsx +102 -0
- package/template/apps/asas-platform/src/components/ui/chart.tsx +371 -0
- package/template/apps/asas-platform/src/components/ui/checkbox.tsx +28 -0
- package/template/apps/asas-platform/src/components/ui/collapsible.tsx +19 -0
- package/template/apps/asas-platform/src/components/ui/combobox.tsx +308 -0
- package/template/apps/asas-platform/src/components/ui/dialog.tsx +158 -0
- package/template/apps/asas-platform/src/components/ui/direction.tsx +6 -0
- package/template/apps/asas-platform/src/components/ui/directional-icon.tsx +20 -0
- package/template/apps/asas-platform/src/components/ui/drawer.tsx +216 -0
- package/template/apps/asas-platform/src/components/ui/dropdown-menu.tsx +267 -0
- package/template/apps/asas-platform/src/components/ui/field.tsx +236 -0
- package/template/apps/asas-platform/src/components/ui/input-group.tsx +155 -0
- package/template/apps/asas-platform/src/components/ui/input-otp.tsx +84 -0
- package/template/apps/asas-platform/src/components/ui/input.tsx +19 -0
- package/template/apps/asas-platform/src/components/ui/label.tsx +19 -0
- package/template/apps/asas-platform/src/components/ui/popover.tsx +90 -0
- package/template/apps/asas-platform/src/components/ui/radio-group.tsx +37 -0
- package/template/apps/asas-platform/src/components/ui/resizable.tsx +47 -0
- package/template/apps/asas-platform/src/components/ui/scroll-area.tsx +54 -0
- package/template/apps/asas-platform/src/components/ui/select.tsx +204 -0
- package/template/apps/asas-platform/src/components/ui/separator.tsx +24 -0
- package/template/apps/asas-platform/src/components/ui/sheet.tsx +139 -0
- package/template/apps/asas-platform/src/components/ui/sidebar.tsx +714 -0
- package/template/apps/asas-platform/src/components/ui/skeleton.tsx +13 -0
- package/template/apps/asas-platform/src/components/ui/slider.tsx +55 -0
- package/template/apps/asas-platform/src/components/ui/spinner.tsx +10 -0
- package/template/apps/asas-platform/src/components/ui/switch.tsx +29 -0
- package/template/apps/asas-platform/src/components/ui/table.tsx +115 -0
- package/template/apps/asas-platform/src/components/ui/tabs.tsx +79 -0
- package/template/apps/asas-platform/src/components/ui/textarea.tsx +17 -0
- package/template/apps/asas-platform/src/components/ui/toggle-group.tsx +89 -0
- package/template/apps/asas-platform/src/components/ui/toggle.tsx +44 -0
- package/template/apps/asas-platform/src/components/ui/tooltip.tsx +63 -0
- package/template/apps/asas-platform/src/copy.ts +1 -0
- package/template/apps/asas-platform/src/hooks/use-mobile.ts +19 -0
- package/template/apps/asas-platform/src/lib/utils.ts +1 -0
- package/template/apps/asas-platform/src/links.ts +38 -0
- package/template/apps/asas-platform/src/locale-switch.tsx +26 -0
- package/template/apps/asas-platform/src/redirect.ts +1 -0
- package/template/apps/asas-platform/src/request-headers.ts +11 -0
- package/template/apps/asas-platform/src/routeTree.gen.ts +181 -0
- package/template/apps/asas-platform/src/router.tsx +7 -0
- package/template/apps/asas-platform/src/routes/(screens)/platform/files.ts +4 -0
- package/template/apps/asas-platform/src/routes/(screens)/platform/screen.json +3609 -0
- package/template/apps/asas-platform/src/routes/(screens)/platform/types.ts +145 -0
- package/template/apps/asas-platform/src/routes/(screens)/platform.$.tsx +17 -0
- package/template/apps/asas-platform/src/routes/(screens)/platform.index.tsx +10 -0
- package/template/apps/asas-platform/src/routes/(screens)/platform.tsx +13 -0
- package/template/apps/asas-platform/src/routes/__root.tsx +95 -0
- package/template/apps/asas-platform/src/routes/api/$.ts +30 -0
- package/template/apps/asas-platform/src/routes/auth.sign-in.tsx +72 -0
- package/template/apps/asas-platform/src/routes/unauthorized.tsx +122 -0
- package/template/apps/asas-platform/src/screen-form.tsx +34 -0
- package/template/apps/asas-platform/src/screen-list.tsx +139 -0
- package/template/apps/asas-platform/src/screen-names.ts +10 -0
- package/template/apps/asas-platform/src/screens.tsx +868 -0
- package/template/apps/asas-platform/src/server.ts +20 -0
- package/template/apps/asas-platform/src/slide.ts +22 -0
- package/template/apps/asas-platform/src/start.ts +42 -0
- package/template/apps/asas-platform/src/styles.css +200 -0
- package/template/apps/asas-platform/src/theme.ts +2 -0
- package/template/apps/asas-platform/tsconfig.json +19 -0
- package/template/apps/asas-platform/vite.config.ts +26 -0
- package/template/apps/asas-tanstack/components.json +25 -0
- package/template/apps/asas-tanstack/gitignore +3 -0
- package/template/apps/asas-tanstack/package.json +56 -0
- package/template/apps/asas-tanstack/public/favicon.svg +1 -0
- package/template/apps/asas-tanstack/src/api.ts +147 -0
- package/template/apps/asas-tanstack/src/auth-frame.tsx +150 -0
- package/template/apps/asas-tanstack/src/components/mithaq/cells.tsx +112 -0
- package/template/apps/asas-tanstack/src/components/mithaq/controls.tsx +650 -0
- package/template/apps/asas-tanstack/src/components/mithaq/field-shell.tsx +53 -0
- package/template/apps/asas-tanstack/src/components/mithaq/filter-operators.ts +108 -0
- package/template/apps/asas-tanstack/src/components/mithaq/form.tsx +1467 -0
- package/template/apps/asas-tanstack/src/components/mithaq/list-columns.tsx +108 -0
- package/template/apps/asas-tanstack/src/components/mithaq/list-filters.tsx +368 -0
- package/template/apps/asas-tanstack/src/components/mithaq/list-pagination.tsx +153 -0
- package/template/apps/asas-tanstack/src/components/mithaq/list-query.ts +432 -0
- package/template/apps/asas-tanstack/src/components/mithaq/list-selection.tsx +74 -0
- package/template/apps/asas-tanstack/src/components/mithaq/list.tsx +865 -0
- package/template/apps/asas-tanstack/src/components/mithaq/nav.tsx +871 -0
- package/template/apps/asas-tanstack/src/components/mithaq/nodes.tsx +1024 -0
- package/template/apps/asas-tanstack/src/components/mithaq/relationship-cell.tsx +127 -0
- package/template/apps/asas-tanstack/src/components/mithaq/relationship-control.tsx +400 -0
- package/template/apps/asas-tanstack/src/components/mithaq/rich-text-nodes.ts +6 -0
- package/template/apps/asas-tanstack/src/components/mithaq/rich-text.tsx +1083 -0
- package/template/apps/asas-tanstack/src/components/mithaq/upload.tsx +686 -0
- package/template/apps/asas-tanstack/src/components/ui/accordion.tsx +10 -0
- package/template/apps/asas-tanstack/src/components/ui/alert-dialog.tsx +173 -0
- package/template/apps/asas-tanstack/src/components/ui/avatar.tsx +104 -0
- package/template/apps/asas-tanstack/src/components/ui/badge.tsx +48 -0
- package/template/apps/asas-tanstack/src/components/ui/breadcrumb.tsx +125 -0
- package/template/apps/asas-tanstack/src/components/ui/button-group.tsx +87 -0
- package/template/apps/asas-tanstack/src/components/ui/button.tsx +56 -0
- package/template/apps/asas-tanstack/src/components/ui/calendar.tsx +223 -0
- package/template/apps/asas-tanstack/src/components/ui/card.tsx +94 -0
- package/template/apps/asas-tanstack/src/components/ui/chart.tsx +369 -0
- package/template/apps/asas-tanstack/src/components/ui/checkbox.tsx +27 -0
- package/template/apps/asas-tanstack/src/components/ui/collapsible.tsx +19 -0
- package/template/apps/asas-tanstack/src/components/ui/combobox.tsx +300 -0
- package/template/apps/asas-tanstack/src/components/ui/dialog.tsx +149 -0
- package/template/apps/asas-tanstack/src/components/ui/direction.tsx +5 -0
- package/template/apps/asas-tanstack/src/components/ui/directional-icon.tsx +20 -0
- package/template/apps/asas-tanstack/src/components/ui/drawer.tsx +215 -0
- package/template/apps/asas-tanstack/src/components/ui/dropdown-menu.tsx +267 -0
- package/template/apps/asas-tanstack/src/components/ui/field.tsx +225 -0
- package/template/apps/asas-tanstack/src/components/ui/input-group.tsx +147 -0
- package/template/apps/asas-tanstack/src/components/ui/input-otp.tsx +20 -0
- package/template/apps/asas-tanstack/src/components/ui/input.tsx +20 -0
- package/template/apps/asas-tanstack/src/components/ui/label.tsx +18 -0
- package/template/apps/asas-tanstack/src/components/ui/popover.tsx +50 -0
- package/template/apps/asas-tanstack/src/components/ui/radio-group.tsx +10 -0
- package/template/apps/asas-tanstack/src/components/ui/resizable.tsx +47 -0
- package/template/apps/asas-tanstack/src/components/ui/scroll-area.tsx +52 -0
- package/template/apps/asas-tanstack/src/components/ui/select.tsx +190 -0
- package/template/apps/asas-tanstack/src/components/ui/separator.tsx +23 -0
- package/template/apps/asas-tanstack/src/components/ui/sheet.tsx +127 -0
- package/template/apps/asas-tanstack/src/components/ui/sidebar.tsx +716 -0
- package/template/apps/asas-tanstack/src/components/ui/skeleton.tsx +13 -0
- package/template/apps/asas-tanstack/src/components/ui/slider.tsx +13 -0
- package/template/apps/asas-tanstack/src/components/ui/spinner.tsx +11 -0
- package/template/apps/asas-tanstack/src/components/ui/switch.tsx +8 -0
- package/template/apps/asas-tanstack/src/components/ui/table.tsx +119 -0
- package/template/apps/asas-tanstack/src/components/ui/tabs.tsx +80 -0
- package/template/apps/asas-tanstack/src/components/ui/textarea.tsx +18 -0
- package/template/apps/asas-tanstack/src/components/ui/toggle-group.tsx +8 -0
- package/template/apps/asas-tanstack/src/components/ui/toggle.tsx +44 -0
- package/template/apps/asas-tanstack/src/components/ui/tooltip.tsx +68 -0
- package/template/apps/asas-tanstack/src/copy.ts +870 -0
- package/template/apps/asas-tanstack/src/hooks/use-mobile.ts +19 -0
- package/template/apps/asas-tanstack/src/lib/utils.ts +6 -0
- package/template/apps/asas-tanstack/src/links.ts +38 -0
- package/template/apps/asas-tanstack/src/locale-switch.tsx +26 -0
- package/template/apps/asas-tanstack/src/quiet-abort.ts +25 -0
- package/template/apps/asas-tanstack/src/redirect.ts +20 -0
- package/template/apps/asas-tanstack/src/request-headers.ts +11 -0
- package/template/apps/asas-tanstack/src/routeTree.gen.ts +382 -0
- package/template/apps/asas-tanstack/src/router.tsx +7 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/files.ts +4 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/screen.json +3883 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/types.ts +158 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard.$.tsx +17 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard.index.tsx +10 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard.tsx +13 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/files.ts +4 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/screen.json +1800 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/types.ts +92 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal.$.tsx +17 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal.index.tsx +10 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal.tsx +13 -0
- package/template/apps/asas-tanstack/src/routes/__root.tsx +99 -0
- package/template/apps/asas-tanstack/src/routes/api/$.ts +11 -0
- package/template/apps/asas-tanstack/src/routes/auth.accept-invitation.tsx +101 -0
- package/template/apps/asas-tanstack/src/routes/auth.forgot-password.tsx +94 -0
- package/template/apps/asas-tanstack/src/routes/auth.handoff.ts +39 -0
- package/template/apps/asas-tanstack/src/routes/auth.reset-password.tsx +109 -0
- package/template/apps/asas-tanstack/src/routes/auth.sign-in.tsx +86 -0
- package/template/apps/asas-tanstack/src/routes/auth.sign-up.tsx +122 -0
- package/template/apps/asas-tanstack/src/routes/index.tsx +142 -0
- package/template/apps/asas-tanstack/src/routes/unauthorized.tsx +122 -0
- package/template/apps/asas-tanstack/src/screen-form.tsx +34 -0
- package/template/apps/asas-tanstack/src/screen-list.tsx +139 -0
- package/template/apps/asas-tanstack/src/screen-names.ts +10 -0
- package/template/apps/asas-tanstack/src/screens.tsx +868 -0
- package/template/apps/asas-tanstack/src/server.ts +16 -0
- package/template/apps/asas-tanstack/src/slide.ts +22 -0
- package/template/apps/asas-tanstack/src/start.ts +57 -0
- package/template/apps/asas-tanstack/src/styles.css +159 -0
- package/template/apps/asas-tanstack/src/theme.ts +5 -0
- package/template/apps/asas-tanstack/tsconfig.json +19 -0
- package/template/apps/asas-tanstack/vite.config.ts +28 -0
- package/template/package.json +16 -0
- package/template/templates/asas/.env.example +16 -0
- package/template/templates/asas/components.json +22 -0
- package/template/templates/asas/mithaq.hints.json +25 -0
- package/template/templates/asas/package.json +38 -0
- package/template/templates/asas/src/asas.ts +93 -0
- package/template/templates/asas/src/audit-log/audit-log.ts +187 -0
- package/template/templates/asas/src/audit-log/sink.ts +89 -0
- package/template/templates/asas/src/audit-log/ui/activity.tsx +243 -0
- package/template/templates/asas/src/courses/courses.ts +612 -0
- package/template/templates/asas/src/courses/ui/archive-button.tsx +25 -0
- package/template/templates/asas/src/courses/ui/fee-cell.tsx +19 -0
- package/template/templates/asas/src/courses/ui/no-courses-on-offer.tsx +11 -0
- package/template/templates/asas/src/courses/ui/no-courses.tsx +13 -0
- package/template/templates/asas/src/courses/ui/on-offer.ts +6 -0
- package/template/templates/asas/src/courses/ui/status-cell.tsx +31 -0
- package/template/templates/asas/src/enrollments/enrollments.ts +137 -0
- package/template/templates/asas/src/enrollments/ui/session-cell.tsx +65 -0
- package/template/templates/asas/src/kayan/auth/user/account.access.ts +8 -0
- package/template/templates/asas/src/kayan/auth/user/account.ts +31 -0
- package/template/templates/asas/src/kayan/auth/user/index.ts +18 -0
- package/template/templates/asas/src/kayan/auth/user/invitation.access.ts +4 -0
- package/template/templates/asas/src/kayan/auth/user/invitation.ts +27 -0
- package/template/templates/asas/src/kayan/auth/user/member.access.ts +10 -0
- package/template/templates/asas/src/kayan/auth/user/member.screens.ts +37 -0
- package/template/templates/asas/src/kayan/auth/user/member.ts +25 -0
- package/template/templates/asas/src/kayan/auth/user/organization.access.ts +20 -0
- package/template/templates/asas/src/kayan/auth/user/organization.screens.ts +37 -0
- package/template/templates/asas/src/kayan/auth/user/organization.ts +24 -0
- package/template/templates/asas/src/kayan/auth/user/organizationRole.access.ts +8 -0
- package/template/templates/asas/src/kayan/auth/user/organizationRole.ts +25 -0
- package/template/templates/asas/src/kayan/auth/user/session.access.ts +8 -0
- package/template/templates/asas/src/kayan/auth/user/session.ts +28 -0
- package/template/templates/asas/src/kayan/auth/user/user.access.ts +29 -0
- package/template/templates/asas/src/kayan/auth/user/user.screens.ts +45 -0
- package/template/templates/asas/src/kayan/auth/user/user.ts +31 -0
- package/template/templates/asas/src/kayan/auth/user/verification.access.ts +8 -0
- package/template/templates/asas/src/kayan/auth/user/verification.ts +23 -0
- package/template/templates/asas/src/local-users/local-users.ts +143 -0
- package/template/templates/asas/src/media/media.ts +137 -0
- package/template/templates/asas/src/media/ui/preview.tsx +143 -0
- package/template/templates/asas/src/member-roles/member-roles.ts +207 -0
- package/template/templates/asas/src/messages/account.json +106 -0
- package/template/templates/asas/src/messages/auditLog.json +186 -0
- package/template/templates/asas/src/messages/courses.json +270 -0
- package/template/templates/asas/src/messages/enrollments.json +42 -0
- package/template/templates/asas/src/messages/invitation.json +66 -0
- package/template/templates/asas/src/messages/localUsers.json +42 -0
- package/template/templates/asas/src/messages/media.json +66 -0
- package/template/templates/asas/src/messages/member.json +42 -0
- package/template/templates/asas/src/messages/memberRoles.json +42 -0
- package/template/templates/asas/src/messages/mithaq.json +170 -0
- package/template/templates/asas/src/messages/organization.json +50 -0
- package/template/templates/asas/src/messages/organizationRole.json +50 -0
- package/template/templates/asas/src/messages/roles.json +58 -0
- package/template/templates/asas/src/messages/session.json +82 -0
- package/template/templates/asas/src/messages/sessions.json +106 -0
- package/template/templates/asas/src/messages/settings.json +66 -0
- package/template/templates/asas/src/messages/tags.json +38 -0
- package/template/templates/asas/src/messages/user.json +90 -0
- package/template/templates/asas/src/messages/verification.json +50 -0
- package/template/templates/asas/src/migrations/20260920080701_parched_tombstone/migration.sql +177 -0
- package/template/templates/asas/src/migrations/20260920080701_parched_tombstone/snapshot.json +2169 -0
- package/template/templates/asas/src/migrations/20260920230505_zippy_ben_urich/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20260920230505_zippy_ben_urich/snapshot.json +2182 -0
- package/template/templates/asas/src/migrations/20260920231219_slim_retro_girl/migration.sql +20 -0
- package/template/templates/asas/src/migrations/20260920231219_slim_retro_girl/snapshot.json +2409 -0
- package/template/templates/asas/src/migrations/20260922082945_military_ironclad/migration.sql +15 -0
- package/template/templates/asas/src/migrations/20260922082945_military_ironclad/snapshot.json +2627 -0
- package/template/templates/asas/src/migrations/20260922112630_bitter_chat/migration.sql +5 -0
- package/template/templates/asas/src/migrations/20260922112630_bitter_chat/snapshot.json +2691 -0
- package/template/templates/asas/src/migrations/20260923235915_foamy_rachel_grey/migration.sql +8 -0
- package/template/templates/asas/src/migrations/20260923235915_foamy_rachel_grey/snapshot.json +2795 -0
- package/template/templates/asas/src/migrations/20260926145709_clean_the_initiative/migration.sql +3 -0
- package/template/templates/asas/src/migrations/20260926145709_clean_the_initiative/snapshot.json +2834 -0
- package/template/templates/asas/src/migrations/20260927212525_bent_prowler/migration.sql +9 -0
- package/template/templates/asas/src/migrations/20260927212525_bent_prowler/snapshot.json +2870 -0
- package/template/templates/asas/src/migrations/20260927223441_tranquil_bromley/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20260927223441_tranquil_bromley/snapshot.json +2881 -0
- package/template/templates/asas/src/migrations/20260928030047_outgoing_wraith/migration.sql +15 -0
- package/template/templates/asas/src/migrations/20260928030047_outgoing_wraith/snapshot.json +3073 -0
- package/template/templates/asas/src/migrations/20260929024407_grey_morlun/migration.sql +21 -0
- package/template/templates/asas/src/migrations/20260929024407_grey_morlun/snapshot.json +3098 -0
- package/template/templates/asas/src/migrations/20260929130530_bored_jackal/migration.sql +21 -0
- package/template/templates/asas/src/migrations/20260929130530_bored_jackal/snapshot.json +3124 -0
- package/template/templates/asas/src/migrations/20260930102924_material_newton_destine/migration.sql +32 -0
- package/template/templates/asas/src/migrations/20260930102924_material_newton_destine/snapshot.json +3324 -0
- package/template/templates/asas/src/migrations/20261003022353_clumsy_taskmaster/migration.sql +2 -0
- package/template/templates/asas/src/migrations/20261003022353_clumsy_taskmaster/snapshot.json +3350 -0
- package/template/templates/asas/src/migrations/20261003143249_premium_red_shift/migration.sql +21 -0
- package/template/templates/asas/src/migrations/20261003143249_premium_red_shift/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261008215349_square_norrin_radd/migration.sql +8 -0
- package/template/templates/asas/src/migrations/20261008215349_square_norrin_radd/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261008230204_many_scarecrow/migration.sql +18 -0
- package/template/templates/asas/src/migrations/20261008230204_many_scarecrow/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261010005521_elite_giant_girl/migration.sql +18 -0
- package/template/templates/asas/src/migrations/20261010005521_elite_giant_girl/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261010120822_needy_thunderbolt/migration.sql +11 -0
- package/template/templates/asas/src/migrations/20261010120822_needy_thunderbolt/snapshot.json +3667 -0
- package/template/templates/asas/src/migrations/20261012000752_organization_ownership/migration.sql +48 -0
- package/template/templates/asas/src/migrations/20261012000752_organization_ownership/snapshot.json +3891 -0
- package/template/templates/asas/src/migrations/drizzle.config.ts +11 -0
- package/template/templates/asas/src/migrations/schema.ts +29 -0
- package/template/templates/asas/src/mithaq.ts +406 -0
- package/template/templates/asas/src/pages.ts +74 -0
- package/template/templates/asas/src/platform-http.ts +96 -0
- package/template/templates/asas/src/rich-text-nodes.ts +11 -0
- package/template/templates/asas/src/roles/grants.ts +47 -0
- package/template/templates/asas/src/roles/roles.ts +184 -0
- package/template/templates/asas/src/roles/ui/role-form.tsx +226 -0
- package/template/templates/asas/src/roles/ui/roles.tsx +166 -0
- package/template/templates/asas/src/roles.ts +16 -0
- package/template/templates/asas/src/seed.ts +325 -0
- package/template/templates/asas/src/sessions/sessions.ts +155 -0
- package/template/templates/asas/src/settings/settings.ts +69 -0
- package/template/templates/asas/src/statements.ts +11 -0
- package/template/templates/asas/src/steps/expected-updated-at.ts +41 -0
- package/template/templates/asas/src/storage/defaults.ts +156 -0
- package/template/templates/asas/src/storage/index.ts +95 -0
- package/template/templates/asas/src/storage/local.ts +143 -0
- package/template/templates/asas/src/storage/r2.ts +5 -0
- package/template/templates/asas/src/storage/s3.ts +91 -0
- package/template/templates/asas/src/storage/uploadthing.ts +59 -0
- package/template/templates/asas/src/tags/tags.ts +80 -0
- package/template/templates/asas/src/tenant-access.ts +221 -0
- package/template/templates/asas/src/tenant-roles.ts +262 -0
- package/template/templates/asas/src/ui/app-shell.tsx +260 -0
- package/template/templates/asas/src/ui/kpi-card.tsx +25 -0
- package/template/templates/asas/src/ui/record-page.tsx +50 -0
- package/template/templates/asas/src/ui/rich-text-nodes.tsx +15 -0
- package/template/templates/asas/src/ui/screen-nav.tsx +28 -0
- package/template/templates/asas/src/ui/session-labels.tsx +36 -0
- package/template/templates/asas/src/ui/table-page.tsx +9 -0
- package/template/templates/asas/src/ui/top-shell.tsx +60 -0
- package/template/templates/asas/src/ui-dashboard/dashboard.tsx +294 -0
- package/template/templates/asas/src/ui-dashboard/members.tsx +630 -0
- package/template/templates/asas/src/ui-dashboard/theme-provider.tsx +10 -0
- package/template/templates/asas/src/ui-dashboard/versions.tsx +432 -0
- package/template/templates/asas/src/ui-platform/home.tsx +63 -0
- package/template/templates/asas/src/ui-platform/organization-actions.tsx +114 -0
- package/template/templates/asas/src/ui-platform/record-page.tsx +30 -0
- package/template/templates/asas/src/ui-platform/role-cells.tsx +52 -0
- package/template/templates/asas/src/ui-platform/user-actions.tsx +251 -0
- package/template/templates/asas/src/ui-portal/home.tsx +77 -0
- package/template/templates/asas/src/ui-portal/page.tsx +11 -0
- package/template/templates/auth/package.json +14 -0
- package/template/templates/auth/src/index.ts +690 -0
- package/template/templates/auth/src/platform-roles.ts +87 -0
- package/README.md +0 -3
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { useState, type ComponentProps, type ReactNode } from 'react'
|
|
2
|
+
import { redirect, useRouteContext } from '@tanstack/react-router'
|
|
3
|
+
import { createServerFn } from '@tanstack/react-start'
|
|
4
|
+
import { Eye, EyeOff } from 'lucide-react'
|
|
5
|
+
import { Button } from '@/components/ui/button'
|
|
6
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
7
|
+
import { Input } from '@/components/ui/input'
|
|
8
|
+
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'
|
|
9
|
+
import { authArm } from './api.ts'
|
|
10
|
+
import { FieldShell, describedBy } from './components/mithaq/field-shell.tsx'
|
|
11
|
+
import { refusalKey } from './copy.ts'
|
|
12
|
+
import { LocaleSwitch } from './locale-switch.tsx'
|
|
13
|
+
import { wanted } from './redirect.ts'
|
|
14
|
+
import { useCopy } from './routes/__root.tsx'
|
|
15
|
+
|
|
16
|
+
/** The one search key the auth pages read, off the raw search. */
|
|
17
|
+
export const redirectSearch = (search: Record<string, unknown>): { redirect?: string } =>
|
|
18
|
+
typeof search.redirect === 'string' ? { redirect: search.redirect } : {}
|
|
19
|
+
|
|
20
|
+
/** Whether a read of the actor names someone. A read that throws, or an actor with no email, names no one. */
|
|
21
|
+
export const signedInAs = async (actor: Promise<unknown>) => Boolean(((await actor.catch(() => null)) as { email?: unknown } | null)?.email)
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Whether this request carries a session, where signing in lands for it, and the provider's password bounds.
|
|
25
|
+
* No auth page sends a referrer, since the reset page's address carries its token.
|
|
26
|
+
*/
|
|
27
|
+
export const authGate = createServerFn({ method: 'GET' }).handler(async () => {
|
|
28
|
+
// Imported inside the server half so no auth page ships the screen host to the browser.
|
|
29
|
+
const [{ getRequest, setResponseHeader }, { asas }, { loadEnterable }] = await Promise.all([import('@tanstack/react-start/server'), import('asas'), import('./screens.tsx')])
|
|
30
|
+
setResponseHeader('referrer-policy', 'no-referrer')
|
|
31
|
+
type Provider = { name: string; server: { $context: Promise<{ password: { config: { minPasswordLength: number; maxPasswordLength: number } } }> } }
|
|
32
|
+
const provider = (asas.auth.strategies as unknown as Provider[]).find((one) => one.name === 'user')!
|
|
33
|
+
const [signedIn, { password }] = await Promise.all([signedInAs(asas.auth.actor(getRequest().headers)), provider.server.$context])
|
|
34
|
+
const first = signedIn ? (await loadEnterable())?.screens[0] : undefined
|
|
35
|
+
const home: { path: string; name?: string } = first ?? { path: '/unauthorized' }
|
|
36
|
+
return { signedIn, home, password: { min: password.config.minPasswordLength, max: password.config.maxPasswordLength } }
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Sign-in's and sign-up's `beforeLoad`. A signed-in person is sent where a
|
|
41
|
+
* successful sign-in sends them; everyone else gets the password bounds in the
|
|
42
|
+
* route context.
|
|
43
|
+
*/
|
|
44
|
+
export const gate = async ({ search }: { search: { redirect?: string } }) => {
|
|
45
|
+
const { signedIn, home, password } = await authGate()
|
|
46
|
+
if (signedIn) throw redirect({ href: wanted({ asked: search.redirect, home: home.path }) })
|
|
47
|
+
return { password }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** What a link to `home` says: the screen it opens, or, where it opens none, the action of seeing the account's status. */
|
|
51
|
+
export const useHomeLabel = () => {
|
|
52
|
+
const { t } = useCopy()
|
|
53
|
+
return (home: { name?: string }, sentence: 'auth.backTo' | 'marketing.openScreen') =>
|
|
54
|
+
home.name === undefined
|
|
55
|
+
? t('auth.accountStatus', 'See your account status')
|
|
56
|
+
: t(sentence, sentence === 'auth.backTo' ? 'Back to {screen}' : 'Open {screen}')!.replace('{screen}', () => t(`screens.${home.name}`, home.name)!)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** What the forgot and reset pages draw for someone already signed in: the way on, and a sign-out. */
|
|
60
|
+
export function AlreadySignedIn({ redirect: asked, home }: { redirect?: string; home: { path: string; name?: string } }) {
|
|
61
|
+
const { t } = useCopy()
|
|
62
|
+
const label = useHomeLabel()
|
|
63
|
+
const to = wanted({ asked, home: home.path })
|
|
64
|
+
return (
|
|
65
|
+
<AuthFrame title={t('auth.alreadySignedIn', 'You are already signed in')}>
|
|
66
|
+
<div className="grid gap-4">
|
|
67
|
+
{/* An anchor: the path is the visitor's own, not a route the router knows. */}
|
|
68
|
+
<a className="text-primary text-center text-sm underline underline-offset-4" href={to}>
|
|
69
|
+
{to === home.path ? label(home, 'auth.backTo') : t('auth.continue', 'Continue')}
|
|
70
|
+
</a>
|
|
71
|
+
<Button type="button" variant="outline" onClick={() => void authArm('sign-out').then(() => window.location.reload())}>
|
|
72
|
+
{t('admin.signOut', 'Sign out')}
|
|
73
|
+
</Button>
|
|
74
|
+
</div>
|
|
75
|
+
</AuthFrame>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The sentence for a refusal of the provider: this app's own words for the status or code, then `fallback`. Never the provider's `message`, which is English in any locale. */
|
|
80
|
+
export const useRefusal = () => {
|
|
81
|
+
const { t } = useCopy()
|
|
82
|
+
return (answered: { status: number; body: Record<string, unknown> | null }, fallback: string | undefined) => {
|
|
83
|
+
const key = refusalKey(answered.status, answered.body?.code)
|
|
84
|
+
return (key && t(key)) || fallback || ''
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Whether the browser's own `type="email"` refuses this text. */
|
|
89
|
+
export const notAnEmail = (value: string) => Object.assign(document.createElement('input'), { type: 'email', value }).validity.typeMismatch
|
|
90
|
+
|
|
91
|
+
/** The frame every auth page is drawn in: the app's name linking home, the language switch, and the page's card. */
|
|
92
|
+
export function AuthFrame({ title, description, children }: { title: string | undefined; description?: ReactNode; children: ReactNode }) {
|
|
93
|
+
const { t, locale } = useCopy()
|
|
94
|
+
const { app } = useRouteContext({ from: '__root__' })
|
|
95
|
+
return (
|
|
96
|
+
<div className="flex min-h-screen flex-col">
|
|
97
|
+
<header className="mx-auto flex h-16 w-full max-w-6xl items-center justify-between gap-2 px-4 sm:px-6">
|
|
98
|
+
{/* An anchor: `/` is not a router route in an app whose start entry answers its home. */}
|
|
99
|
+
<a className="text-lg font-semibold" href="/">
|
|
100
|
+
{t(app, 'Asas')}
|
|
101
|
+
</a>
|
|
102
|
+
<LocaleSwitch locale={locale} />
|
|
103
|
+
</header>
|
|
104
|
+
<main className="flex flex-1 items-center justify-center px-4 pb-16">
|
|
105
|
+
<Card className="w-full max-w-sm">
|
|
106
|
+
<CardHeader>
|
|
107
|
+
<CardTitle><h1>{title}</h1></CardTitle>
|
|
108
|
+
{description ? <CardDescription>{description}</CardDescription> : null}
|
|
109
|
+
</CardHeader>
|
|
110
|
+
{/* Descriptions follow the text direction; the shared primitive aligns them left. */}
|
|
111
|
+
<CardContent className="[&_[data-slot=field-description]]:text-start">{children}</CardContent>
|
|
112
|
+
</Card>
|
|
113
|
+
</main>
|
|
114
|
+
</div>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function PasswordInput(props: ComponentProps<'input'>) {
|
|
119
|
+
const { t } = useCopy()
|
|
120
|
+
const [shown, setShown] = useState(false)
|
|
121
|
+
return (
|
|
122
|
+
// Focus moving to the box's own toggle has not left the box.
|
|
123
|
+
<InputGroup onBlur={(event) => event.currentTarget.contains(event.relatedTarget) && event.stopPropagation()}>
|
|
124
|
+
<InputGroupInput {...props} dir="ltr" type={shown ? 'text' : 'password'} />
|
|
125
|
+
<InputGroupAddon align="inline-end">
|
|
126
|
+
<InputGroupButton aria-label={t('auth.showPassword', 'Show password')} aria-pressed={shown} size="icon-xs" onClick={() => setShown((was) => !was)}>
|
|
127
|
+
{shown ? <EyeOff /> : <Eye />}
|
|
128
|
+
</InputGroupButton>
|
|
129
|
+
</InputGroupAddon>
|
|
130
|
+
</InputGroup>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** One labelled box, which says what is wrong with it once it has been left. An email or password reads left to right in any locale. */
|
|
135
|
+
export function AuthBox({
|
|
136
|
+
id,
|
|
137
|
+
label,
|
|
138
|
+
error,
|
|
139
|
+
description,
|
|
140
|
+
onLeave,
|
|
141
|
+
...props
|
|
142
|
+
}: { id: string; label: string | undefined; error?: string; description?: string; onLeave: () => void } & ComponentProps<'input'>) {
|
|
143
|
+
const control = { 'aria-describedby': describedBy({ id, description, error }), 'aria-invalid': error ? true : undefined, id, name: id, required: true, ...props }
|
|
144
|
+
return (
|
|
145
|
+
<FieldShell id={id} label={label ?? id} description={description} error={error} onBlur={onLeave}>
|
|
146
|
+
{props.type === 'password' ? <PasswordInput {...control} /> : <Input dir={props.type === 'email' ? 'ltr' : 'auto'} {...control} />}
|
|
147
|
+
</FieldShell>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
// mithaq-admin b06d8d335d306c07556f8f2b81fba20ba7ded198 ab822afe361dfc5f82c504570fd5d0ea13ec4572e60adb679a3f9532ccf67803
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { useSyncExternalStore, type ReactNode } from 'react'
|
|
2
|
+
import type { ClientField, ClientKayan } from 'mithaq/admin'
|
|
3
|
+
import { formatDate, listed, noValue, type Translate } from './controls.tsx'
|
|
4
|
+
import { RelationshipCell, type RelationshipTitles } from './relationship-cell.tsx'
|
|
5
|
+
import { UploadCell } from './upload.tsx'
|
|
6
|
+
|
|
7
|
+
// The server does not know the viewer's zone, so it and the hydrating render draw the day in UTC
|
|
8
|
+
// and the mounted client swaps in the moment; drawing both in a zone would be a hydration mismatch.
|
|
9
|
+
function Moment({ value, locale }: { value: unknown; locale: string }): ReactNode {
|
|
10
|
+
const mounted = useSyncExternalStore(() => () => {}, () => true, () => false)
|
|
11
|
+
const text = formatDate({ value, locale, day: !mounted })
|
|
12
|
+
return text === undefined ? plain(value) : <time dateTime={new Date(value as string).toISOString()} suppressHydrationWarning>{text}</time>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** What every cell is handed. The locale is the browser's; `t` is here because a cell that renders a word rather than the value is rendering the project's copy. */
|
|
16
|
+
export type CellProps = {
|
|
17
|
+
kayan: ClientKayan
|
|
18
|
+
field: ClientField
|
|
19
|
+
value: unknown
|
|
20
|
+
t: Translate
|
|
21
|
+
locale: string
|
|
22
|
+
/**
|
|
23
|
+
* The titles of the rows the relationship columns point at, read once per page. Absent on a
|
|
24
|
+
* server render, where every relationship cell reads as loading; no cell shows the id it holds.
|
|
25
|
+
*/
|
|
26
|
+
titles?: RelationshipTitles
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const plain = (value: unknown) => (value === null || value === undefined ? '' : String(value))
|
|
30
|
+
|
|
31
|
+
const worded = (field: ClientField, value: unknown, locale: string) => {
|
|
32
|
+
const held = field.rules.localized === true && value && typeof value === 'object' ? (value as Record<string, unknown>)[locale] : value
|
|
33
|
+
return field.options?.find((one) => one.value === held)?.label[locale] ?? plain(held)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The text a reader sees in a rich text value, a block to a line. Lives here, not beside the editor, so lists read it without loading Lexical. */
|
|
37
|
+
export const richTextPlainText = (node: unknown, depth = 64): string => {
|
|
38
|
+
// A stored value nested past the bound ends in an ellipsis rather than overflowing the stack.
|
|
39
|
+
if (depth <= 0) return '…'
|
|
40
|
+
if (!node || typeof node !== 'object') return ''
|
|
41
|
+
const held = node as { root?: unknown; type?: unknown; text?: unknown; children?: unknown }
|
|
42
|
+
if (held.root) return richTextPlainText(held.root, depth - 1)
|
|
43
|
+
if (held.type === 'linebreak') return '\n'
|
|
44
|
+
const children: unknown[] = Array.isArray(held.children) ? held.children : []
|
|
45
|
+
const inner = children.map((child) => richTextPlainText(child, depth - 1)).join(children.some((child) => typeof (child as { text?: unknown } | null)?.text === 'string') ? '' : '\n')
|
|
46
|
+
return (typeof held.text === 'string' ? held.text : '') + inner
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The blocks of a rich text value: its root's children, or the value itself where it holds none. */
|
|
50
|
+
export const blocksOf = (value: unknown): unknown[] => {
|
|
51
|
+
const root = (value as { root?: unknown } | null)?.root ?? value
|
|
52
|
+
return Array.isArray((root as { children?: unknown } | null)?.children) ? (root as { children: unknown[] }).children : [root]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const lineLength = 120
|
|
56
|
+
|
|
57
|
+
/** The words of a rich text value's first non-empty block on one line, cut at 120 characters with an ellipsis. */
|
|
58
|
+
export const richTextLine = (value: unknown): string => {
|
|
59
|
+
const first = blocksOf(value).map((block) => richTextPlainText(block).replace(/\s+/g, ' ').trim()).find(Boolean) ?? ''
|
|
60
|
+
const characters = Array.from(first)
|
|
61
|
+
return characters.length > lineLength ? `${characters.slice(0, lineLength).join('').trimEnd()}…` : characters.join('')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** One cell per shipped kind, keyed by the kind's own name. */
|
|
65
|
+
export const cells: Record<string, (props: CellProps) => ReactNode> = {
|
|
66
|
+
text: ({ field, value, locale }) => worded(field, value, locale),
|
|
67
|
+
email: ({ value }) =>
|
|
68
|
+
value ? (
|
|
69
|
+
<a href={`mailto:${String(value)}`} className="underline underline-offset-2">
|
|
70
|
+
{String(value)}
|
|
71
|
+
</a>
|
|
72
|
+
) : (
|
|
73
|
+
''
|
|
74
|
+
),
|
|
75
|
+
number: ({ value, locale }) => (typeof value === 'number' ? value.toLocaleString(locale) : plain(value)),
|
|
76
|
+
integer: (props) => cells.number!(props),
|
|
77
|
+
// Exact text: a JS double would lose digits.
|
|
78
|
+
decimal: ({ field, value, locale }) => worded(field, value, locale),
|
|
79
|
+
// The glyph is aria-hidden, so the sr-only word is what a screen reader gets. The words are keyed per field because `true` means different things on `archived` and `published`.
|
|
80
|
+
checkbox: ({ kayan, field, value, t }) => (
|
|
81
|
+
<>
|
|
82
|
+
<span aria-hidden className="tabular-nums">
|
|
83
|
+
{value === true ? '✓' : value === false ? '✗' : '—'}
|
|
84
|
+
</span>
|
|
85
|
+
<span className="sr-only">
|
|
86
|
+
{value === true
|
|
87
|
+
? (t(`${kayan.name}.${field.name}.true`) ?? t('admin.yes', 'Yes') ?? 'Yes')
|
|
88
|
+
: (t(`${kayan.name}.${field.name}.false`) ?? t('admin.no', 'No') ?? 'No')}
|
|
89
|
+
</span>
|
|
90
|
+
</>
|
|
91
|
+
),
|
|
92
|
+
datetime: ({ value, locale }) => <Moment value={value} locale={locale} />,
|
|
93
|
+
date: ({ value, locale }) => formatDate({ value, locale, day: true }) ?? plain(value),
|
|
94
|
+
textArray: ({ field, value, locale }) => (Array.isArray(value) ? listed(value.map((one) => worded(field, one, locale)), locale) : plain(value)),
|
|
95
|
+
uuid: ({ value }) => <span className="font-mono text-xs">{plain(value)}</span>,
|
|
96
|
+
relationship: RelationshipCell,
|
|
97
|
+
upload: UploadCell,
|
|
98
|
+
// Nothing where the read carried no join: an absent key means the read did not ask, an empty array means no children, and a count of zero would say both.
|
|
99
|
+
join: ({ value, locale }) => (Array.isArray(value) ? value.length.toLocaleString(locale) : ''),
|
|
100
|
+
// min-w-48 keeps a phone-width table from squeezing the words to one per line.
|
|
101
|
+
richText: ({ value }) => {
|
|
102
|
+
const line = richTextLine(value)
|
|
103
|
+
return line ? <span dir="auto" className="line-clamp-2 min-w-48 whitespace-normal">{line}</span> : noValue
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
// No prototype, so a kind named `constructor` never resolves to an inherited property.
|
|
107
|
+
Object.setPrototypeOf(cells, null)
|
|
108
|
+
|
|
109
|
+
/** The cell for a field, first match wins: the list column's named cell, the field's own cell, the kind's cell, then plain text. */
|
|
110
|
+
export const cellFor = (field: ClientField, column?: string): ((props: CellProps) => ReactNode) =>
|
|
111
|
+
cells[column ?? ''] ?? cells[field.cell] ?? cells[field.kind] ?? cells.text!
|
|
112
|
+
// mithaq-admin b06d8d335d306c07556f8f2b81fba20ba7ded198 95340e7fd65595abe95ca51f11ac4b6f98a69775637a46591d6aa053f6aa5f27
|