setStep(1)}
- className="flex items-center gap-1.5 text-sm text-neutral-500 dark:text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300 mb-6 focus:outline-none focus:ring-2 focus:ring-brand-orange rounded"
+ className="flex items-center gap-2 text-sm text-neutral-500 dark:text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300 mb-6 focus:outline-none focus:ring-2 focus:ring-brand-orange rounded"
aria-label="Back to welcome"
>
@@ -485,7 +485,7 @@ function WelcomeContent() {
-
+
Name your organization
@@ -546,7 +546,7 @@ function WelcomeContent() {
setStep(2)}
- className="flex items-center gap-1.5 text-sm text-neutral-500 dark:text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300 mb-6 focus:outline-none focus:ring-2 focus:ring-brand-orange rounded"
+ className="flex items-center gap-2 text-sm text-neutral-500 dark:text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300 mb-6 focus:outline-none focus:ring-2 focus:ring-brand-orange rounded"
aria-label="Back to organization"
>
@@ -556,7 +556,7 @@ function WelcomeContent() {
-
+
{showPendingCheckoutInStep3 ? 'Complete your plan' : "You're on the free plan"}
@@ -631,7 +631,7 @@ function WelcomeContent() {
setStep(3)}
- className="flex items-center gap-1.5 text-sm text-neutral-500 dark:text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300 mb-6 focus:outline-none focus:ring-2 focus:ring-brand-orange rounded"
+ className="flex items-center gap-2 text-sm text-neutral-500 dark:text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300 mb-6 focus:outline-none focus:ring-2 focus:ring-brand-orange rounded"
aria-label="Back to plan"
>
@@ -641,7 +641,7 @@ function WelcomeContent() {
-
+
Add your first site
@@ -759,11 +759,11 @@ function WelcomeContent() {
)}
-
+
Go to dashboard
{createdSite && (
-
+
View {createdSite.name}
)}
diff --git a/components/Footer.tsx b/components/Footer.tsx
index cf7865a..0adeaa1 100644
--- a/components/Footer.tsx
+++ b/components/Footer.tsx
@@ -95,7 +95,7 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
Simple analytics for privacy-conscious apps.
-
+
diff --git a/components/IntegrationGuide.tsx b/components/IntegrationGuide.tsx
index a019e23..efca796 100644
--- a/components/IntegrationGuide.tsx
+++ b/components/IntegrationGuide.tsx
@@ -47,7 +47,7 @@ export function IntegrationGuide({ integration, children }: IntegrationGuideProp
/>
-
+
+
You are currently offline. Changes may not be saved.
diff --git a/components/PricingSection.tsx b/components/PricingSection.tsx
index 2624e72..41e346f 100644
--- a/components/PricingSection.tsx
+++ b/components/PricingSection.tsx
@@ -238,7 +238,7 @@ export default function PricingSection() {
{/* Top Toolbar */}
-
+
10k
Up to {currentTraffic.label} monthly pageviews
@@ -259,7 +259,7 @@ export default function PricingSection() {
-
+
Get 1 month free with yearly
@@ -310,7 +310,7 @@ export default function PricingSection() {
{plan.name}
-
{plan.description}
+
{plan.description}
{priceDetails ? (
isYearly ? (
@@ -319,7 +319,7 @@ export default function PricingSection() {
€{priceDetails.yearlyTotal}
-
/year
+
/year
@@ -335,7 +335,7 @@ export default function PricingSection() {
€{priceDetails.baseMonthly}
- /mo
+ /mo
)
) : (
@@ -370,18 +370,19 @@ export default function PricingSection() {
Enterprise
-
For high volume sites and custom needs
+
For high volume sites and custom needs
Custom
-
{ window.location.href = 'mailto:business@ciphera.net?subject=Enterprise%20Plan%20Inquiry' }}
>
Contact us
-
+
{[
diff --git a/components/dashboard/Campaigns.tsx b/components/dashboard/Campaigns.tsx
index 96c7ebf..bd0f6a3 100644
--- a/components/dashboard/Campaigns.tsx
+++ b/components/dashboard/Campaigns.tsx
@@ -146,7 +146,7 @@ export default function Campaigns({ siteId, dateRange }: CampaignsProps) {
handleSort(colKey)}
- className={`inline-flex items-center gap-0.5 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-inset rounded ${className}`}
+ className={`inline-flex items-center gap-1 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-inset rounded ${className}`}
aria-label={`Sort by ${label}`}
>
{label}
@@ -170,7 +170,7 @@ export default function Campaigns({ siteId, dateRange }: CampaignsProps) {
Export
@@ -179,7 +179,7 @@ export default function Campaigns({ siteId, dateRange }: CampaignsProps) {
setIsBuilderOpen(true)}
- className="h-8 px-3 text-xs gap-1.5"
+ className="h-8 px-3 text-xs gap-2"
>
Build URL
@@ -276,7 +276,7 @@ export default function Campaigns({ siteId, dateRange }: CampaignsProps) {
Read documentation
diff --git a/components/dashboard/Chart.tsx b/components/dashboard/Chart.tsx
index f5c08e5..355090f 100644
--- a/components/dashboard/Chart.tsx
+++ b/components/dashboard/Chart.tsx
@@ -18,27 +18,27 @@ import { ArrowUpRightIcon, ArrowDownRightIcon, BarChartIcon, Select, Button, Dow
import { Checkbox } from '@ciphera-net/ui'
const COLORS = {
- brand: '#FD5E0F',
- success: '#10B981', // Emerald-500
- danger: '#EF4444', // Red-500
+ brand: 'var(--color-brand-orange)',
+ success: 'var(--color-success)',
+ danger: 'var(--color-error)',
}
const CHART_COLORS_LIGHT = {
- border: '#E5E5E5',
- text: '#171717',
- textMuted: '#737373',
- axis: '#A3A3A3',
+ border: 'var(--color-neutral-200)',
+ text: 'var(--color-neutral-900)',
+ textMuted: 'var(--color-neutral-500)',
+ axis: 'var(--color-neutral-400)',
tooltipBg: '#ffffff',
- tooltipBorder: '#E5E5E5',
+ tooltipBorder: 'var(--color-neutral-200)',
}
const CHART_COLORS_DARK = {
- border: '#404040',
- text: '#fafafa',
- textMuted: '#a3a3a3',
- axis: '#737373',
- tooltipBg: '#262626',
- tooltipBorder: '#404040',
+ border: 'var(--color-neutral-700)',
+ text: 'var(--color-neutral-50)',
+ textMuted: 'var(--color-neutral-400)',
+ axis: 'var(--color-neutral-500)',
+ tooltipBg: 'var(--color-neutral-800)',
+ tooltipBorder: 'var(--color-neutral-700)',
}
export interface DailyStat {
@@ -127,7 +127,7 @@ function ChartTooltip({
return (
{hasPrev && (
-
+
vs {formatValue(prev as number)} {prevPeriodLabel ? `(${prevPeriodLabel})` : 'prev'}
{delta !== null && (
@@ -540,7 +540,7 @@ export default function Chart({
{prevData?.length ? (
-
+
Export chart
@@ -570,7 +570,7 @@ export default function Chart({
{!hasData ? (
-
+
No data for this period
@@ -578,7 +578,7 @@ export default function Chart({
Try a different date range
) : !hasAnyNonZero ? (
-
+
No {metricLabel.toLowerCase()} data for this period
@@ -694,7 +694,7 @@ export default function Chart({
activeDot={{
r: 5,
strokeWidth: 2,
- fill: resolvedTheme === 'dark' ? '#262626' : '#ffffff',
+ fill: resolvedTheme === 'dark' ? 'var(--color-neutral-800)' : '#ffffff',
stroke: activeMetric.color,
}}
isAnimationActive
diff --git a/components/dashboard/GoalStats.tsx b/components/dashboard/GoalStats.tsx
index 6c0571f..f3f6b06 100644
--- a/components/dashboard/GoalStats.tsx
+++ b/components/dashboard/GoalStats.tsx
@@ -52,7 +52,7 @@ export default function GoalStats({ goalCounts }: GoalStatsProps) {
Read documentation
diff --git a/components/dashboard/PerformanceStats.tsx b/components/dashboard/PerformanceStats.tsx
index 78ca72e..6b9b184 100644
--- a/components/dashboard/PerformanceStats.tsx
+++ b/components/dashboard/PerformanceStats.tsx
@@ -108,7 +108,7 @@ export default function PerformanceStats({ stats, performanceByPage, siteId, sta
const summaryText = `LCP ${Math.round(stats.lcp)} ms · CLS ${Number(stats.cls.toFixed(3))} · INP ${Math.round(stats.inp)} ms`
return (
-
+
{/* * One-line summary: Performance score + metric summary. Click to expand. */}
{
// Plausible-like colors based on provided SVG snippet
const isDark = resolvedTheme === 'dark'
- const defaultFill = isDark ? "#262626" : "#f5f5f5" // neutral-800 / neutral-100
- const defaultStroke = isDark ? "#171717" : "#ffffff" // neutral-900 / white
- const brandOrange = "#FD5E0F"
+ const defaultFill = isDark ? "var(--color-neutral-800)" : "var(--color-neutral-100)"
+ const defaultStroke = isDark ? "var(--color-neutral-900)" : "#ffffff"
+ const brandOrange = "var(--color-brand-orange)"
return (
@@ -97,7 +97,7 @@ const WorldMap = ({ data }: WorldMapProps) => {
{tooltipContent && (
{tooltipContent.content}
diff --git a/components/notifications/NotificationCenter.tsx b/components/notifications/NotificationCenter.tsx
index dad2ca4..19f9a4c 100644
--- a/components/notifications/NotificationCenter.tsx
+++ b/components/notifications/NotificationCenter.tsx
@@ -235,7 +235,7 @@ export default function NotificationCenter() {
setOpen(false)}
- className="flex items-center gap-1.5 text-sm text-neutral-500 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
+ className="flex items-center gap-2 text-sm text-neutral-500 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
>
Manage settings
diff --git a/components/settings/OrganizationSettings.tsx b/components/settings/OrganizationSettings.tsx
index 0febe51..327c857 100644
--- a/components/settings/OrganizationSettings.tsx
+++ b/components/settings/OrganizationSettings.tsx
@@ -320,7 +320,7 @@ export default function OrganizationSettings() {
// If no org ID, we are in personal organization context, so don't show org settings
if (!currentOrgId) {
return (
-
+
You are in your personal context. Switch to an Organization to manage its settings.
)
@@ -497,7 +497,7 @@ export default function OrganizationSettings() {
// handleTabChange is defined above
return (
-
+
Organization Settings
@@ -584,7 +584,7 @@ export default function OrganizationSettings() {
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.2 }}
- className="w-full bg-white dark:bg-neutral-900 rounded-2xl border border-neutral-200 dark:border-neutral-800 p-6 md:p-8 shadow-sm"
+ className="w-full bg-white dark:bg-neutral-900 rounded-2xl border border-neutral-200 dark:border-neutral-800 p-6 shadow-sm"
>
{activeTab === 'general' && (
@@ -606,7 +606,7 @@ export default function OrganizationSettings() {
minLength={2}
maxLength={50}
disabled={!isEditing}
- className={`bg-white dark:bg-neutral-900 ${!isEditing ? 'text-neutral-500' : ''}`}
+ className={`bg-white dark:bg-neutral-900 ${!isEditing ? 'text-neutral-500 dark:text-neutral-400' : ''}`}
/>
@@ -615,8 +615,8 @@ export default function OrganizationSettings() {
Organization Slug
-
- drop.ciphera.net/
+
+ pulse.ciphera.net/
-
+
Changing the slug will change your organization's URL.
@@ -670,7 +670,7 @@ export default function OrganizationSettings() {
Irreversible actions for this organization.
-
+
Delete Organization
Permanently delete this organization and all its data.
@@ -737,14 +737,14 @@ export default function OrganizationSettings() {
{/* Members List */}
-
Active Members
+
Active Members
{isLoadingMembers ? (
) : members.length === 0 ? (
-
No members found.
+
No members found.
) : (
members.map((member) => (
@@ -756,7 +756,7 @@ export default function OrganizationSettings() {
{member.user_email || 'Unknown User'}
-
+
Joined {new Date(member.joined_at).toLocaleDateString()}
@@ -781,7 +781,7 @@ export default function OrganizationSettings() {
{/* Pending Invitations */}
{invitations.length > 0 && (
-
Pending Invitations
+
Pending Invitations
{invitations.map((invite) => (
@@ -793,7 +793,7 @@ export default function OrganizationSettings() {
{invite.email}
-
+
Invited as {invite.role} • Expires {new Date(invite.expires_at).toLocaleDateString()}
@@ -825,8 +825,8 @@ export default function OrganizationSettings() {
) : !subscription ? (
-
-
Could not load subscription details.
+
+
Could not load subscription details.
Retry
) : (
@@ -834,7 +834,7 @@ export default function OrganizationSettings() {
{/* Trial notice */}
{subscription.subscription_status === 'trialing' && (
-
+
Your free trial ends on{' '}
@@ -854,7 +854,7 @@ export default function OrganizationSettings() {
{/* Past due notice */}
{subscription.subscription_status === 'past_due' && (
-
+
Payment past due
@@ -877,7 +877,7 @@ export default function OrganizationSettings() {
{/* Cancel-at-period-end notice */}
{subscription.cancel_at_period_end && (
-
+
Your subscription will end on{' '}
@@ -1024,7 +1024,7 @@ export default function OrganizationSettings() {
type="button"
onClick={handleManageSubscription}
disabled={isRedirectingToPortal}
- className="inline-flex items-center gap-1.5 text-sm text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
+ className="inline-flex items-center gap-2 text-sm text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
>
Payment method & invoices
@@ -1034,7 +1034,7 @@ export default function OrganizationSettings() {
setShowCancelPrompt(true)}
- className="inline-flex items-center gap-1.5 rounded-xl border border-neutral-200 dark:border-neutral-700 px-3.5 py-1.5 text-sm text-neutral-600 dark:text-neutral-400 hover:border-red-300 hover:text-red-600 dark:hover:border-red-800 dark:hover:text-red-400 transition-colors focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
+ className="inline-flex items-center gap-2 rounded-xl border border-neutral-200 dark:border-neutral-700 px-3.5 py-1.5 text-sm text-neutral-600 dark:text-neutral-400 hover:border-red-300 hover:text-red-600 dark:hover:border-red-800 dark:hover:text-red-400 transition-colors focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
>
Cancel subscription
@@ -1050,7 +1050,7 @@ export default function OrganizationSettings() {
) : invoices.length === 0 ? (
-
No invoices found.
+
No invoices found.
) : (
<>
{invoices.map((invoice) => (
@@ -1077,14 +1077,14 @@ export default function OrganizationSettings() {
{invoice.invoice_pdf && (
+ className="inline-flex items-center gap-2 px-2.5 py-1.5 text-xs font-medium text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange" title="Download PDF">
Download PDF
)}
{invoice.hosted_invoice_url && (
) : (
-
Notification categories
+
Notification categories
{notificationCategories.map((cat) => (
auditPageSize && (
-
+
{auditPage * auditPageSize + 1}–{Math.min((auditPage + 1) * auditPageSize, auditTotal)} of {auditTotal}
@@ -1502,7 +1502,7 @@ export default function OrganizationSettings() {
{plan.sites}
{isCurrentPlan && (
-
+
Current
)}
diff --git a/components/sites/VerificationModal.tsx b/components/sites/VerificationModal.tsx
index 1ba4564..1b360f1 100644
--- a/components/sites/VerificationModal.tsx
+++ b/components/sites/VerificationModal.tsx
@@ -11,7 +11,7 @@ import {
} from '@ciphera-net/ui'
import { Site } from '@/lib/api/sites'
import { getRealtime } from '@/lib/api/stats'
-import { toast } from '@ciphera-net/ui'
+import { toast, Button } from '@ciphera-net/ui'
interface VerificationModalProps {
isOpen: boolean
@@ -130,15 +130,12 @@ export default function VerificationModal({ isOpen, onClose, site }: Verificatio
-
+
Open Website & Verify
-
+
-
+
)}
@@ -172,12 +169,9 @@ export default function VerificationModal({ isOpen, onClose, site }: Verificatio
We are successfully receiving data from your website.
-
+
Done
-
+
)}
@@ -205,18 +199,12 @@ export default function VerificationModal({ isOpen, onClose, site }: Verificatio
-
+
Close
-
-
+
+
Try Again
-
+
)}
diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md
index 030103d..b6cfa30 100644
--- a/docs/DESIGN_SYSTEM.md
+++ b/docs/DESIGN_SYSTEM.md
@@ -817,9 +817,9 @@ Always test both light and dark modes:
### VS Code-Style Syntax Highlighting
```tsx
-
+
{/* Header bar */}
-
+
@@ -973,7 +973,6 @@ presets: [
**Dashboard:** Chart, TopPages, TopReferrers, Locations, TechSpecs, Campaigns, Goals, Performance
**Settings:** OrganizationSettings, ProfileSettings
**Sites:** SiteList, VerificationModal
-**Tools:** UtmBuilder
---
diff --git a/package-lock.json b/package-lock.json
index 9c1256e..eb8f7d6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,14 +1,14 @@
{
"name": "pulse-frontend",
- "version": "0.7.0-alpha",
+ "version": "0.9.0-alpha",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pulse-frontend",
- "version": "0.7.0-alpha",
+ "version": "0.9.0-alpha",
"dependencies": {
- "@ciphera-net/ui": "^0.0.57",
+ "@ciphera-net/ui": "^0.0.58",
"@ducanh2912/next-pwa": "^10.2.9",
"@radix-ui/react-icons": "^1.3.0",
"@stripe/react-stripe-js": "^5.6.0",
@@ -1541,9 +1541,9 @@
}
},
"node_modules/@ciphera-net/ui": {
- "version": "0.0.57",
- "resolved": "https://npm.pkg.github.com/download/@ciphera-net/ui/0.0.57/1839d6ea6184b8aefa921ceeaa1d1d50d532e6a8",
- "integrity": "sha512-sgdBajwBgmZnqnZ/kJ1PYpb4XR2j/yPXw1xHyMpNaLa/wLYXqylJ1ffQ3aRE7BB37IkGgDO+fzeQVjYnJvHSBA==",
+ "version": "0.0.58",
+ "resolved": "https://npm.pkg.github.com/download/@ciphera-net/ui/0.0.58/ac48a989da2db79880ce2fa7f89b63a62e2b68c9",
+ "integrity": "sha512-cvptYjs+E72EQvM5YGx5pp4SOiyJ7t5qv5NSRfoFxtcTCwR4sKUN4SoZUA+HV3tLlq4qXXHAB98E7qgbBRIn+Q==",
"dependencies": {
"@radix-ui/react-icons": "^1.3.0",
"clsx": "^2.1.0",
diff --git a/package.json b/package.json
index 8ed7d8a..10fb548 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pulse-frontend",
- "version": "0.9.0-alpha",
+ "version": "0.10.0-alpha",
"private": true,
"scripts": {
"dev": "next dev",
@@ -10,7 +10,7 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
- "@ciphera-net/ui": "^0.0.57",
+ "@ciphera-net/ui": "^0.0.58",
"@ducanh2912/next-pwa": "^10.2.9",
"@radix-ui/react-icons": "^1.3.0",
"@stripe/react-stripe-js": "^5.6.0",