feat: Domain-based routing — marketing site at bare domain, panel at subdomain
corrosionmgmt.com now serves LandingView as the default page with marketing routes at root level. panel.corrosionmgmt.com continues serving the admin panel unchanged. /site/* backward compat via redirects on marketing domain. - nginx: Add bare domain server block (only proxies /api/early-access/) - router: Detect hostname at module load, generate domain-specific routes - MarketingLayout: Named routes for nav, external <a> tags for auth links - LandingView: CTAs point to panel domain via VITE_PANEL_URL Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,53 @@
|
||||
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
// ---------------------------------------------------------------------------
|
||||
// Domain detection — runs once at module load
|
||||
// ---------------------------------------------------------------------------
|
||||
const hostname = typeof window !== 'undefined' ? window.location.hostname : ''
|
||||
const isMarketingDomain = hostname === 'corrosionmgmt.com'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Marketing page children — shared between both domain route sets
|
||||
// ---------------------------------------------------------------------------
|
||||
const marketingChildren: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '',
|
||||
name: 'landing',
|
||||
component: () => import('@/views/marketing/LandingView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'pricing',
|
||||
name: 'pricing',
|
||||
component: () => import('@/views/marketing/PricingView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'how-it-works',
|
||||
name: 'how-it-works',
|
||||
component: () => import('@/views/marketing/HowItWorksView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'faq',
|
||||
name: 'faq',
|
||||
component: () => import('@/views/marketing/FaqView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'roadmap',
|
||||
name: 'roadmap',
|
||||
component: () => import('@/views/marketing/RoadmapView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'early-access',
|
||||
name: 'early-access',
|
||||
component: () => import('@/views/marketing/EarlyAccessView.vue'),
|
||||
},
|
||||
]
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Panel domain routes — panel.corrosionmgmt.com, localhost, etc.
|
||||
// Existing behavior, unchanged.
|
||||
// ---------------------------------------------------------------------------
|
||||
const panelRoutes: RouteRecordRaw[] = [
|
||||
// Auth routes (no layout)
|
||||
{
|
||||
path: '/login',
|
||||
@@ -113,7 +159,7 @@ const routes: RouteRecordRaw[] = [
|
||||
name: 'settings',
|
||||
component: () => import('@/views/admin/SettingsView.vue'),
|
||||
},
|
||||
// Platform Admin views (super-admin only, guarded in components)
|
||||
// Platform Admin views (super-admin only)
|
||||
{
|
||||
path: 'admin',
|
||||
name: 'platform-admin',
|
||||
@@ -165,42 +211,11 @@ const routes: RouteRecordRaw[] = [
|
||||
],
|
||||
},
|
||||
|
||||
// Marketing site (public, no auth)
|
||||
// Marketing site (accessible on panel domain at /site/*)
|
||||
{
|
||||
path: '/site',
|
||||
component: () => import('@/components/layout/MarketingLayout.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'landing',
|
||||
component: () => import('@/views/marketing/LandingView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'pricing',
|
||||
name: 'pricing',
|
||||
component: () => import('@/views/marketing/PricingView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'how-it-works',
|
||||
name: 'how-it-works',
|
||||
component: () => import('@/views/marketing/HowItWorksView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'faq',
|
||||
name: 'faq',
|
||||
component: () => import('@/views/marketing/FaqView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'roadmap',
|
||||
name: 'roadmap',
|
||||
component: () => import('@/views/marketing/RoadmapView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'early-access',
|
||||
name: 'early-access',
|
||||
component: () => import('@/views/marketing/EarlyAccessView.vue'),
|
||||
},
|
||||
],
|
||||
children: marketingChildren,
|
||||
},
|
||||
|
||||
// Status page
|
||||
@@ -211,12 +226,52 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
]
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Marketing domain routes — corrosionmgmt.com (bare domain)
|
||||
// Marketing pages at root. No admin/auth routes.
|
||||
// ---------------------------------------------------------------------------
|
||||
const marketingRoutes: RouteRecordRaw[] = [
|
||||
// Marketing layout at /
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('@/components/layout/MarketingLayout.vue'),
|
||||
children: marketingChildren,
|
||||
},
|
||||
|
||||
// Backward compat: /site/* → root-level equivalents
|
||||
{
|
||||
path: '/site/:pathMatch(.*)*',
|
||||
redirect: (to) => {
|
||||
const sub = to.params.pathMatch
|
||||
if (!sub || (Array.isArray(sub) && sub.length === 0)) return '/'
|
||||
const subPath = Array.isArray(sub) ? sub.join('/') : sub
|
||||
return subPath ? `/${subPath}` : '/'
|
||||
},
|
||||
},
|
||||
|
||||
// Status page
|
||||
{
|
||||
path: '/status',
|
||||
name: 'status',
|
||||
component: () => import('@/views/public/StatusPageView.vue'),
|
||||
},
|
||||
|
||||
// Catch-all: unknown routes → landing page
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
redirect: '/',
|
||||
},
|
||||
]
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Router instance
|
||||
// ---------------------------------------------------------------------------
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
routes: isMarketingDomain ? marketingRoutes : panelRoutes,
|
||||
})
|
||||
|
||||
// Auth guard
|
||||
// Auth guard — only meaningful on panel domain (marketing has no requiresAuth routes)
|
||||
router.beforeEach((to, _from, next) => {
|
||||
const auth = useAuthStore()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user