Enforce recipient-bound single-use invites and fix issue card layout; clean release tooling
Magent CI/CD / verify (push) Successful in 10m31s
Magent CI/CD / deploy-prod (push) Skipped
Magent CI/CD / deploy-beta (push) Skipped

This commit is contained in:
2026-09-07 19:59:51 +12:00
parent 13edcb8136
commit a3b5759708
19 changed files with 439 additions and 305 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ export default function InviteDeliveryChoice({ value, onChange }: {
<span className="delivery-choice-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
{method === 'manual' ? <><path d="M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-2 2" /><path d="M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l2-2" /></> : <><rect x="3" y="5" width="18" height="14" rx="3" /><path d="m3 7 9 6 9-6" /></>}
</svg></span>
<span className="delivery-choice-copy"><strong>{method === 'manual' ? 'Copy a link' : 'Send an email'}</strong><small>{method === 'manual' ? 'Share it yourself. No email needed.' : 'Well send the invite. You get the link too.'}</small></span>
<span className="delivery-choice-copy"><strong>{method === 'manual' ? 'Copy a link' : 'Send an email'}</strong><small>{method === 'manual' ? 'They add their email when signing up.' : 'One use, tied to the recipients email. You get the link too.'}</small></span>
<span className="delivery-choice-check" aria-hidden="true">{value === method ? '✓' : ''}</span>
</button>)}
</div>
-59
View File
@@ -1,59 +0,0 @@
'use client'
import { useEffect, useState } from 'react'
const STORAGE_KEY = 'magent_theme'
const getPreferredTheme = () => {
if (typeof window === 'undefined') return 'dark'
const stored = window.localStorage.getItem(STORAGE_KEY)
if (stored === 'light' || stored === 'dark') {
return stored
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
const applyTheme = (theme: string) => {
if (typeof document === 'undefined') return
document.documentElement.setAttribute('data-theme', theme)
}
export default function ThemeToggle() {
const [theme, setTheme] = useState<'light' | 'dark'>('dark')
useEffect(() => {
const preferred = getPreferredTheme()
setTheme(preferred)
applyTheme(preferred)
}, [])
const toggle = () => {
const next = theme === 'dark' ? 'light' : 'dark'
setTheme(next)
applyTheme(next)
if (typeof window !== 'undefined') {
window.localStorage.setItem(STORAGE_KEY, next)
}
}
return (
<button
type="button"
className="theme-toggle"
onClick={toggle}
aria-label={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}
title={theme === 'dark' ? 'Light mode' : 'Dark mode'}
>
{theme === 'dark' ? (
<svg viewBox="0 0 24 24" aria-hidden="true">
<circle cx="12" cy="12" r="4" />
<path d="M12 2v3M12 19v3M4.22 4.22l2.12 2.12M17.66 17.66l2.12 2.12M2 12h3M19 12h3M4.22 19.78l2.12-2.12M17.66 6.34l2.12-2.12" />
</svg>
) : (
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M21 14.5A8.5 8.5 0 0 1 9.5 3a8.5 8.5 0 1 0 11.5 11.5z" />
</svg>
)}
</button>
)
}