first commit

Made-with: Cursor
This commit is contained in:
Michilis
2026-04-01 02:46:53 +00:00
commit 76210db03d
126 changed files with 20208 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
"use client";
import { useEffect, useState } from "react";
import { api } from "@/lib/api";
import { Save } from "lucide-react";
const settingFields = [
{ key: "site_title", label: "Site Title" },
{ key: "site_tagline", label: "Site Tagline" },
{ key: "telegram_link", label: "Telegram Link" },
{ key: "nostr_link", label: "Nostr Link" },
{ key: "x_link", label: "X Link" },
{ key: "youtube_link", label: "YouTube Link" },
{ key: "discord_link", label: "Discord Link" },
{ key: "linkedin_link", label: "LinkedIn Link" },
];
export default function SettingsPage() {
const [settings, setSettings] = useState<Record<string, string>>({});
const [original, setOriginal] = useState<Record<string, string>>({});
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [error, setError] = useState("");
const [success, setSuccess] = useState("");
useEffect(() => {
async function load() {
try {
const data = await api.getSettings();
setSettings(data);
setOriginal(data);
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
}
load();
}, []);
const handleSave = async () => {
setSaving(true);
setError("");
setSuccess("");
try {
const changed = Object.entries(settings).filter(
([key, value]) => value !== (original[key] || "")
);
await Promise.all(
changed.map(([key, value]) => api.updateSetting(key, value))
);
setOriginal({ ...settings });
setSuccess("Settings saved successfully.");
} catch (err: any) {
setError(err.message);
} finally {
setSaving(false);
}
};
const hasChanges = Object.entries(settings).some(
([key, value]) => value !== (original[key] || "")
);
if (loading) {
return (
<div className="flex items-center justify-center min-h-[60vh]">
<div className="text-on-surface/50">Loading settings...</div>
</div>
);
}
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold text-on-surface">Site Settings</h1>
{error && <p className="text-error text-sm">{error}</p>}
{success && <p className="text-green-400 text-sm">{success}</p>}
<div className="bg-surface-container-low rounded-xl p-6 space-y-4">
{settingFields.map((field) => (
<div key={field.key}>
<label className="block text-on-surface/70 text-sm mb-1">{field.label}</label>
<input
value={settings[field.key] || ""}
onChange={(e) =>
setSettings({ ...settings, [field.key]: e.target.value })
}
className="bg-surface-container-highest text-on-surface rounded-lg px-4 py-3 w-full focus:outline-none focus:ring-1 focus:ring-primary/40"
/>
</div>
))}
<button
onClick={handleSave}
disabled={saving || !hasChanges}
className="flex items-center gap-2 px-6 py-3 rounded-lg bg-gradient-to-r from-primary to-primary-container text-on-primary font-semibold text-sm hover:opacity-90 transition-opacity disabled:opacity-50 mt-2"
>
<Save size={16} />
{saving ? "Saving..." : "Save Settings"}
</button>
</div>
</div>
);
}