feat: enhance UI components by updating button styles and improving layout in ToolsPage and Campaigns; refactor UtmBuilder for better input handling and user experience

This commit is contained in:
Usman Baig
2026-02-04 20:40:16 +01:00
parent 210ea7b754
commit 159f514b71
3 changed files with 29 additions and 30 deletions

View File

@@ -6,7 +6,7 @@ export default function ToolsPage() {
return ( return (
<div className="max-w-2xl mx-auto py-10 px-4"> <div className="max-w-2xl mx-auto py-10 px-4">
<h1 className="text-2xl font-bold mb-6 text-neutral-900 dark:text-white">Tools</h1> <h1 className="text-2xl font-bold mb-6 text-neutral-900 dark:text-white">Tools</h1>
<div className="bg-white dark:bg-neutral-900 p-6 rounded-xl border border-neutral-200 dark:border-neutral-800"> <div className="bg-white dark:bg-neutral-900 p-6 rounded-2xl border border-neutral-200 dark:border-neutral-800">
<h2 className="text-lg font-semibold mb-4 text-neutral-900 dark:text-white">UTM Campaign Builder</h2> <h2 className="text-lg font-semibold mb-4 text-neutral-900 dark:text-white">UTM Campaign Builder</h2>
<UtmBuilder /> <UtmBuilder />
</div> </div>

View File

@@ -3,7 +3,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import Link from 'next/link' import Link from 'next/link'
import { formatNumber } from '@/lib/utils/format' import { formatNumber } from '@/lib/utils/format'
import { Modal, ArrowRightIcon } from '@ciphera-net/ui' import { Modal, ArrowRightIcon, Button } from '@ciphera-net/ui'
import { getCampaigns, CampaignStat } from '@/lib/api/stats' import { getCampaigns, CampaignStat } from '@/lib/api/stats'
import { FaBullhorn } from 'react-icons/fa' import { FaBullhorn } from 'react-icons/fa'
import { PlusIcon } from '@radix-ui/react-icons' import { PlusIcon } from '@radix-ui/react-icons'
@@ -70,21 +70,23 @@ export default function Campaigns({ siteId, dateRange }: CampaignsProps) {
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white"> <h3 className="text-lg font-semibold text-neutral-900 dark:text-white">
Campaigns Campaigns
</h3> </h3>
<div className="flex items-center gap-3"> <div className="flex items-center gap-2">
<button <Button
variant="ghost"
onClick={() => setIsBuilderOpen(true)} onClick={() => setIsBuilderOpen(true)}
className="flex items-center gap-1.5 text-xs font-medium text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white transition-colors" className="h-8 px-3 text-xs gap-1.5"
> >
<PlusIcon className="w-3.5 h-3.5" /> <PlusIcon className="w-3.5 h-3.5" />
Build URL Build URL
</button> </Button>
{showViewAll && ( {showViewAll && (
<button <Button
variant="ghost"
onClick={() => setIsModalOpen(true)} 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="h-8 px-3 text-xs"
> >
View All View All
</button> </Button>
)} )}
</div> </div>
</div> </div>

View File

@@ -3,7 +3,7 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { CopyIcon, CheckIcon } from '@radix-ui/react-icons' import { CopyIcon, CheckIcon } from '@radix-ui/react-icons'
import { listSites, Site } from '@/lib/api/sites' import { listSites, Site } from '@/lib/api/sites'
import { Select } from '@ciphera-net/ui' import { Select, Input, Button } from '@ciphera-net/ui'
interface UtmBuilderProps { interface UtmBuilderProps {
initialSiteId?: string initialSiteId?: string
@@ -132,62 +132,58 @@ export default function UtmBuilder({ initialSiteId }: UtmBuilderProps) {
)} )}
<div> <div>
<label className="block text-sm font-medium mb-1 text-neutral-900 dark:text-white">Website URL *</label> <label className="block text-sm font-medium mb-1.5 text-neutral-900 dark:text-white">Website URL *</label>
{selectedSite ? ( {selectedSite ? (
<div className="flex rounded-xl shadow-sm"> <div className="flex rounded-xl shadow-sm transition-all duration-200 focus-within:ring-4 focus-within:ring-brand-orange/10 focus-within:border-brand-orange hover:border-brand-orange/50 border border-neutral-200 dark:border-neutral-800">
<span className="inline-flex items-center px-3 rounded-l-xl border border-r-0 border-neutral-200 dark:border-neutral-800 bg-neutral-100 dark:bg-neutral-800 text-neutral-500 text-sm"> <span className="inline-flex items-center px-4 rounded-l-xl border-r border-neutral-200 dark:border-neutral-800 bg-neutral-100 dark:bg-neutral-900 text-neutral-500 text-sm select-none">
https://{selectedSite.domain} https://{selectedSite.domain}
</span> </span>
<input <input
type="text" type="text"
className="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-xl border border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/50 focus:ring-2 focus:ring-brand-orange/20 outline-none transition-all text-neutral-900 dark:text-white sm:text-sm" className="flex-1 min-w-0 block w-full px-4 py-3 rounded-none rounded-r-xl bg-neutral-50/50 dark:bg-neutral-900/50 outline-none transition-all text-neutral-900 dark:text-white text-sm placeholder:text-neutral-400"
placeholder="/blog/post-1" placeholder="/blog/post-1"
value={getCurrentPath()} value={getCurrentPath()}
onChange={handlePathChange} onChange={handlePathChange}
/> />
</div> </div>
) : ( ) : (
<input <Input
name="url" name="url"
placeholder="https://example.com/landing-page" placeholder="https://example.com/landing-page"
className="w-full p-2 rounded-xl border border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/50 focus:ring-2 focus:ring-brand-orange/20 outline-none transition-all text-neutral-900 dark:text-white"
value={values.url} value={values.url}
onChange={handleChange} onChange={handleChange}
/> />
)} )}
<p className="text-xs text-neutral-500 mt-1"> <p className="text-xs text-neutral-500 mt-1.5">
You can add specific paths (e.g., /blog/post-1) to the URL above. You can add specific paths (e.g., /blog/post-1) to the URL above.
</p> </p>
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium mb-1 text-neutral-900 dark:text-white">Source *</label> <label className="block text-sm font-medium mb-1.5 text-neutral-900 dark:text-white">Source *</label>
<input <Input
name="source" name="source"
placeholder="google, newsletter" placeholder="google, newsletter"
className="w-full p-2 rounded-xl border border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/50 focus:ring-2 focus:ring-brand-orange/20 outline-none transition-all text-neutral-900 dark:text-white"
value={values.source} value={values.source}
onChange={handleChange} onChange={handleChange}
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium mb-1 text-neutral-900 dark:text-white">Medium *</label> <label className="block text-sm font-medium mb-1.5 text-neutral-900 dark:text-white">Medium *</label>
<input <Input
name="medium" name="medium"
placeholder="cpc, email" placeholder="cpc, email"
className="w-full p-2 rounded-xl border border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/50 focus:ring-2 focus:ring-brand-orange/20 outline-none transition-all text-neutral-900 dark:text-white"
value={values.medium} value={values.medium}
onChange={handleChange} onChange={handleChange}
/> />
</div> </div>
</div> </div>
<div> <div>
<label className="block text-sm font-medium mb-1 text-neutral-900 dark:text-white">Campaign Name *</label> <label className="block text-sm font-medium mb-1.5 text-neutral-900 dark:text-white">Campaign Name *</label>
<input <Input
name="campaign" name="campaign"
placeholder="spring_sale" placeholder="spring_sale"
className="w-full p-2 rounded-xl border border-neutral-200 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/50 focus:ring-2 focus:ring-brand-orange/20 outline-none transition-all text-neutral-900 dark:text-white"
value={values.campaign} value={values.campaign}
onChange={handleChange} onChange={handleChange}
/> />
@@ -197,13 +193,14 @@ export default function UtmBuilder({ initialSiteId }: UtmBuilderProps) {
{generatedUrl && ( {generatedUrl && (
<div className="mt-6 p-4 bg-neutral-50 dark:bg-neutral-900 rounded-xl border border-neutral-200 dark:border-neutral-800 flex items-center justify-between group"> <div className="mt-6 p-4 bg-neutral-50 dark:bg-neutral-900 rounded-xl border border-neutral-200 dark:border-neutral-800 flex items-center justify-between group">
<code className="text-sm break-all text-brand-orange font-mono">{generatedUrl}</code> <code className="text-sm break-all text-brand-orange font-mono">{generatedUrl}</code>
<button <Button
variant="secondary"
onClick={copyToClipboard} onClick={copyToClipboard}
className="ml-2 p-2 hover:bg-neutral-200 dark:hover:bg-neutral-800 rounded-lg transition-colors text-neutral-500 hover:text-neutral-900 dark:hover:text-white" className="ml-4 shrink-0 h-9 w-9 p-0 rounded-lg"
title="Copy to clipboard" title="Copy to clipboard"
> >
{copied ? <CheckIcon className="w-5 h-5 text-green-500" /> : <CopyIcon className="w-5 h-5" />} {copied ? <CheckIcon className="w-4 h-4 text-green-500" /> : <CopyIcon className="w-4 h-4" />}
</button> </Button>
</div> </div>
)} )}
</div> </div>