feat: enforce tighter character limits for site, funnel, and monitor names to improve UI consistency and usability

This commit is contained in:
Usman Baig
2026-02-22 20:07:00 +01:00
parent da0366603e
commit acac536590
5 changed files with 11 additions and 10 deletions

View File

@@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
- **Graceful error recovery.** If a page crashes, you now see a friendly error screen with a "Try again" button instead of a blank white page. Each section of the app has its own error message so you know exactly what went wrong. - **Graceful error recovery.** If a page crashes, you now see a friendly error screen with a "Try again" button instead of a blank white page. Each section of the app has its own error message so you know exactly what went wrong.
- **Security headers.** All pages now include clickjacking protection, MIME-sniffing prevention, a strict referrer policy, and HSTS. Browser APIs like camera and microphone are explicitly disabled. - **Security headers.** All pages now include clickjacking protection, MIME-sniffing prevention, a strict referrer policy, and HSTS. Browser APIs like camera and microphone are explicitly disabled.
- **Better form experience.** Forms now auto-focus the first field when they open, text inputs enforce character limits with a visible counter when you're close, and the settings page warns you before navigating away with unsaved changes. - **Better form experience.** Forms now auto-focus the first field when they open, text inputs enforce character limits with a visible counter when you're close, and the settings page warns you before navigating away with unsaved changes.
- **Tighter name limits.** Site, funnel, and monitor names are now capped at 100 characters instead of 255 — long enough for any real name, short enough to not break the UI.
## [0.10.0-alpha] - 2026-02-21 ## [0.10.0-alpha] - 2026-02-21

View File

@@ -122,10 +122,10 @@ export default function CreateFunnelPage() {
placeholder="e.g. Signup Flow" placeholder="e.g. Signup Flow"
autoFocus autoFocus
required required
maxLength={255} maxLength={100}
/> />
{name.length > 200 && ( {name.length > 80 && (
<span className={`text-xs tabular-nums mt-1 ${name.length > 240 ? 'text-amber-500' : 'text-neutral-400'}`}>{name.length}/255</span> <span className={`text-xs tabular-nums mt-1 ${name.length > 90 ? 'text-amber-500' : 'text-neutral-400'}`}>{name.length}/100</span>
)} )}
</div> </div>
<div> <div>

View File

@@ -501,14 +501,14 @@ export default function SiteSettingsPage() {
type="text" type="text"
id="name" id="name"
required required
maxLength={255} maxLength={100}
value={formData.name} value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })} onChange={(e) => setFormData({ ...formData, name: e.target.value })}
className="w-full px-4 py-2 border border-neutral-200 dark:border-neutral-800 rounded-lg bg-neutral-50/50 dark:bg-neutral-900/50 focus:bg-white dark:focus:bg-neutral-900 className="w-full px-4 py-2 border border-neutral-200 dark:border-neutral-800 rounded-lg bg-neutral-50/50 dark:bg-neutral-900/50 focus:bg-white dark:focus:bg-neutral-900
focus:border-brand-orange focus:ring-4 focus:ring-brand-orange/10 outline-none transition-all duration-200 dark:text-white" focus:border-brand-orange focus:ring-4 focus:ring-brand-orange/10 outline-none transition-all duration-200 dark:text-white"
/> />
{formData.name.length > 200 && ( {formData.name.length > 80 && (
<span className={`text-xs tabular-nums ${formData.name.length > 240 ? 'text-amber-500' : 'text-neutral-400'}`}>{formData.name.length}/255</span> <span className={`text-xs tabular-nums ${formData.name.length > 90 ? 'text-amber-500' : 'text-neutral-400'}`}>{formData.name.length}/100</span>
)} )}
</div> </div>

View File

@@ -938,11 +938,11 @@ function MonitorForm({
onChange={(e) => setFormData({ ...formData, name: e.target.value })} onChange={(e) => setFormData({ ...formData, name: e.target.value })}
placeholder="e.g. API, Website, CDN" placeholder="e.g. API, Website, CDN"
autoFocus autoFocus
maxLength={255} maxLength={100}
className="w-full px-3 py-2 rounded-lg border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800 text-neutral-900 dark:text-white placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:border-transparent text-sm" className="w-full px-3 py-2 rounded-lg border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800 text-neutral-900 dark:text-white placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:border-transparent text-sm"
/> />
{formData.name.length > 200 && ( {formData.name.length > 80 && (
<span className={`text-xs tabular-nums mt-1 ${formData.name.length > 240 ? 'text-amber-500' : 'text-neutral-400'}`}>{formData.name.length}/255</span> <span className={`text-xs tabular-nums mt-1 ${formData.name.length > 90 ? 'text-amber-500' : 'text-neutral-400'}`}>{formData.name.length}/100</span>
)} )}
</div> </div>

View File

@@ -192,7 +192,7 @@ export default function NewSitePage() {
id="name" id="name"
required required
autoFocus autoFocus
maxLength={255} maxLength={100}
value={formData.name} value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })} onChange={(e) => setFormData({ ...formData, name: e.target.value })}
placeholder="My Website" placeholder="My Website"