Skip to content

Commit 96f5e0e

Browse files
committed
ADD - admin panel UI
1 parent a9bb368 commit 96f5e0e

4 files changed

Lines changed: 406 additions & 9 deletions

File tree

client/src/App.jsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import { Hero } from "./components/Hero.jsx";
55
import { MainPage } from "./components/MainPage.jsx";
66
import { ProjectsPage } from "./components/ProjectsPage.jsx";
77
import { ShopPage } from "./components/ShopPage.jsx";
8-
import { TestPage } from "./components/TestPage.jsx";
8+
import { AdminPage } from "./components/AdminPage.jsx";
99
import { UserAreaPage } from "./components/UserAreaPage.jsx";
1010

11-
const PROTECTED = new Set(["/main", "/shop", "/projects", "/faq", "/user", "/test"]);
11+
const PROTECTED = new Set(["/main", "/shop", "/projects", "/faq", "/user", "/test", "/admin"]);
12+
const ADMIN_ONLY = new Set(["/admin"]);
1213

1314
export default function App() {
1415
const [auth, setAuth] = useState({ status: "loading", user: null });
@@ -43,6 +44,11 @@ export default function App() {
4344
return null;
4445
}
4546

47+
if (ADMIN_ONLY.has(pathname) && auth.user?.role !== "admin") {
48+
window.location.replace("/main");
49+
return null;
50+
}
51+
4652
if (pathname === "/" && auth.user) {
4753
window.location.replace("/main");
4854
return null;
@@ -60,8 +66,8 @@ export default function App() {
6066
page = <MainPage />;
6167
break;
6268
case "/test":
63-
page = <TestPage />;
64-
break;
69+
window.location.replace("/admin#admin-airtable-sync");
70+
return null;
6571
case "/projects":
6672
page = <ProjectsPage />;
6773
break;
@@ -74,6 +80,9 @@ export default function App() {
7480
case "/user":
7581
page = <UserAreaPage />;
7682
break;
83+
case "/admin":
84+
page = <AdminPage />;
85+
break;
7786
default:
7887
page = <Hero />;
7988
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
.admin-page {
2+
position: fixed;
3+
inset: 0;
4+
z-index: 0;
5+
overflow-y: auto;
6+
}
7+
8+
.admin-page::before {
9+
content: "";
10+
position: fixed;
11+
inset: 0;
12+
background: linear-gradient(145deg, #0b1226 0%, #171f3e 48%, #2a1452 100%);
13+
z-index: -1;
14+
}
15+
16+
.admin-content {
17+
position: relative;
18+
max-width: 900px;
19+
margin: 0 auto;
20+
padding: 100px 2rem 4rem;
21+
font-family: Georgia, "Times New Roman", serif;
22+
color: #f0e6d2;
23+
}
24+
25+
.admin-content h1 {
26+
font-size: 2.4rem;
27+
color: #8af4ff;
28+
text-shadow: 1px 2px 4px rgb(0 0 0 / 60%);
29+
margin: 0 0 2rem;
30+
text-align: center;
31+
font-style: italic;
32+
}
33+
34+
.admin-links {
35+
display: flex;
36+
flex-direction: column;
37+
gap: 1rem;
38+
margin: 2rem 0;
39+
}
40+
41+
.admin-link {
42+
display: flex;
43+
align-items: center;
44+
gap: 1rem;
45+
padding: 1.2rem 1.5rem;
46+
background: rgb(9 18 42 / 82%);
47+
border: 2px solid #4ba2ff;
48+
border-radius: 12px;
49+
text-decoration: none;
50+
font-family: Georgia, serif;
51+
font-size: 1.3rem;
52+
font-weight: 700;
53+
color: #98e8ff;
54+
transition: all 0.2s;
55+
}
56+
57+
.admin-link:hover {
58+
background: rgb(21 34 70 / 95%);
59+
border-color: #a765ff;
60+
transform: translateX(4px);
61+
}
62+
63+
.admin-link-icon {
64+
font-size: 1.6rem;
65+
}
66+
67+
.admin-link-desc {
68+
display: block;
69+
font-size: 0.85rem;
70+
font-weight: 400;
71+
color: #c8d4ff;
72+
margin-top: 0.2rem;
73+
}
74+
75+
.admin-super {
76+
margin-top: 0.75rem;
77+
display: flex;
78+
align-items: center;
79+
gap: 0.8rem;
80+
color: #f0e6d2;
81+
}
82+
83+
.admin-super-icon {
84+
font-size: 1.2rem;
85+
color: #a765ff;
86+
}
87+
88+
.admin-super-copy {
89+
display: flex;
90+
flex-direction: column;
91+
}
92+
93+
.admin-super-copy span {
94+
opacity: 0.85;
95+
}
96+
97+
.admin-silly {
98+
margin-top: 3rem;
99+
text-align: center;
100+
opacity: 0.6;
101+
}
102+
103+
.admin-silly pre {
104+
font-size: 0.8rem;
105+
line-height: 1;
106+
color: #c4b89a;
107+
}
108+
109+
.admin-silly .admin-emojis {
110+
font-size: 1.2rem;
111+
margin: 0.5rem 0;
112+
}
113+
114+
.admin-silly .admin-tagline {
115+
font-family: Georgia, serif;
116+
font-size: 1.5rem;
117+
color: #79a6ff;
118+
font-style: italic;
119+
}
120+
121+
.admin-airtable {
122+
margin-top: 2.2rem;
123+
padding: 1.2rem;
124+
border: 2px solid #4ba2ff;
125+
border-radius: 12px;
126+
background: rgb(10 18 43 / 78%);
127+
}
128+
129+
.admin-airtable h2 {
130+
margin: 0 0 0.5rem;
131+
color: #8af4ff;
132+
}
133+
134+
.admin-airtable-subtitle {
135+
margin: 0 0 1rem;
136+
color: #c8d4ff;
137+
}
138+
139+
.admin-airtable-sync-row {
140+
display: flex;
141+
align-items: center;
142+
justify-content: space-between;
143+
gap: 1rem;
144+
padding: 0.8rem;
145+
margin-bottom: 1rem;
146+
border: 1px solid #4ba2ff;
147+
border-radius: 10px;
148+
background: rgb(11 28 62 / 70%);
149+
}
150+
151+
.admin-airtable-sync-row div {
152+
display: grid;
153+
gap: 0.25rem;
154+
}
155+
156+
.admin-airtable-sync-row button {
157+
border: 1px solid #7f5cff;
158+
background: linear-gradient(135deg, #43c6ff, #8d4dff);
159+
color: #fff;
160+
border-radius: 999px;
161+
padding: 0.45rem 0.95rem;
162+
cursor: pointer;
163+
}
164+
165+
.admin-airtable-sync-row button:disabled {
166+
opacity: 0.7;
167+
cursor: not-allowed;
168+
}
169+
170+
.admin-airtable-error {
171+
color: #ffb5b5;
172+
}
173+
174+
.admin-airtable-success {
175+
color: #9cffcf;
176+
}
177+
178+
.admin-airtable-details {
179+
margin-top: 1rem;
180+
padding: 0.8rem;
181+
border-radius: 10px;
182+
background: rgb(20 32 67 / 62%);
183+
}
184+
185+
.admin-airtable-details p {
186+
margin: 0.35rem 0;
187+
}
188+
189+
.admin-airtable-rows {
190+
margin-top: 1rem;
191+
display: grid;
192+
gap: 0.75rem;
193+
}
194+
195+
.admin-airtable-rows pre {
196+
margin: 0;
197+
padding: 0.75rem;
198+
overflow-x: auto;
199+
border: 1px solid #4ba2ff;
200+
border-radius: 8px;
201+
background: rgb(6 10 26 / 95%);
202+
color: #e9f4ff;
203+
}

0 commit comments

Comments
 (0)