forked from cardosofelipe/pragma-stack
feat: complete Syndarix rebranding from PragmaStack
- Update PROJECT_NAME to Syndarix in backend config - Update all frontend components with Syndarix branding - Replace all GitHub URLs with Gitea Syndarix repo URLs - Update metadata, headers, footers with new branding - Update tests to match new URLs - Update E2E tests for new repo references - Preserve "Built on PragmaStack" attribution in docs Closes #13 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# PragmaStack Backend API
|
# Syndarix Backend API
|
||||||
|
|
||||||
> The pragmatic, production-ready FastAPI backend for PragmaStack.
|
> The pragmatic, production-ready FastAPI backend for Syndarix.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from pydantic_settings import BaseSettings
|
|||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
PROJECT_NAME: str = "PragmaStack"
|
PROJECT_NAME: str = "Syndarix"
|
||||||
VERSION: str = "1.0.0"
|
VERSION: str = "1.0.0"
|
||||||
API_V1_STR: str = "/api/v1"
|
API_V1_STR: str = "/api/v1"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# PragmaStack - Frontend
|
# Syndarix - Frontend
|
||||||
|
|
||||||
Production-ready Next.js 16 frontend with TypeScript, authentication, admin panel, and internationalization.
|
Production-ready Next.js 16 frontend with TypeScript, authentication, admin panel, and internationalization.
|
||||||
|
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ NEXT_PUBLIC_DEMO_MODE=true npm run dev
|
|||||||
**1. Fork Repository**
|
**1. Fork Repository**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gh repo fork your-repo/fast-next-template
|
git clone https://gitea.pragmazest.com/cardosofelipe/syndarix.git
|
||||||
```
|
```
|
||||||
|
|
||||||
**2. Connect to Vercel**
|
**2. Connect to Vercel**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Internationalization (i18n) Guide
|
# Internationalization (i18n) Guide
|
||||||
|
|
||||||
This document describes the internationalization implementation in the PragmaStack.
|
This document describes the internationalization implementation in Syndarix.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
## Logo
|
## Logo
|
||||||
|
|
||||||
The **PragmaStack** logo represents the core values of the project: structure, speed, and clarity.
|
The **Syndarix** logo represents the core values of the project: structure, speed, and clarity.
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="../../public/logo.svg" alt="PragmaStack Logo" width="300" />
|
<img src="../../public/logo.svg" alt="Syndarix Logo" width="300" />
|
||||||
<p><em>The Stack: Geometric layers representing the full-stack architecture.</em></p>
|
<p><em>The Stack: Geometric layers representing the full-stack architecture.</em></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ The **PragmaStack** logo represents the core values of the project: structure, s
|
|||||||
For smaller contexts (favicons, headers), we use the simplified icon:
|
For smaller contexts (favicons, headers), we use the simplified icon:
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="../../public/logo-icon.svg" alt="PragmaStack Icon" width="64" />
|
<img src="../../public/logo-icon.svg" alt="Syndarix Icon" width="64" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
For now, we use the **Lucide React** icon set for all iconography. Icons should be used sparingly and meaningfully to enhance understanding, not just for decoration.
|
For now, we use the **Lucide React** icon set for all iconography. Icons should be used sparingly and meaningfully to enhance understanding, not just for decoration.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Branding Guidelines
|
# Branding Guidelines
|
||||||
|
|
||||||
Welcome to the **PragmaStack** branding guidelines. This section defines who we are, how we speak, and how we look.
|
Welcome to the **Syndarix** branding guidelines. This section defines who we are, how we speak, and how we look.
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Quick Start Guide
|
# Quick Start Guide
|
||||||
|
|
||||||
Get up and running with the PragmaStack design system immediately. This guide covers the essential patterns you need to build 80% of interfaces.
|
Get up and running with the Syndarix design system immediately. This guide covers the essential patterns you need to build 80% of interfaces.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# AI Code Generation Guidelines
|
# AI Code Generation Guidelines
|
||||||
|
|
||||||
**For AI Assistants**: This document contains strict rules for generating code in the PragmaStack project. Follow these rules to ensure generated code matches the design system perfectly.
|
**For AI Assistants**: This document contains strict rules for generating code in the Syndarix project. Follow these rules to ensure generated code matches the design system perfectly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Quick Reference
|
# Quick Reference
|
||||||
|
|
||||||
**Bookmark this page** for instant lookups of colors, spacing, typography, components, and common patterns. Your go-to cheat sheet for the PragmaStack design system.
|
**Bookmark this page** for instant lookups of colors, spacing, typography, components, and common patterns. Your go-to cheat sheet for the Syndarix design system.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Design System Documentation
|
# Design System Documentation
|
||||||
|
|
||||||
**PragmaStack Design System** - A comprehensive guide to building consistent, accessible, and beautiful user interfaces.
|
**Syndarix Design System** - A comprehensive guide to building consistent, accessible, and beautiful user interfaces.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ test.describe('Homepage - Desktop Navigation', () => {
|
|||||||
|
|
||||||
test('should display header with logo and navigation', async ({ page }) => {
|
test('should display header with logo and navigation', async ({ page }) => {
|
||||||
// Logo should be visible
|
// Logo should be visible
|
||||||
await expect(page.getByRole('link', { name: /PragmaStack/i })).toBeVisible();
|
await expect(page.getByRole('link', { name: /Syndarix/i })).toBeVisible();
|
||||||
|
|
||||||
// Desktop navigation links should be visible (use locator to find within header)
|
// Desktop navigation links should be visible (use locator to find within header)
|
||||||
const header = page.locator('header').first();
|
const header = page.locator('header').first();
|
||||||
@@ -23,8 +23,8 @@ test.describe('Homepage - Desktop Navigation', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should display GitHub link with star badge', async ({ page }) => {
|
test('should display GitHub link with star badge', async ({ page }) => {
|
||||||
// Find GitHub link by checking for one that has github.com in href
|
// Find GitHub link by checking for one that has gitea.pragmazest.com in href
|
||||||
const githubLink = page.locator('a[href*="github.com"]').first();
|
const githubLink = page.locator('a[href*="gitea.pragmazest.com"]').first();
|
||||||
await expect(githubLink).toBeVisible();
|
await expect(githubLink).toBeVisible();
|
||||||
await expect(githubLink).toHaveAttribute('target', '_blank');
|
await expect(githubLink).toHaveAttribute('target', '_blank');
|
||||||
});
|
});
|
||||||
@@ -120,7 +120,7 @@ test.describe('Homepage - Hero Section', () => {
|
|||||||
test('should navigate to GitHub when clicking View on GitHub', async ({ page }) => {
|
test('should navigate to GitHub when clicking View on GitHub', async ({ page }) => {
|
||||||
const githubLink = page.getByRole('link', { name: /View on GitHub/i }).first();
|
const githubLink = page.getByRole('link', { name: /View on GitHub/i }).first();
|
||||||
await expect(githubLink).toBeVisible();
|
await expect(githubLink).toBeVisible();
|
||||||
await expect(githubLink).toHaveAttribute('href', expect.stringContaining('github.com'));
|
await expect(githubLink).toHaveAttribute('href', expect.stringContaining('gitea.pragmazest.com'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should navigate to components when clicking Explore Components', async ({ page }) => {
|
test('should navigate to components when clicking Explore Components', async ({ page }) => {
|
||||||
@@ -250,7 +250,7 @@ test.describe('Homepage - Feature Sections', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should display philosophy section', async ({ page }) => {
|
test('should display philosophy section', async ({ page }) => {
|
||||||
await expect(page.getByRole('heading', { name: /Why PragmaStack/i })).toBeVisible();
|
await expect(page.getByRole('heading', { name: /Why Syndarix/i })).toBeVisible();
|
||||||
await expect(page.getByText(/MIT licensed/i).first()).toBeVisible();
|
await expect(page.getByText(/MIT licensed/i).first()).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -264,7 +264,7 @@ test.describe('Homepage - Footer', () => {
|
|||||||
// Scroll to footer
|
// Scroll to footer
|
||||||
await page.locator('footer').scrollIntoViewIfNeeded();
|
await page.locator('footer').scrollIntoViewIfNeeded();
|
||||||
|
|
||||||
await expect(page.getByText(/PragmaStack. MIT Licensed/i)).toBeVisible();
|
await expect(page.getByText(/Syndarix. MIT Licensed/i)).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ test.describe('Homepage - Accessibility', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should have accessible links with proper attributes', async ({ page }) => {
|
test('should have accessible links with proper attributes', async ({ page }) => {
|
||||||
const githubLink = page.locator('a[href*="github.com"]').first();
|
const githubLink = page.locator('a[href*="gitea.pragmazest.com"]').first();
|
||||||
await expect(githubLink).toHaveAttribute('target', '_blank');
|
await expect(githubLink).toHaveAttribute('target', '_blank');
|
||||||
await expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
await expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,42 +7,42 @@
|
|||||||
* - Please do NOT modify this file.
|
* - Please do NOT modify this file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const PACKAGE_VERSION = '2.12.3';
|
const PACKAGE_VERSION = '2.12.3'
|
||||||
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82';
|
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
|
||||||
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse');
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
||||||
const activeClientIds = new Set();
|
const activeClientIds = new Set()
|
||||||
|
|
||||||
addEventListener('install', function () {
|
addEventListener('install', function () {
|
||||||
self.skipWaiting();
|
self.skipWaiting()
|
||||||
});
|
})
|
||||||
|
|
||||||
addEventListener('activate', function (event) {
|
addEventListener('activate', function (event) {
|
||||||
event.waitUntil(self.clients.claim());
|
event.waitUntil(self.clients.claim())
|
||||||
});
|
})
|
||||||
|
|
||||||
addEventListener('message', async function (event) {
|
addEventListener('message', async function (event) {
|
||||||
const clientId = Reflect.get(event.source || {}, 'id');
|
const clientId = Reflect.get(event.source || {}, 'id')
|
||||||
|
|
||||||
if (!clientId || !self.clients) {
|
if (!clientId || !self.clients) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = await self.clients.get(clientId);
|
const client = await self.clients.get(clientId)
|
||||||
|
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const allClients = await self.clients.matchAll({
|
const allClients = await self.clients.matchAll({
|
||||||
type: 'window',
|
type: 'window',
|
||||||
});
|
})
|
||||||
|
|
||||||
switch (event.data) {
|
switch (event.data) {
|
||||||
case 'KEEPALIVE_REQUEST': {
|
case 'KEEPALIVE_REQUEST': {
|
||||||
sendToClient(client, {
|
sendToClient(client, {
|
||||||
type: 'KEEPALIVE_RESPONSE',
|
type: 'KEEPALIVE_RESPONSE',
|
||||||
});
|
})
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'INTEGRITY_CHECK_REQUEST': {
|
case 'INTEGRITY_CHECK_REQUEST': {
|
||||||
@@ -52,12 +52,12 @@ addEventListener('message', async function (event) {
|
|||||||
packageVersion: PACKAGE_VERSION,
|
packageVersion: PACKAGE_VERSION,
|
||||||
checksum: INTEGRITY_CHECKSUM,
|
checksum: INTEGRITY_CHECKSUM,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'MOCK_ACTIVATE': {
|
case 'MOCK_ACTIVATE': {
|
||||||
activeClientIds.add(clientId);
|
activeClientIds.add(clientId)
|
||||||
|
|
||||||
sendToClient(client, {
|
sendToClient(client, {
|
||||||
type: 'MOCKING_ENABLED',
|
type: 'MOCKING_ENABLED',
|
||||||
@@ -67,51 +67,54 @@ addEventListener('message', async function (event) {
|
|||||||
frameType: client.frameType,
|
frameType: client.frameType,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'CLIENT_CLOSED': {
|
case 'CLIENT_CLOSED': {
|
||||||
activeClientIds.delete(clientId);
|
activeClientIds.delete(clientId)
|
||||||
|
|
||||||
const remainingClients = allClients.filter((client) => {
|
const remainingClients = allClients.filter((client) => {
|
||||||
return client.id !== clientId;
|
return client.id !== clientId
|
||||||
});
|
})
|
||||||
|
|
||||||
// Unregister itself when there are no more clients
|
// Unregister itself when there are no more clients
|
||||||
if (remainingClients.length === 0) {
|
if (remainingClients.length === 0) {
|
||||||
self.registration.unregister();
|
self.registration.unregister()
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
addEventListener('fetch', function (event) {
|
addEventListener('fetch', function (event) {
|
||||||
const requestInterceptedAt = Date.now();
|
const requestInterceptedAt = Date.now()
|
||||||
|
|
||||||
// Bypass navigation requests.
|
// Bypass navigation requests.
|
||||||
if (event.request.mode === 'navigate') {
|
if (event.request.mode === 'navigate') {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opening the DevTools triggers the "only-if-cached" request
|
// Opening the DevTools triggers the "only-if-cached" request
|
||||||
// that cannot be handled by the worker. Bypass such requests.
|
// that cannot be handled by the worker. Bypass such requests.
|
||||||
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') {
|
if (
|
||||||
return;
|
event.request.cache === 'only-if-cached' &&
|
||||||
|
event.request.mode !== 'same-origin'
|
||||||
|
) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bypass all requests when there are no active clients.
|
// Bypass all requests when there are no active clients.
|
||||||
// Prevents the self-unregistered worked from handling requests
|
// Prevents the self-unregistered worked from handling requests
|
||||||
// after it's been terminated (still remains active until the next reload).
|
// after it's been terminated (still remains active until the next reload).
|
||||||
if (activeClientIds.size === 0) {
|
if (activeClientIds.size === 0) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestId = crypto.randomUUID();
|
const requestId = crypto.randomUUID()
|
||||||
event.respondWith(handleRequest(event, requestId, requestInterceptedAt));
|
event.respondWith(handleRequest(event, requestId, requestInterceptedAt))
|
||||||
});
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {FetchEvent} event
|
* @param {FetchEvent} event
|
||||||
@@ -119,18 +122,23 @@ addEventListener('fetch', function (event) {
|
|||||||
* @param {number} requestInterceptedAt
|
* @param {number} requestInterceptedAt
|
||||||
*/
|
*/
|
||||||
async function handleRequest(event, requestId, requestInterceptedAt) {
|
async function handleRequest(event, requestId, requestInterceptedAt) {
|
||||||
const client = await resolveMainClient(event);
|
const client = await resolveMainClient(event)
|
||||||
const requestCloneForEvents = event.request.clone();
|
const requestCloneForEvents = event.request.clone()
|
||||||
const response = await getResponse(event, client, requestId, requestInterceptedAt);
|
const response = await getResponse(
|
||||||
|
event,
|
||||||
|
client,
|
||||||
|
requestId,
|
||||||
|
requestInterceptedAt,
|
||||||
|
)
|
||||||
|
|
||||||
// Send back the response clone for the "response:*" life-cycle events.
|
// Send back the response clone for the "response:*" life-cycle events.
|
||||||
// Ensure MSW is active and ready to handle the message, otherwise
|
// Ensure MSW is active and ready to handle the message, otherwise
|
||||||
// this message will pend indefinitely.
|
// this message will pend indefinitely.
|
||||||
if (client && activeClientIds.has(client.id)) {
|
if (client && activeClientIds.has(client.id)) {
|
||||||
const serializedRequest = await serializeRequest(requestCloneForEvents);
|
const serializedRequest = await serializeRequest(requestCloneForEvents)
|
||||||
|
|
||||||
// Clone the response so both the client and the library could consume it.
|
// Clone the response so both the client and the library could consume it.
|
||||||
const responseClone = response.clone();
|
const responseClone = response.clone()
|
||||||
|
|
||||||
sendToClient(
|
sendToClient(
|
||||||
client,
|
client,
|
||||||
@@ -151,11 +159,11 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
responseClone.body ? [serializedRequest.body, responseClone.body] : []
|
responseClone.body ? [serializedRequest.body, responseClone.body] : [],
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,30 +175,30 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
|
|||||||
* @returns {Promise<Client | undefined>}
|
* @returns {Promise<Client | undefined>}
|
||||||
*/
|
*/
|
||||||
async function resolveMainClient(event) {
|
async function resolveMainClient(event) {
|
||||||
const client = await self.clients.get(event.clientId);
|
const client = await self.clients.get(event.clientId)
|
||||||
|
|
||||||
if (activeClientIds.has(event.clientId)) {
|
if (activeClientIds.has(event.clientId)) {
|
||||||
return client;
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client?.frameType === 'top-level') {
|
if (client?.frameType === 'top-level') {
|
||||||
return client;
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
const allClients = await self.clients.matchAll({
|
const allClients = await self.clients.matchAll({
|
||||||
type: 'window',
|
type: 'window',
|
||||||
});
|
})
|
||||||
|
|
||||||
return allClients
|
return allClients
|
||||||
.filter((client) => {
|
.filter((client) => {
|
||||||
// Get only those clients that are currently visible.
|
// Get only those clients that are currently visible.
|
||||||
return client.visibilityState === 'visible';
|
return client.visibilityState === 'visible'
|
||||||
})
|
})
|
||||||
.find((client) => {
|
.find((client) => {
|
||||||
// Find the client ID that's recorded in the
|
// Find the client ID that's recorded in the
|
||||||
// set of clients that have registered the worker.
|
// set of clients that have registered the worker.
|
||||||
return activeClientIds.has(client.id);
|
return activeClientIds.has(client.id)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,34 +211,36 @@ async function resolveMainClient(event) {
|
|||||||
async function getResponse(event, client, requestId, requestInterceptedAt) {
|
async function getResponse(event, client, requestId, requestInterceptedAt) {
|
||||||
// Clone the request because it might've been already used
|
// Clone the request because it might've been already used
|
||||||
// (i.e. its body has been read and sent to the client).
|
// (i.e. its body has been read and sent to the client).
|
||||||
const requestClone = event.request.clone();
|
const requestClone = event.request.clone()
|
||||||
|
|
||||||
function passthrough() {
|
function passthrough() {
|
||||||
// Cast the request headers to a new Headers instance
|
// Cast the request headers to a new Headers instance
|
||||||
// so the headers can be manipulated with.
|
// so the headers can be manipulated with.
|
||||||
const headers = new Headers(requestClone.headers);
|
const headers = new Headers(requestClone.headers)
|
||||||
|
|
||||||
// Remove the "accept" header value that marked this request as passthrough.
|
// Remove the "accept" header value that marked this request as passthrough.
|
||||||
// This prevents request alteration and also keeps it compliant with the
|
// This prevents request alteration and also keeps it compliant with the
|
||||||
// user-defined CORS policies.
|
// user-defined CORS policies.
|
||||||
const acceptHeader = headers.get('accept');
|
const acceptHeader = headers.get('accept')
|
||||||
if (acceptHeader) {
|
if (acceptHeader) {
|
||||||
const values = acceptHeader.split(',').map((value) => value.trim());
|
const values = acceptHeader.split(',').map((value) => value.trim())
|
||||||
const filteredValues = values.filter((value) => value !== 'msw/passthrough');
|
const filteredValues = values.filter(
|
||||||
|
(value) => value !== 'msw/passthrough',
|
||||||
|
)
|
||||||
|
|
||||||
if (filteredValues.length > 0) {
|
if (filteredValues.length > 0) {
|
||||||
headers.set('accept', filteredValues.join(', '));
|
headers.set('accept', filteredValues.join(', '))
|
||||||
} else {
|
} else {
|
||||||
headers.delete('accept');
|
headers.delete('accept')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(requestClone, { headers });
|
return fetch(requestClone, { headers })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bypass mocking when the client is not active.
|
// Bypass mocking when the client is not active.
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return passthrough();
|
return passthrough()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bypass initial page load requests (i.e. static assets).
|
// Bypass initial page load requests (i.e. static assets).
|
||||||
@@ -238,11 +248,11 @@ async function getResponse(event, client, requestId, requestInterceptedAt) {
|
|||||||
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
|
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
|
||||||
// and is not ready to handle requests.
|
// and is not ready to handle requests.
|
||||||
if (!activeClientIds.has(client.id)) {
|
if (!activeClientIds.has(client.id)) {
|
||||||
return passthrough();
|
return passthrough()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the client that a request has been intercepted.
|
// Notify the client that a request has been intercepted.
|
||||||
const serializedRequest = await serializeRequest(event.request);
|
const serializedRequest = await serializeRequest(event.request)
|
||||||
const clientMessage = await sendToClient(
|
const clientMessage = await sendToClient(
|
||||||
client,
|
client,
|
||||||
{
|
{
|
||||||
@@ -253,20 +263,20 @@ async function getResponse(event, client, requestId, requestInterceptedAt) {
|
|||||||
...serializedRequest,
|
...serializedRequest,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[serializedRequest.body]
|
[serializedRequest.body],
|
||||||
);
|
)
|
||||||
|
|
||||||
switch (clientMessage.type) {
|
switch (clientMessage.type) {
|
||||||
case 'MOCK_RESPONSE': {
|
case 'MOCK_RESPONSE': {
|
||||||
return respondWithMock(clientMessage.data);
|
return respondWithMock(clientMessage.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'PASSTHROUGH': {
|
case 'PASSTHROUGH': {
|
||||||
return passthrough();
|
return passthrough()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return passthrough();
|
return passthrough()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,18 +287,21 @@ async function getResponse(event, client, requestId, requestInterceptedAt) {
|
|||||||
*/
|
*/
|
||||||
function sendToClient(client, message, transferrables = []) {
|
function sendToClient(client, message, transferrables = []) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const channel = new MessageChannel();
|
const channel = new MessageChannel()
|
||||||
|
|
||||||
channel.port1.onmessage = (event) => {
|
channel.port1.onmessage = (event) => {
|
||||||
if (event.data && event.data.error) {
|
if (event.data && event.data.error) {
|
||||||
return reject(event.data.error);
|
return reject(event.data.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(event.data);
|
resolve(event.data)
|
||||||
};
|
}
|
||||||
|
|
||||||
client.postMessage(message, [channel.port2, ...transferrables.filter(Boolean)]);
|
client.postMessage(message, [
|
||||||
});
|
channel.port2,
|
||||||
|
...transferrables.filter(Boolean),
|
||||||
|
])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,17 +314,17 @@ function respondWithMock(response) {
|
|||||||
// instance will have status code set to 0. Since it's not possible to create
|
// instance will have status code set to 0. Since it's not possible to create
|
||||||
// a Response instance with status code 0, handle that use-case separately.
|
// a Response instance with status code 0, handle that use-case separately.
|
||||||
if (response.status === 0) {
|
if (response.status === 0) {
|
||||||
return Response.error();
|
return Response.error()
|
||||||
}
|
}
|
||||||
|
|
||||||
const mockedResponse = new Response(response.body, response);
|
const mockedResponse = new Response(response.body, response)
|
||||||
|
|
||||||
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
|
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
|
||||||
value: true,
|
value: true,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
})
|
||||||
|
|
||||||
return mockedResponse;
|
return mockedResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,5 +345,5 @@ async function serializeRequest(request) {
|
|||||||
referrerPolicy: request.referrerPolicy,
|
referrerPolicy: request.referrerPolicy,
|
||||||
body: await request.arrayBuffer(),
|
body: await request.arrayBuffer(),
|
||||||
keepalive: request.keepalive,
|
keepalive: request.keepalive,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Footer } from '@/components/layout/Footer';
|
|||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
template: '%s | PragmaStack',
|
template: '%s | Syndarix',
|
||||||
default: 'Dashboard',
|
default: 'Dashboard',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { AdminSidebar, Breadcrumbs } from '@/components/admin';
|
|||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
template: '%s | Admin | PragmaStack',
|
template: '%s | Admin | Syndarix',
|
||||||
default: 'Admin Dashboard',
|
default: 'Admin Dashboard',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import { Badge } from '@/components/ui/badge';
|
|||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Demo Tour | PragmaStack',
|
title: 'Demo Tour | Syndarix',
|
||||||
description: 'Try all features with demo credentials - comprehensive guide to the PragmaStack',
|
description: 'Try all features with demo credentials - comprehensive guide to the Syndarix',
|
||||||
};
|
};
|
||||||
|
|
||||||
const demoCategories = [
|
const demoCategories = [
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ export default function DocsHub() {
|
|||||||
<h2 className="text-4xl font-bold tracking-tight mb-4">Design System Documentation</h2>
|
<h2 className="text-4xl font-bold tracking-tight mb-4">Design System Documentation</h2>
|
||||||
<p className="text-lg text-muted-foreground mb-8">
|
<p className="text-lg text-muted-foreground mb-8">
|
||||||
Comprehensive guides, best practices, and references for building consistent,
|
Comprehensive guides, best practices, and references for building consistent,
|
||||||
accessible, and maintainable user interfaces with the PragmaStack design system.
|
accessible, and maintainable user interfaces with the Syndarix design system.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap gap-3 justify-center">
|
<div className="flex flex-wrap gap-3 justify-center">
|
||||||
<Link href="/dev/docs/design-system/00-quick-start">
|
<Link href="/dev/docs/design-system/00-quick-start">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Badge } from '@/components/ui/badge';
|
|||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Design System Hub | PragmaStack',
|
title: 'Design System Hub | Syndarix',
|
||||||
description:
|
description:
|
||||||
'Interactive design system demonstrations with live examples - explore components, layouts, spacing, and forms built with shadcn/ui and Tailwind CSS',
|
'Interactive design system demonstrations with live examples - explore components, layouts, spacing, and forms built with shadcn/ui and Tailwind CSS',
|
||||||
};
|
};
|
||||||
@@ -90,7 +90,7 @@ export default function DesignSystemHub() {
|
|||||||
</div>
|
</div>
|
||||||
<p className="text-lg text-muted-foreground">
|
<p className="text-lg text-muted-foreground">
|
||||||
Interactive demonstrations, live examples, and comprehensive documentation for the
|
Interactive demonstrations, live examples, and comprehensive documentation for the
|
||||||
PragmaStack design system. Built with shadcn/ui + Tailwind CSS 4.
|
Syndarix design system. Built with shadcn/ui + Tailwind CSS 4.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* istanbul ignore file -- @preserve Landing page with complex interactions tested via E2E */
|
/* istanbul ignore file -- @preserve Landing page with complex interactions tested via E2E */
|
||||||
/**
|
/**
|
||||||
* Homepage / Landing Page
|
* Homepage / Landing Page
|
||||||
* Main landing page for the PragmaStack project
|
* Main landing page for the Syndarix project
|
||||||
* Showcases features, tech stack, and provides demos for developers
|
* Showcases features, tech stack, and provides demos for developers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ export default function Home() {
|
|||||||
<div className="container mx-auto px-6 py-8">
|
<div className="container mx-auto px-6 py-8">
|
||||||
<div className="flex flex-col md:flex-row items-center justify-between gap-4">
|
<div className="flex flex-col md:flex-row items-center justify-between gap-4">
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
© {new Date().getFullYear()} PragmaStack. MIT Licensed.
|
© {new Date().getFullYear()} Syndarix. MIT Licensed.
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-6 text-sm text-muted-foreground">
|
<div className="flex items-center gap-6 text-sm text-muted-foreground">
|
||||||
<Link href="/demos" className="hover:text-foreground transition-colors">
|
<Link href="/demos" className="hover:text-foreground transition-colors">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PragmaStack Design System
|
* Syndarix Design System
|
||||||
* Theme: Modern Minimal (from tweakcn.com)
|
* Theme: Modern Minimal (from tweakcn.com)
|
||||||
* Primary: Blue | Color Space: OKLCH
|
* Primary: Blue | Color Space: OKLCH
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -96,12 +96,12 @@ export function DevLayout({ children }: DevLayoutProps) {
|
|||||||
<div className="flex items-center gap-3 shrink-0">
|
<div className="flex items-center gap-3 shrink-0">
|
||||||
<Image
|
<Image
|
||||||
src="/logo-icon.svg"
|
src="/logo-icon.svg"
|
||||||
alt="PragmaStack Logo"
|
alt="Syndarix Logo"
|
||||||
width={24}
|
width={24}
|
||||||
height={24}
|
height={24}
|
||||||
className="h-6 w-6"
|
className="h-6 w-6"
|
||||||
/>
|
/>
|
||||||
<h1 className="text-base font-semibold">PragmaStack</h1>
|
<h1 className="text-base font-semibold">Syndarix</h1>
|
||||||
<Badge variant="secondary" className="text-xs">
|
<Badge variant="secondary" className="text-xs">
|
||||||
Dev
|
Dev
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import { Link } from '@/lib/i18n/routing';
|
|||||||
|
|
||||||
const commands = [
|
const commands = [
|
||||||
{ text: '# Clone the repository', delay: 0 },
|
{ text: '# Clone the repository', delay: 0 },
|
||||||
{ text: '$ git clone https://github.com/your-org/fast-next-template.git', delay: 800 },
|
{ text: '$ git clone https://gitea.pragmazest.com/cardosofelipe/syndarix.git', delay: 800 },
|
||||||
{ text: '$ cd fast-next-template', delay: 1600 },
|
{ text: '$ cd syndarix', delay: 1600 },
|
||||||
{ text: '', delay: 2200 },
|
{ text: '', delay: 2200 },
|
||||||
{ text: '# Start with Docker (one command)', delay: 2400 },
|
{ text: '# Start with Docker (one command)', delay: 2400 },
|
||||||
{ text: '$ docker-compose up', delay: 3200 },
|
{ text: '$ docker-compose up', delay: 3200 },
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export function CTASection({ onOpenDemoModal }: CTASectionProps) {
|
|||||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 pt-4">
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 pt-4">
|
||||||
<Button asChild size="lg" className="gap-2 text-base group">
|
<Button asChild size="lg" className="gap-2 text-base group">
|
||||||
<a
|
<a
|
||||||
href="https://github.com/your-org/fast-next-template"
|
href="https://gitea.pragmazest.com/cardosofelipe/syndarix"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
@@ -75,7 +75,7 @@ export function CTASection({ onOpenDemoModal }: CTASectionProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button asChild size="lg" variant="ghost" className="gap-2 text-base group">
|
<Button asChild size="lg" variant="ghost" className="gap-2 text-base group">
|
||||||
<a
|
<a
|
||||||
href="https://github.com/your-org/fast-next-template#documentation"
|
href="https://gitea.pragmazest.com/cardosofelipe/syndarix#documentation"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const features = [
|
|||||||
'12+ documentation guides covering architecture, design system, testing patterns, deployment, and AI code generation guidelines. Interactive API docs with Swagger and ReDoc',
|
'12+ documentation guides covering architecture, design system, testing patterns, deployment, and AI code generation guidelines. Interactive API docs with Swagger and ReDoc',
|
||||||
highlight: 'Developer-first docs',
|
highlight: 'Developer-first docs',
|
||||||
ctaText: 'Browse Docs',
|
ctaText: 'Browse Docs',
|
||||||
ctaHref: 'https://github.com/your-org/fast-next-template#documentation',
|
ctaHref: 'https://gitea.pragmazest.com/cardosofelipe/syndarix#documentation',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Server,
|
icon: Server,
|
||||||
@@ -53,7 +53,7 @@ const features = [
|
|||||||
'Docker deployment configs, database migrations with Alembic helpers, connection pooling, health checks, monitoring setup, and production security headers',
|
'Docker deployment configs, database migrations with Alembic helpers, connection pooling, health checks, monitoring setup, and production security headers',
|
||||||
highlight: 'Deploy with confidence',
|
highlight: 'Deploy with confidence',
|
||||||
ctaText: 'Deployment Guide',
|
ctaText: 'Deployment Guide',
|
||||||
ctaHref: 'https://github.com/your-org/fast-next-template#deployment',
|
ctaHref: 'https://gitea.pragmazest.com/cardosofelipe/syndarix#deployment',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Code,
|
icon: Code,
|
||||||
|
|||||||
@@ -48,13 +48,13 @@ export function Header({ onOpenDemoModal }: HeaderProps) {
|
|||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src="/logo-icon.svg"
|
src="/logo-icon.svg"
|
||||||
alt="PragmaStack Logo"
|
alt="Syndarix Logo"
|
||||||
width={32}
|
width={32}
|
||||||
height={32}
|
height={32}
|
||||||
className="h-8 w-8"
|
className="h-8 w-8"
|
||||||
/>
|
/>
|
||||||
<span className="bg-gradient-to-r from-primary to-primary/60 bg-clip-text text-transparent">
|
<span className="bg-gradient-to-r from-primary to-primary/60 bg-clip-text text-transparent">
|
||||||
PragmaStack
|
Syndarix
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ export function Header({ onOpenDemoModal }: HeaderProps) {
|
|||||||
|
|
||||||
{/* GitHub Link with Star */}
|
{/* GitHub Link with Star */}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/your-org/fast-next-template"
|
href="https://gitea.pragmazest.com/cardosofelipe/syndarix"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="flex items-center gap-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
|
className="flex items-center gap-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
|
||||||
@@ -135,7 +135,7 @@ export function Header({ onOpenDemoModal }: HeaderProps) {
|
|||||||
|
|
||||||
{/* GitHub Link */}
|
{/* GitHub Link */}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/your-org/fast-next-template"
|
href="https://gitea.pragmazest.com/cardosofelipe/syndarix"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
onClick={() => setMobileMenuOpen(false)}
|
onClick={() => setMobileMenuOpen(false)}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export function HeroSection({ onOpenDemoModal }: HeroSectionProps) {
|
|||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.5, delay: 0.2 }}
|
transition={{ duration: 0.5, delay: 0.2 }}
|
||||||
>
|
>
|
||||||
Opinionated, secure, and production-ready. PragmaStack gives you the solid foundation
|
Opinionated, secure, and production-ready. Syndarix gives you the solid foundation
|
||||||
you need to stop configuring and start shipping.{' '}
|
you need to stop configuring and start shipping.{' '}
|
||||||
<span className="text-foreground font-medium">Start building features on day one.</span>
|
<span className="text-foreground font-medium">Start building features on day one.</span>
|
||||||
</motion.p>
|
</motion.p>
|
||||||
@@ -93,7 +93,7 @@ export function HeroSection({ onOpenDemoModal }: HeroSectionProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button asChild size="lg" variant="outline" className="gap-2 text-base group">
|
<Button asChild size="lg" variant="outline" className="gap-2 text-base group">
|
||||||
<a
|
<a
|
||||||
href="https://github.com/your-org/fast-next-template"
|
href="https://gitea.pragmazest.com/cardosofelipe/syndarix"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export function PhilosophySection() {
|
|||||||
viewport={{ once: true, margin: '-100px' }}
|
viewport={{ once: true, margin: '-100px' }}
|
||||||
transition={{ duration: 0.6 }}
|
transition={{ duration: 0.6 }}
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold mb-6">Why PragmaStack?</h2>
|
<h2 className="text-3xl md:text-4xl font-bold mb-6">Why Syndarix?</h2>
|
||||||
<div className="space-y-4 text-lg text-muted-foreground leading-relaxed">
|
<div className="space-y-4 text-lg text-muted-foreground leading-relaxed">
|
||||||
<p>
|
<p>
|
||||||
We built this template after rebuilding the same authentication, authorization, and
|
We built this template after rebuilding the same authentication, authorization, and
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
|
||||||
const codeString = `# Clone and start with Docker
|
const codeString = `# Clone and start with Docker
|
||||||
git clone https://github.com/your-org/fast-next-template.git
|
git clone https://gitea.pragmazest.com/cardosofelipe/syndarix.git
|
||||||
cd fast-next-template
|
cd syndarix
|
||||||
docker-compose up
|
docker-compose up
|
||||||
|
|
||||||
# Or set up locally
|
# Or set up locally
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ export function Footer() {
|
|||||||
<div className="flex items-center gap-2 text-center text-sm text-muted-foreground md:text-left">
|
<div className="flex items-center gap-2 text-center text-sm text-muted-foreground md:text-left">
|
||||||
<Image
|
<Image
|
||||||
src="/logo-icon.svg"
|
src="/logo-icon.svg"
|
||||||
alt="PragmaStack Logo"
|
alt="Syndarix Logo"
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
className="h-5 w-5 opacity-70"
|
className="h-5 w-5 opacity-70"
|
||||||
/>
|
/>
|
||||||
<span>© {currentYear} PragmaStack. All rights reserved.</span>
|
<span>© {currentYear} Syndarix. All rights reserved.</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-6">
|
<div className="flex space-x-6">
|
||||||
<Link
|
<Link
|
||||||
@@ -33,7 +33,7 @@ export function Footer() {
|
|||||||
Settings
|
Settings
|
||||||
</Link>
|
</Link>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/cardosofelipe/pragmastack"
|
href="https://gitea.pragmazest.com/cardosofelipe/syndarix"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
|||||||
@@ -86,12 +86,12 @@ export function Header() {
|
|||||||
<Link href="/" className="flex items-center space-x-2">
|
<Link href="/" className="flex items-center space-x-2">
|
||||||
<Image
|
<Image
|
||||||
src="/logo-icon.svg"
|
src="/logo-icon.svg"
|
||||||
alt="PragmaStack Logo"
|
alt="Syndarix Logo"
|
||||||
width={32}
|
width={32}
|
||||||
height={32}
|
height={32}
|
||||||
className="h-8 w-8"
|
className="h-8 w-8"
|
||||||
/>
|
/>
|
||||||
<span className="text-xl font-bold text-foreground">PragmaStack</span>
|
<span className="text-xl font-bold text-foreground">Syndarix</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Navigation Links */}
|
{/* Navigation Links */}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ export type Locale = 'en' | 'it';
|
|||||||
*/
|
*/
|
||||||
export const siteConfig = {
|
export const siteConfig = {
|
||||||
name: {
|
name: {
|
||||||
en: 'PragmaStack',
|
en: 'Syndarix',
|
||||||
it: 'PragmaStack',
|
it: 'Syndarix',
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
en: 'Production-ready FastAPI + Next.js full-stack template with authentication, admin panel, and comprehensive testing',
|
en: 'Production-ready FastAPI + Next.js full-stack template with authentication, admin panel, and comprehensive testing',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Tests for Home Page
|
* Tests for Home Page
|
||||||
* Tests for the new PragmaStack landing page
|
* Tests for the new Syndarix landing page
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { render, screen, within, fireEvent } from '@testing-library/react';
|
import { render, screen, within, fireEvent } from '@testing-library/react';
|
||||||
@@ -87,13 +87,13 @@ describe('HomePage', () => {
|
|||||||
it('renders header with logo', () => {
|
it('renders header with logo', () => {
|
||||||
render(<Home />);
|
render(<Home />);
|
||||||
const header = screen.getByRole('banner');
|
const header = screen.getByRole('banner');
|
||||||
expect(within(header).getByText('PragmaStack')).toBeInTheDocument();
|
expect(within(header).getByText('Syndarix')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders footer with copyright', () => {
|
it('renders footer with copyright', () => {
|
||||||
render(<Home />);
|
render(<Home />);
|
||||||
const footer = screen.getByRole('contentinfo');
|
const footer = screen.getByRole('contentinfo');
|
||||||
expect(within(footer).getByText(/PragmaStack. MIT Licensed/i)).toBeInTheDocument();
|
expect(within(footer).getByText(/Syndarix. MIT Licensed/i)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ describe('HomePage', () => {
|
|||||||
describe('Philosophy Section', () => {
|
describe('Philosophy Section', () => {
|
||||||
it('renders why this template exists', () => {
|
it('renders why this template exists', () => {
|
||||||
render(<Home />);
|
render(<Home />);
|
||||||
expect(screen.getByText(/Why PragmaStack\?/i)).toBeInTheDocument();
|
expect(screen.getByText(/Why Syndarix\?/i)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders what you wont find section', () => {
|
it('renders what you wont find section', () => {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ describe('CTASection', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const githubLink = screen.getByRole('link', { name: /get started on github/i });
|
const githubLink = screen.getByRole('link', { name: /get started on github/i });
|
||||||
expect(githubLink).toHaveAttribute('href', 'https://github.com/your-org/fast-next-template');
|
expect(githubLink).toHaveAttribute('href', 'https://gitea.pragmazest.com/cardosofelipe/syndarix');
|
||||||
expect(githubLink).toHaveAttribute('target', '_blank');
|
expect(githubLink).toHaveAttribute('target', '_blank');
|
||||||
expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
||||||
});
|
});
|
||||||
@@ -101,7 +101,7 @@ describe('CTASection', () => {
|
|||||||
const docsLink = screen.getByRole('link', { name: /read documentation/i });
|
const docsLink = screen.getByRole('link', { name: /read documentation/i });
|
||||||
expect(docsLink).toHaveAttribute(
|
expect(docsLink).toHaveAttribute(
|
||||||
'href',
|
'href',
|
||||||
'https://github.com/your-org/fast-next-template#documentation'
|
'https://gitea.pragmazest.com/cardosofelipe/syndarix#documentation'
|
||||||
);
|
);
|
||||||
expect(docsLink).toHaveAttribute('target', '_blank');
|
expect(docsLink).toHaveAttribute('target', '_blank');
|
||||||
expect(docsLink).toHaveAttribute('rel', 'noopener noreferrer');
|
expect(docsLink).toHaveAttribute('rel', 'noopener noreferrer');
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ describe('Header', () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByText('PragmaStack')).toBeInTheDocument();
|
expect(screen.getByText('Syndarix')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('logo links to homepage', () => {
|
it('logo links to homepage', () => {
|
||||||
@@ -67,7 +67,7 @@ describe('Header', () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const logoLink = screen.getByRole('link', { name: /PragmaStack/i });
|
const logoLink = screen.getByRole('link', { name: /Syndarix/i });
|
||||||
expect(logoLink).toHaveAttribute('href', '/');
|
expect(logoLink).toHaveAttribute('href', '/');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -97,12 +97,12 @@ describe('Header', () => {
|
|||||||
|
|
||||||
const githubLinks = screen.getAllByRole('link', { name: /github/i });
|
const githubLinks = screen.getAllByRole('link', { name: /github/i });
|
||||||
const desktopGithubLink = githubLinks.find((link) =>
|
const desktopGithubLink = githubLinks.find((link) =>
|
||||||
link.getAttribute('href')?.includes('github.com')
|
link.getAttribute('href')?.includes('gitea.pragmazest.com')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(desktopGithubLink).toHaveAttribute(
|
expect(desktopGithubLink).toHaveAttribute(
|
||||||
'href',
|
'href',
|
||||||
'https://github.com/your-org/fast-next-template'
|
'https://gitea.pragmazest.com/cardosofelipe/syndarix'
|
||||||
);
|
);
|
||||||
expect(desktopGithubLink).toHaveAttribute('target', '_blank');
|
expect(desktopGithubLink).toHaveAttribute('target', '_blank');
|
||||||
expect(desktopGithubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
expect(desktopGithubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ describe('HeroSection', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const githubLink = screen.getByRole('link', { name: /view on github/i });
|
const githubLink = screen.getByRole('link', { name: /view on github/i });
|
||||||
expect(githubLink).toHaveAttribute('href', 'https://github.com/your-org/fast-next-template');
|
expect(githubLink).toHaveAttribute('href', 'https://gitea.pragmazest.com/cardosofelipe/syndarix');
|
||||||
expect(githubLink).toHaveAttribute('target', '_blank');
|
expect(githubLink).toHaveAttribute('target', '_blank');
|
||||||
expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe('Footer', () => {
|
|||||||
|
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
expect(
|
expect(
|
||||||
screen.getByText(`© ${currentYear} PragmaStack. All rights reserved.`)
|
screen.getByText(`© ${currentYear} Syndarix. All rights reserved.`)
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ describe('Header', () => {
|
|||||||
|
|
||||||
render(<Header />);
|
render(<Header />);
|
||||||
|
|
||||||
expect(screen.getByText('PragmaStack')).toBeInTheDocument();
|
expect(screen.getByText('Syndarix')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders theme toggle', () => {
|
it('renders theme toggle', () => {
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ describe('metadata utilities', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should have English and Italian names', () => {
|
it('should have English and Italian names', () => {
|
||||||
expect(siteConfig.name.en).toBe('PragmaStack');
|
expect(siteConfig.name.en).toBe('Syndarix');
|
||||||
expect(siteConfig.name.it).toBe('PragmaStack');
|
expect(siteConfig.name.it).toBe('Syndarix');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have English and Italian descriptions', () => {
|
it('should have English and Italian descriptions', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user