Merge pull request #12 from ciphera-net/staging
[PULSE-44] Design consistency audit fixes
This commit is contained in:
@@ -51,13 +51,13 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
|
||||
© 2024-{year} Ciphera. All rights reserved.
|
||||
</div>
|
||||
<div className="flex gap-6 text-sm font-medium text-neutral-600 dark:text-neutral-300">
|
||||
<Component href="/about" className="hover:text-brand-orange transition-colors">
|
||||
<Component href="/about" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
|
||||
Why {appName}
|
||||
</Component>
|
||||
<Component href="/pricing" className="hover:text-brand-orange transition-colors">
|
||||
<Component href="/pricing" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
|
||||
Pricing
|
||||
</Component>
|
||||
<Component href="/faq" className="hover:text-brand-orange transition-colors">
|
||||
<Component href="/faq" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
|
||||
FAQ
|
||||
</Component>
|
||||
</div>
|
||||
@@ -102,7 +102,7 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
|
||||
href="https://github.com/ciphera-net"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="w-9 h-9 rounded-lg bg-neutral-100 dark:bg-neutral-800 flex items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange hover:bg-neutral-200 dark:hover:bg-neutral-700 transition-colors"
|
||||
className="w-9 h-9 rounded-lg bg-neutral-100 dark:bg-neutral-800 flex items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange hover:bg-neutral-200 dark:hover:bg-neutral-700 transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange"
|
||||
aria-label="GitHub"
|
||||
>
|
||||
<GithubIcon className="w-5 h-5" />
|
||||
@@ -111,7 +111,7 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
|
||||
href="https://x.com/cipheranet"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="w-9 h-9 rounded-lg bg-neutral-100 dark:bg-neutral-800 flex items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange hover:bg-neutral-200 dark:hover:bg-neutral-700 transition-colors"
|
||||
className="w-9 h-9 rounded-lg bg-neutral-100 dark:bg-neutral-800 flex items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange hover:bg-neutral-200 dark:hover:bg-neutral-700 transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange"
|
||||
aria-label="X (Twitter)"
|
||||
>
|
||||
<TwitterIcon className="w-5 h-5" />
|
||||
@@ -130,14 +130,14 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
{link.name}
|
||||
</a>
|
||||
) : (
|
||||
<Component
|
||||
href={link.href}
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
{link.name}
|
||||
</Component>
|
||||
@@ -158,14 +158,14 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
{link.name}
|
||||
</a>
|
||||
) : (
|
||||
<Component
|
||||
href={link.href}
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
{link.name}
|
||||
</Component>
|
||||
@@ -186,14 +186,14 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
{link.name}
|
||||
</a>
|
||||
) : (
|
||||
<Component
|
||||
href={link.href}
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors"
|
||||
className="text-sm text-neutral-600 dark:text-neutral-400 hover:text-brand-orange dark:hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
{link.name}
|
||||
</Component>
|
||||
|
||||
@@ -219,7 +219,7 @@ export default function PricingSection() {
|
||||
transition={{ duration: 0.5 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h2 className="text-4xl md:text-5xl font-bold text-neutral-900 dark:text-white mb-6 tracking-tight">
|
||||
<h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-6">
|
||||
Transparent Pricing
|
||||
</h2>
|
||||
<p className="text-xl text-neutral-600 dark:text-neutral-400">
|
||||
|
||||
@@ -96,18 +96,20 @@ export default function ContentStats({ topPages, entryPages, exitPages, domain,
|
||||
{showViewAll && (
|
||||
<button
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors"
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
View All
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex p-1 bg-neutral-100 dark:bg-neutral-800 rounded-lg">
|
||||
<div className="flex p-1 bg-neutral-100 dark:bg-neutral-800 rounded-lg" role="tablist" aria-label="Content view tabs">
|
||||
{(['top_pages', 'entry_pages', 'exit_pages'] as Tab[]).map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => setActiveTab(tab)}
|
||||
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors ${
|
||||
role="tab"
|
||||
aria-selected={activeTab === tab}
|
||||
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange ${
|
||||
activeTab === tab
|
||||
? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm'
|
||||
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white'
|
||||
|
||||
@@ -196,18 +196,20 @@ export default function Locations({ countries, cities, regions, geoDataLevel = '
|
||||
{showViewAll && (
|
||||
<button
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors"
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
View All
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex p-1 bg-neutral-100 dark:bg-neutral-800 rounded-lg">
|
||||
<div className="flex p-1 bg-neutral-100 dark:bg-neutral-800 rounded-lg" role="tablist" aria-label="Location view tabs">
|
||||
{(['map', 'countries', 'regions', 'cities'] as Tab[]).map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => setActiveTab(tab)}
|
||||
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors capitalize ${
|
||||
role="tab"
|
||||
aria-selected={activeTab === tab}
|
||||
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors capitalize focus:outline-none focus:ring-2 focus:ring-brand-orange ${
|
||||
activeTab === tab
|
||||
? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm'
|
||||
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white'
|
||||
|
||||
@@ -119,18 +119,20 @@ export default function TechSpecs({ browsers, os, devices, screenResolutions, co
|
||||
{showViewAll && (
|
||||
<button
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors"
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
View All
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex p-1 bg-neutral-100 dark:bg-neutral-800 rounded-lg">
|
||||
<div className="flex p-1 bg-neutral-100 dark:bg-neutral-800 rounded-lg" role="tablist" aria-label="Technology view tabs">
|
||||
{(['browsers', 'os', 'devices', 'screens'] as Tab[]).map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => setActiveTab(tab)}
|
||||
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors capitalize ${
|
||||
role="tab"
|
||||
aria-selected={activeTab === tab}
|
||||
className={`px-3 py-1 text-xs font-medium rounded-lg transition-colors capitalize focus:outline-none focus:ring-2 focus:ring-brand-orange ${
|
||||
activeTab === tab
|
||||
? 'bg-white dark:bg-neutral-700 text-neutral-900 dark:text-white shadow-sm'
|
||||
: 'text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white'
|
||||
|
||||
@@ -63,7 +63,7 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI
|
||||
{showViewAll && (
|
||||
<button
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors"
|
||||
className="text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded"
|
||||
>
|
||||
View All
|
||||
</button>
|
||||
|
||||
@@ -353,7 +353,7 @@ export default function OrganizationSettings() {
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto space-y-8">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-neutral-900 dark:text-white">Organization Settings</h1>
|
||||
<h1 className="text-2xl font-bold text-neutral-900 dark:text-white">Organization Settings</h1>
|
||||
<p className="mt-2 text-neutral-600 dark:text-neutral-400">
|
||||
Manage your organization workspace and members.
|
||||
</p>
|
||||
@@ -361,10 +361,12 @@ export default function OrganizationSettings() {
|
||||
|
||||
<div className="flex flex-col md:flex-row gap-8">
|
||||
{/* Sidebar Navigation */}
|
||||
<nav className="w-full md:w-64 flex-shrink-0 space-y-1">
|
||||
<nav className="w-full md:w-64 flex-shrink-0 space-y-1" role="tablist" aria-label="Organization settings sections">
|
||||
<button
|
||||
onClick={() => handleTabChange('general')}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||
role="tab"
|
||||
aria-selected={activeTab === 'general'}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${
|
||||
activeTab === 'general'
|
||||
? 'bg-brand-orange/10 text-brand-orange'
|
||||
: 'text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-800'
|
||||
@@ -375,7 +377,9 @@ export default function OrganizationSettings() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleTabChange('members')}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||
role="tab"
|
||||
aria-selected={activeTab === 'members'}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${
|
||||
activeTab === 'members'
|
||||
? 'bg-brand-orange/10 text-brand-orange'
|
||||
: 'text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-800'
|
||||
@@ -386,7 +390,9 @@ export default function OrganizationSettings() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleTabChange('billing')}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||
role="tab"
|
||||
aria-selected={activeTab === 'billing'}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${
|
||||
activeTab === 'billing'
|
||||
? 'bg-brand-orange/10 text-brand-orange'
|
||||
: 'text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-800'
|
||||
@@ -397,7 +403,9 @@ export default function OrganizationSettings() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleTabChange('audit')}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||
role="tab"
|
||||
aria-selected={activeTab === 'audit'}
|
||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2 ${
|
||||
activeTab === 'audit'
|
||||
? 'bg-brand-orange/10 text-brand-orange'
|
||||
: 'text-neutral-600 dark:text-neutral-400 hover:bg-neutral-100 dark:hover:bg-neutral-800'
|
||||
@@ -420,9 +428,9 @@ export default function OrganizationSettings() {
|
||||
{activeTab === 'general' && (
|
||||
<div className="space-y-12">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-neutral-900 dark:text-white mb-1">General Information</h2>
|
||||
<h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-1">General Information</h2>
|
||||
<p className="text-sm text-neutral-500 dark:text-neutral-400">Basic details about your organization.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleUpdateOrg} className="space-y-4">
|
||||
<div className="space-y-1.5">
|
||||
@@ -497,7 +505,7 @@ export default function OrganizationSettings() {
|
||||
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-red-600 dark:text-red-500 mb-1">Danger Zone</h2>
|
||||
<h2 className="text-2xl font-bold text-red-600 dark:text-red-500 mb-1">Danger Zone</h2>
|
||||
<p className="text-sm text-neutral-500 dark:text-neutral-400">Irreversible actions for this organization.</p>
|
||||
</div>
|
||||
|
||||
@@ -521,7 +529,7 @@ export default function OrganizationSettings() {
|
||||
<div className="space-y-12">
|
||||
{/* Invite Section */}
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-neutral-900 dark:text-white mb-1">Organization Members</h2>
|
||||
<h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-1">Organization Members</h2>
|
||||
<p className="text-sm text-neutral-500 dark:text-neutral-400 mb-6">Manage who has access to this organization.</p>
|
||||
|
||||
<div className="bg-neutral-50 dark:bg-neutral-900/50 border border-neutral-200 dark:border-neutral-800 rounded-2xl p-4">
|
||||
@@ -647,7 +655,7 @@ export default function OrganizationSettings() {
|
||||
{activeTab === 'billing' && (
|
||||
<div className="space-y-12">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-neutral-900 dark:text-white mb-1">Billing & Subscription</h2>
|
||||
<h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-1">Billing & Subscription</h2>
|
||||
<p className="text-sm text-neutral-500 dark:text-neutral-400">Manage your subscription plan and payment methods.</p>
|
||||
</div>
|
||||
|
||||
@@ -832,7 +840,7 @@ export default function OrganizationSettings() {
|
||||
{activeTab === 'audit' && (
|
||||
<div className="space-y-12">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-neutral-900 dark:text-white mb-1">Audit log</h2>
|
||||
<h2 className="text-2xl font-bold text-neutral-900 dark:text-white mb-1">Audit log</h2>
|
||||
<p className="text-sm text-neutral-500 dark:text-neutral-400">Who did what and when for this organization.</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function SiteList({ sites, loading, onDelete }: SiteListProps) {
|
||||
if (sites.length === 0) {
|
||||
return (
|
||||
<div className="rounded-lg border border-dashed border-neutral-300 dark:border-neutral-700 p-12 text-center">
|
||||
<h3 className="text-lg font-medium text-neutral-900 dark:text-white">No sites yet</h3>
|
||||
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white">No sites yet</h3>
|
||||
<p className="mt-2 text-sm text-neutral-500 dark:text-neutral-400">Create your first site to get started.</p>
|
||||
</div>
|
||||
)
|
||||
@@ -105,7 +105,7 @@ export default function SiteList({ sites, loading, onDelete }: SiteListProps) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onDelete(site.id)}
|
||||
className="flex items-center justify-center rounded-lg border border-neutral-200 px-3 hover:bg-neutral-50 dark:border-neutral-700 dark:hover:bg-neutral-800 text-neutral-500 hover:text-red-600 dark:hover:text-red-400 transition-colors"
|
||||
className="flex items-center justify-center rounded-lg border border-neutral-200 px-3 hover:bg-neutral-50 dark:border-neutral-700 dark:hover:bg-neutral-800 text-neutral-500 hover:text-red-600 dark:hover:text-red-400 transition-colors focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
||||
title="Delete Site"
|
||||
>
|
||||
<SettingsIcon className="h-4 w-4" />
|
||||
|
||||
Reference in New Issue
Block a user