@fydemy/cms 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -18
- package/dist/bin.js +36 -8
- package/dist/bin.js.map +1 -1
- package/dist/bin.mjs +36 -8
- package/dist/bin.mjs.map +1 -1
- package/dist/index.js +287 -679
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +287 -679
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -10
- package/LICENSE +0 -21
package/dist/index.js
CHANGED
|
@@ -1075,33 +1075,8 @@ function AdminDashboard() {
|
|
|
1075
1075
|
event.target.value = "";
|
|
1076
1076
|
}
|
|
1077
1077
|
};
|
|
1078
|
-
const handleFileUpload = async (event) => {
|
|
1079
|
-
const file = event.target.files?.[0];
|
|
1080
|
-
if (!file) return;
|
|
1081
|
-
setUploading(true);
|
|
1082
|
-
setMessage("");
|
|
1083
|
-
try {
|
|
1084
|
-
const formData = new FormData();
|
|
1085
|
-
formData.append("file", file);
|
|
1086
|
-
const response = await fetch("/api/cms/upload", {
|
|
1087
|
-
method: "POST",
|
|
1088
|
-
body: formData
|
|
1089
|
-
});
|
|
1090
|
-
const data = await response.json();
|
|
1091
|
-
if (response.ok) {
|
|
1092
|
-
setMessage(`\u2705 File uploaded! Path: ${data.url}`);
|
|
1093
|
-
setTimeout(() => setMessage(""), 5e3);
|
|
1094
|
-
} else {
|
|
1095
|
-
setMessage("\u274C Failed to upload file");
|
|
1096
|
-
}
|
|
1097
|
-
} catch (error) {
|
|
1098
|
-
setMessage("\u274C Error uploading file");
|
|
1099
|
-
} finally {
|
|
1100
|
-
setUploading(false);
|
|
1101
|
-
event.target.value = "";
|
|
1102
|
-
}
|
|
1103
|
-
};
|
|
1104
1078
|
const renderField = (key, field) => {
|
|
1079
|
+
const inputClasses = "flex h-9 w-full rounded-md border border-slate-200 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-400 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:cursor-not-allowed disabled:opacity-50";
|
|
1105
1080
|
switch (field.type) {
|
|
1106
1081
|
case "text":
|
|
1107
1082
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1111,12 +1086,7 @@ function AdminDashboard() {
|
|
|
1111
1086
|
type: "text",
|
|
1112
1087
|
value: field.value,
|
|
1113
1088
|
onChange: (e) => updateField(key, e.target.value),
|
|
1114
|
-
|
|
1115
|
-
width: "100%",
|
|
1116
|
-
padding: "0.5rem",
|
|
1117
|
-
border: "1px solid #ddd",
|
|
1118
|
-
borderRadius: "4px"
|
|
1119
|
-
}
|
|
1089
|
+
className: inputClasses
|
|
1120
1090
|
}
|
|
1121
1091
|
);
|
|
1122
1092
|
case "number":
|
|
@@ -1127,12 +1097,7 @@ function AdminDashboard() {
|
|
|
1127
1097
|
type: "number",
|
|
1128
1098
|
value: field.value,
|
|
1129
1099
|
onChange: (e) => updateField(key, parseFloat(e.target.value) || 0),
|
|
1130
|
-
|
|
1131
|
-
width: "100%",
|
|
1132
|
-
padding: "0.5rem",
|
|
1133
|
-
border: "1px solid #ddd",
|
|
1134
|
-
borderRadius: "4px"
|
|
1135
|
-
}
|
|
1100
|
+
className: inputClasses
|
|
1136
1101
|
}
|
|
1137
1102
|
);
|
|
1138
1103
|
case "date":
|
|
@@ -1143,12 +1108,7 @@ function AdminDashboard() {
|
|
|
1143
1108
|
type: "date",
|
|
1144
1109
|
value: field.value,
|
|
1145
1110
|
onChange: (e) => updateField(key, e.target.value),
|
|
1146
|
-
|
|
1147
|
-
width: "100%",
|
|
1148
|
-
padding: "0.5rem",
|
|
1149
|
-
border: "1px solid #ddd",
|
|
1150
|
-
borderRadius: "4px"
|
|
1151
|
-
}
|
|
1111
|
+
className: inputClasses
|
|
1152
1112
|
}
|
|
1153
1113
|
);
|
|
1154
1114
|
case "markdown":
|
|
@@ -1158,19 +1118,12 @@ function AdminDashboard() {
|
|
|
1158
1118
|
id: key,
|
|
1159
1119
|
value: field.value,
|
|
1160
1120
|
onChange: (e) => updateField(key, e.target.value),
|
|
1161
|
-
|
|
1162
|
-
width: "100%",
|
|
1163
|
-
minHeight: key === "content" ? "400px" : "150px",
|
|
1164
|
-
fontFamily: "monospace",
|
|
1165
|
-
padding: "0.5rem",
|
|
1166
|
-
border: "1px solid #ddd",
|
|
1167
|
-
borderRadius: "4px"
|
|
1168
|
-
},
|
|
1121
|
+
className: "flex min-h-[300px] w-full rounded-md border border-slate-200 bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-slate-400 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:cursor-not-allowed disabled:opacity-50 font-mono",
|
|
1169
1122
|
placeholder: key === "content" ? "Write your markdown content here..." : "Markdown text..."
|
|
1170
1123
|
}
|
|
1171
1124
|
);
|
|
1172
1125
|
case "image":
|
|
1173
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1126
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
1174
1127
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1175
1128
|
"input",
|
|
1176
1129
|
{
|
|
@@ -1179,13 +1132,7 @@ function AdminDashboard() {
|
|
|
1179
1132
|
value: field.value,
|
|
1180
1133
|
onChange: (e) => updateField(key, e.target.value),
|
|
1181
1134
|
placeholder: "/uploads/image.jpg or https://...",
|
|
1182
|
-
|
|
1183
|
-
width: "100%",
|
|
1184
|
-
padding: "0.5rem",
|
|
1185
|
-
marginBottom: "0.5rem",
|
|
1186
|
-
border: "1px solid #ddd",
|
|
1187
|
-
borderRadius: "4px"
|
|
1188
|
-
}
|
|
1135
|
+
className: inputClasses
|
|
1189
1136
|
}
|
|
1190
1137
|
),
|
|
1191
1138
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1195,7 +1142,7 @@ function AdminDashboard() {
|
|
|
1195
1142
|
accept: "image/*",
|
|
1196
1143
|
onChange: (e) => handleImageUpload(key, e),
|
|
1197
1144
|
disabled: uploading,
|
|
1198
|
-
|
|
1145
|
+
className: "block w-full text-sm text-slate-500\n file:mr-4 file:py-2 file:px-4\n file:rounded-md file:border-0\n file:text-sm file:font-semibold\n file:bg-slate-50 file:text-slate-700\n hover:file:bg-slate-100"
|
|
1199
1146
|
}
|
|
1200
1147
|
),
|
|
1201
1148
|
field.value && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1203,13 +1150,7 @@ function AdminDashboard() {
|
|
|
1203
1150
|
{
|
|
1204
1151
|
src: field.value,
|
|
1205
1152
|
alt: key,
|
|
1206
|
-
|
|
1207
|
-
maxWidth: "200px",
|
|
1208
|
-
display: "block",
|
|
1209
|
-
marginTop: "0.5rem",
|
|
1210
|
-
borderRadius: "4px",
|
|
1211
|
-
border: "1px solid #ddd"
|
|
1212
|
-
}
|
|
1153
|
+
className: "max-w-[200px] rounded-md border border-slate-200"
|
|
1213
1154
|
}
|
|
1214
1155
|
)
|
|
1215
1156
|
] });
|
|
@@ -1220,497 +1161,202 @@ function AdminDashboard() {
|
|
|
1220
1161
|
id: key,
|
|
1221
1162
|
type: "text",
|
|
1222
1163
|
value: field.value,
|
|
1223
|
-
onChange: (e) => updateField(key, e.target.value)
|
|
1164
|
+
onChange: (e) => updateField(key, e.target.value),
|
|
1165
|
+
className: inputClasses
|
|
1224
1166
|
}
|
|
1225
1167
|
);
|
|
1226
1168
|
}
|
|
1227
1169
|
};
|
|
1228
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1229
|
-
"div",
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
"
|
|
1170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-h-screen bg-slate-50/50 pb-8", children: [
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border-b border-slate-200 bg-white px-4 py-4 mb-6", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "container mx-auto max-w-7xl flex items-center justify-between", children: [
|
|
1172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-xl font-bold tracking-tight", children: "\u{1F4DD} Admin Dashboard" }) }),
|
|
1173
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1174
|
+
"button",
|
|
1175
|
+
{
|
|
1176
|
+
onClick: handleLogout2,
|
|
1177
|
+
className: "inline-flex h-9 items-center justify-center rounded-md border border-slate-200 bg-white px-4 py-2 text-sm font-medium transition-colors hover:bg-slate-100 hover:text-slate-900 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950",
|
|
1178
|
+
children: "Logout"
|
|
1179
|
+
}
|
|
1180
|
+
)
|
|
1181
|
+
] }) }),
|
|
1182
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "container mx-auto max-w-7xl px-4 grid grid-cols-1 md:grid-cols-[300px_1fr] gap-6", children: [
|
|
1183
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rounded-xl border border-slate-200 bg-white text-slate-950 shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "p-6", children: [
|
|
1184
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-lg font-semibold leading-none tracking-tight mb-4", children: "Files" }),
|
|
1185
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-4 text-sm text-slate-500 flex items-center gap-1 overflow-hidden", children: [
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1187
|
+
"button",
|
|
1188
|
+
{
|
|
1189
|
+
onClick: () => setCurrentPath(""),
|
|
1190
|
+
className: "hover:text-slate-900 hover:underline shrink-0",
|
|
1191
|
+
children: "content"
|
|
1192
|
+
}
|
|
1193
|
+
),
|
|
1194
|
+
currentPath && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-slate-300", children: "/" }),
|
|
1196
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-medium truncate text-slate-900", children: currentPath })
|
|
1197
|
+
] })
|
|
1198
|
+
] }),
|
|
1199
|
+
currentPath && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1200
|
+
"button",
|
|
1236
1201
|
{
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
alignItems: "center",
|
|
1241
|
-
marginBottom: "2rem"
|
|
1242
|
-
},
|
|
1243
|
-
children: [
|
|
1244
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: "\u{1F4DD} Admin Dashboard" }),
|
|
1245
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1246
|
-
"button",
|
|
1247
|
-
{
|
|
1248
|
-
onClick: handleLogout2,
|
|
1249
|
-
style: {
|
|
1250
|
-
padding: "0.5rem 1rem",
|
|
1251
|
-
background: "#f5f5f5",
|
|
1252
|
-
border: "1px solid #ddd",
|
|
1253
|
-
borderRadius: "4px",
|
|
1254
|
-
cursor: "pointer"
|
|
1255
|
-
},
|
|
1256
|
-
children: "Logout"
|
|
1257
|
-
}
|
|
1258
|
-
)
|
|
1259
|
-
]
|
|
1202
|
+
onClick: goUp,
|
|
1203
|
+
className: "mb-4 inline-flex h-8 w-full items-center justify-center rounded-md bg-slate-100 px-3 text-xs font-medium text-slate-900 hover:bg-slate-200/80",
|
|
1204
|
+
children: "\u2B06\uFE0F Go Up"
|
|
1260
1205
|
}
|
|
1261
1206
|
),
|
|
1262
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1207
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-6 space-y-2 border-b border-slate-100 pb-6", children: [
|
|
1208
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1209
|
+
"input",
|
|
1210
|
+
{
|
|
1211
|
+
type: "text",
|
|
1212
|
+
placeholder: "new-file.md",
|
|
1213
|
+
value: newFileName,
|
|
1214
|
+
onChange: (e) => setNewFileName(e.target.value),
|
|
1215
|
+
className: "flex h-9 w-full rounded-md border border-slate-200 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-slate-400 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950"
|
|
1216
|
+
}
|
|
1217
|
+
),
|
|
1218
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1219
|
+
"button",
|
|
1220
|
+
{
|
|
1221
|
+
onClick: createFile,
|
|
1222
|
+
disabled: loading || !newFileName,
|
|
1223
|
+
className: "inline-flex h-9 w-full items-center justify-center rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-slate-50 shadow hover:bg-slate-900/90 disabled:pointer-events-none disabled:opacity-50",
|
|
1224
|
+
children: "+ New File"
|
|
1225
|
+
}
|
|
1226
|
+
)
|
|
1227
|
+
] }),
|
|
1228
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", { className: "space-y-1", children: [
|
|
1229
|
+
entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "text-sm text-slate-500 italic px-2", children: "Empty directory" }),
|
|
1230
|
+
entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: entry.type === "directory" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1231
|
+
"button",
|
|
1232
|
+
{
|
|
1233
|
+
onClick: () => navigateToDir(entry.path),
|
|
1234
|
+
className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium hover:bg-slate-100 text-slate-700 hover:text-slate-900",
|
|
1235
|
+
children: [
|
|
1236
|
+
"\u{1F4C1} ",
|
|
1237
|
+
entry.name
|
|
1238
|
+
]
|
|
1239
|
+
}
|
|
1240
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "group flex items-center justify-between rounded-md hover:bg-slate-100 px-2 py-1.5", children: [
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1242
|
+
"button",
|
|
1243
|
+
{
|
|
1244
|
+
onClick: () => loadFile(entry.path),
|
|
1245
|
+
className: `flex-1 text-left text-sm truncate ${selectedFile === entry.path ? "font-semibold text-slate-900" : "text-slate-600 group-hover:text-slate-900"}`,
|
|
1246
|
+
children: [
|
|
1247
|
+
"\u{1F4C4} ",
|
|
1248
|
+
entry.name
|
|
1249
|
+
]
|
|
1250
|
+
}
|
|
1251
|
+
),
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1253
|
+
"button",
|
|
1254
|
+
{
|
|
1255
|
+
onClick: () => deleteFile(entry.path),
|
|
1256
|
+
disabled: loading,
|
|
1257
|
+
className: "opacity-0 group-hover:opacity-100 ml-2 text-slate-400 hover:text-red-500 transition-opacity",
|
|
1258
|
+
title: "Delete file",
|
|
1259
|
+
children: "\u2715"
|
|
1260
|
+
}
|
|
1261
|
+
)
|
|
1262
|
+
] }) }, entry.path))
|
|
1263
|
+
] })
|
|
1264
|
+
] }) }) }),
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rounded-xl border border-slate-200 bg-white text-slate-950 shadow-sm min-h-[500px]", children: selectedFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "p-6", children: [
|
|
1266
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6 pb-6 border-b border-slate-100", children: [
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h2", { className: "text-xl font-semibold tracking-tight break-all", children: [
|
|
1268
|
+
"Edit: ",
|
|
1269
|
+
selectedFile
|
|
1270
|
+
] }),
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2 shrink-0", children: [
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1273
|
+
"button",
|
|
1274
|
+
{
|
|
1275
|
+
onClick: duplicateFile,
|
|
1276
|
+
disabled: loading,
|
|
1277
|
+
className: "inline-flex h-9 items-center justify-center rounded-md border border-slate-200 bg-white px-4 py-2 text-sm font-medium shadow-sm transition-colors hover:bg-slate-100 hover:text-slate-900 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:pointer-events-none disabled:opacity-50",
|
|
1278
|
+
children: "\u{1F4CB} Duplicate"
|
|
1279
|
+
}
|
|
1280
|
+
),
|
|
1281
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1282
|
+
"button",
|
|
1283
|
+
{
|
|
1284
|
+
onClick: saveFile,
|
|
1285
|
+
disabled: loading,
|
|
1286
|
+
className: "inline-flex h-9 items-center justify-center rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-slate-50 shadow hover:bg-slate-900/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:pointer-events-none disabled:opacity-50",
|
|
1287
|
+
children: loading ? "Saving..." : "\u{1F4BE} Save Changes"
|
|
1288
|
+
}
|
|
1289
|
+
)
|
|
1290
|
+
] })
|
|
1291
|
+
] }),
|
|
1292
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1263
1293
|
"div",
|
|
1264
1294
|
{
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
{
|
|
1313
|
-
onClick: goUp,
|
|
1314
|
-
style: {
|
|
1315
|
-
width: "100%",
|
|
1316
|
-
marginBottom: "1rem",
|
|
1317
|
-
padding: "0.5rem",
|
|
1318
|
-
background: "#f5f5f5",
|
|
1319
|
-
border: "1px solid #ddd",
|
|
1320
|
-
borderRadius: "4px",
|
|
1321
|
-
cursor: "pointer"
|
|
1322
|
-
},
|
|
1323
|
-
children: "\u2B06\uFE0F Go Up"
|
|
1324
|
-
}
|
|
1325
|
-
),
|
|
1326
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1327
|
-
"div",
|
|
1328
|
-
{
|
|
1329
|
-
style: {
|
|
1330
|
-
marginBottom: "1.5rem",
|
|
1331
|
-
paddingBottom: "1.5rem",
|
|
1332
|
-
borderBottom: "1px solid #eee"
|
|
1333
|
-
},
|
|
1334
|
-
children: [
|
|
1335
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1336
|
-
"input",
|
|
1337
|
-
{
|
|
1338
|
-
type: "text",
|
|
1339
|
-
placeholder: "new-file.md",
|
|
1340
|
-
value: newFileName,
|
|
1341
|
-
onChange: (e) => setNewFileName(e.target.value),
|
|
1342
|
-
style: {
|
|
1343
|
-
width: "100%",
|
|
1344
|
-
padding: "0.5rem",
|
|
1345
|
-
marginBottom: "0.5rem",
|
|
1346
|
-
border: "1px solid #ddd",
|
|
1347
|
-
borderRadius: "4px"
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
),
|
|
1351
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1352
|
-
"button",
|
|
1353
|
-
{
|
|
1354
|
-
onClick: createFile,
|
|
1355
|
-
disabled: loading || !newFileName,
|
|
1356
|
-
style: {
|
|
1357
|
-
width: "100%",
|
|
1358
|
-
padding: "0.5rem",
|
|
1359
|
-
background: "#0070f3",
|
|
1360
|
-
color: "white",
|
|
1361
|
-
border: "none",
|
|
1362
|
-
borderRadius: "4px",
|
|
1363
|
-
cursor: "pointer",
|
|
1364
|
-
opacity: loading ? 0.7 : 1
|
|
1365
|
-
},
|
|
1366
|
-
children: "+ New File"
|
|
1367
|
-
}
|
|
1368
|
-
)
|
|
1369
|
-
]
|
|
1370
|
-
}
|
|
1371
|
-
),
|
|
1372
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: [
|
|
1373
|
-
entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { style: { color: "#999", fontStyle: "italic" }, children: "Empty directory" }),
|
|
1374
|
-
entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1375
|
-
"li",
|
|
1376
|
-
{
|
|
1377
|
-
style: {
|
|
1378
|
-
marginBottom: "0.5rem",
|
|
1379
|
-
display: "flex",
|
|
1380
|
-
flexDirection: "column"
|
|
1381
|
-
},
|
|
1382
|
-
children: entry.type === "directory" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1383
|
-
"button",
|
|
1384
|
-
{
|
|
1385
|
-
onClick: () => navigateToDir(entry.path),
|
|
1386
|
-
style: {
|
|
1387
|
-
background: "none",
|
|
1388
|
-
border: "none",
|
|
1389
|
-
color: "#0070f3",
|
|
1390
|
-
cursor: "pointer",
|
|
1391
|
-
textAlign: "left",
|
|
1392
|
-
fontSize: "1rem",
|
|
1393
|
-
padding: "0.25rem 0",
|
|
1394
|
-
fontWeight: "bold"
|
|
1395
|
-
},
|
|
1396
|
-
children: [
|
|
1397
|
-
"\u{1F4C1} ",
|
|
1398
|
-
entry.name
|
|
1399
|
-
]
|
|
1400
|
-
}
|
|
1401
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1402
|
-
"div",
|
|
1403
|
-
{
|
|
1404
|
-
style: {
|
|
1405
|
-
display: "flex",
|
|
1406
|
-
justifyContent: "space-between",
|
|
1407
|
-
alignItems: "center"
|
|
1408
|
-
},
|
|
1409
|
-
children: [
|
|
1410
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1411
|
-
"button",
|
|
1412
|
-
{
|
|
1413
|
-
onClick: () => loadFile(entry.path),
|
|
1414
|
-
style: {
|
|
1415
|
-
background: "none",
|
|
1416
|
-
border: "none",
|
|
1417
|
-
color: selectedFile === entry.path ? "#000" : "#444",
|
|
1418
|
-
cursor: "pointer",
|
|
1419
|
-
textAlign: "left",
|
|
1420
|
-
padding: "0.25rem 0",
|
|
1421
|
-
fontWeight: selectedFile === entry.path ? "bold" : "normal",
|
|
1422
|
-
textDecoration: selectedFile === entry.path ? "underline" : "none",
|
|
1423
|
-
flex: 1
|
|
1424
|
-
},
|
|
1425
|
-
children: [
|
|
1426
|
-
"\u{1F4C4} ",
|
|
1427
|
-
entry.name
|
|
1428
|
-
]
|
|
1429
|
-
}
|
|
1430
|
-
),
|
|
1431
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1432
|
-
"button",
|
|
1433
|
-
{
|
|
1434
|
-
onClick: () => deleteFile(entry.path),
|
|
1435
|
-
disabled: loading,
|
|
1436
|
-
style: {
|
|
1437
|
-
background: "none",
|
|
1438
|
-
border: "none",
|
|
1439
|
-
color: "#d32f2f",
|
|
1440
|
-
cursor: "pointer",
|
|
1441
|
-
fontSize: "0.8rem",
|
|
1442
|
-
opacity: 0.7
|
|
1443
|
-
},
|
|
1444
|
-
children: "\u2715"
|
|
1445
|
-
}
|
|
1446
|
-
)
|
|
1447
|
-
]
|
|
1448
|
-
}
|
|
1449
|
-
)
|
|
1450
|
-
},
|
|
1451
|
-
entry.path
|
|
1452
|
-
))
|
|
1453
|
-
] })
|
|
1454
|
-
]
|
|
1455
|
-
}
|
|
1456
|
-
),
|
|
1295
|
+
className: `mb-6 rounded-md p-3 text-sm flex items-center gap-2 ${message.includes("\u2705") ? "bg-green-50 text-green-900 border border-green-200" : "bg-red-50 text-red-900 border border-red-200"}`,
|
|
1296
|
+
children: message
|
|
1297
|
+
}
|
|
1298
|
+
),
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-6", children: [
|
|
1300
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1301
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-sm font-medium leading-none text-slate-500 uppercase tracking-wider", children: "Frontmatter Fields" }),
|
|
1302
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1303
|
+
"button",
|
|
1304
|
+
{
|
|
1305
|
+
onClick: addField,
|
|
1306
|
+
className: "inline-flex h-8 items-center justify-center rounded-md bg-slate-100 px-3 text-xs font-medium text-slate-900 hover:bg-slate-200",
|
|
1307
|
+
children: "+ Add Field"
|
|
1308
|
+
}
|
|
1309
|
+
)
|
|
1310
|
+
] }),
|
|
1311
|
+
Object.keys(fields).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-center py-12 text-slate-500 border-2 border-dashed border-slate-200 rounded-lg", children: "No fields found. Add one or load a file layout." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-4", children: [
|
|
1312
|
+
Object.entries(fields).filter(([key]) => key !== "content").map(([key, field]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1315
|
+
"label",
|
|
1316
|
+
{
|
|
1317
|
+
htmlFor: key,
|
|
1318
|
+
className: "text-sm font-medium bg-slate-100 px-2 py-0.5 rounded text-slate-700",
|
|
1319
|
+
children: [
|
|
1320
|
+
key,
|
|
1321
|
+
" ",
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-slate-400 font-normal text-xs ml-1", children: [
|
|
1323
|
+
"(",
|
|
1324
|
+
field.type,
|
|
1325
|
+
")"
|
|
1326
|
+
] })
|
|
1327
|
+
]
|
|
1328
|
+
}
|
|
1329
|
+
),
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1331
|
+
"button",
|
|
1332
|
+
{
|
|
1333
|
+
onClick: () => removeField(key),
|
|
1334
|
+
className: "text-xs text-red-500 hover:text-red-700 hover:underline",
|
|
1335
|
+
children: "Remove"
|
|
1336
|
+
}
|
|
1337
|
+
)
|
|
1338
|
+
] }),
|
|
1339
|
+
renderField(key, field)
|
|
1340
|
+
] }, key)),
|
|
1341
|
+
fields["content"] && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pt-6 mt-6 border-t border-slate-100", children: [
|
|
1457
1342
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1458
|
-
"
|
|
1343
|
+
"label",
|
|
1459
1344
|
{
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
borderRadius: "8px",
|
|
1464
|
-
boxShadow: "0 2px 4px rgba(0,0,0,0.1)"
|
|
1465
|
-
},
|
|
1466
|
-
children: selectedFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1467
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1468
|
-
"div",
|
|
1469
|
-
{
|
|
1470
|
-
style: {
|
|
1471
|
-
display: "flex",
|
|
1472
|
-
justifyContent: "space-between",
|
|
1473
|
-
alignItems: "center",
|
|
1474
|
-
marginBottom: "2rem",
|
|
1475
|
-
paddingBottom: "1rem",
|
|
1476
|
-
borderBottom: "1px solid #eee"
|
|
1477
|
-
},
|
|
1478
|
-
children: [
|
|
1479
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h2", { style: { margin: 0 }, children: [
|
|
1480
|
-
"Edit: ",
|
|
1481
|
-
selectedFile
|
|
1482
|
-
] }),
|
|
1483
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "0.5rem" }, children: [
|
|
1484
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1485
|
-
"button",
|
|
1486
|
-
{
|
|
1487
|
-
onClick: duplicateFile,
|
|
1488
|
-
disabled: loading,
|
|
1489
|
-
style: {
|
|
1490
|
-
padding: "0.5rem 1rem",
|
|
1491
|
-
background: "#f5f5f5",
|
|
1492
|
-
border: "1px solid #ddd",
|
|
1493
|
-
borderRadius: "4px",
|
|
1494
|
-
cursor: "pointer"
|
|
1495
|
-
},
|
|
1496
|
-
children: "\u{1F4CB} Duplicate"
|
|
1497
|
-
}
|
|
1498
|
-
),
|
|
1499
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1500
|
-
"button",
|
|
1501
|
-
{
|
|
1502
|
-
onClick: saveFile,
|
|
1503
|
-
disabled: loading,
|
|
1504
|
-
style: {
|
|
1505
|
-
padding: "0.5rem 1rem",
|
|
1506
|
-
background: "#0070f3",
|
|
1507
|
-
color: "white",
|
|
1508
|
-
border: "none",
|
|
1509
|
-
borderRadius: "4px",
|
|
1510
|
-
cursor: "pointer",
|
|
1511
|
-
opacity: loading ? 0.7 : 1
|
|
1512
|
-
},
|
|
1513
|
-
children: loading ? "Saving..." : "\u{1F4BE} Save Changes"
|
|
1514
|
-
}
|
|
1515
|
-
)
|
|
1516
|
-
] })
|
|
1517
|
-
]
|
|
1518
|
-
}
|
|
1519
|
-
),
|
|
1520
|
-
message && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1521
|
-
"div",
|
|
1522
|
-
{
|
|
1523
|
-
style: {
|
|
1524
|
-
marginBottom: "1.5rem",
|
|
1525
|
-
padding: "0.75rem",
|
|
1526
|
-
background: message.includes("\u2705") ? "#e6ffe6" : "#ffe6e6",
|
|
1527
|
-
borderRadius: "4px",
|
|
1528
|
-
border: message.includes("\u2705") ? "1px solid #a5d6a7" : "1px solid #ef9a9a"
|
|
1529
|
-
},
|
|
1530
|
-
children: message
|
|
1531
|
-
}
|
|
1532
|
-
),
|
|
1533
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: "2rem" }, children: [
|
|
1534
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1535
|
-
"div",
|
|
1536
|
-
{
|
|
1537
|
-
style: {
|
|
1538
|
-
display: "flex",
|
|
1539
|
-
justifyContent: "space-between",
|
|
1540
|
-
alignItems: "center",
|
|
1541
|
-
marginBottom: "1rem"
|
|
1542
|
-
},
|
|
1543
|
-
children: [
|
|
1544
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { fontSize: "1.1rem", margin: 0 }, children: "Fields" }),
|
|
1545
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1546
|
-
"button",
|
|
1547
|
-
{
|
|
1548
|
-
onClick: addField,
|
|
1549
|
-
style: {
|
|
1550
|
-
fontSize: "0.875rem",
|
|
1551
|
-
padding: "0.4rem 0.8rem",
|
|
1552
|
-
background: "#e1f5fe",
|
|
1553
|
-
color: "#0288d1",
|
|
1554
|
-
border: "none",
|
|
1555
|
-
borderRadius: "4px",
|
|
1556
|
-
cursor: "pointer"
|
|
1557
|
-
},
|
|
1558
|
-
children: "+ Add Field"
|
|
1559
|
-
}
|
|
1560
|
-
)
|
|
1561
|
-
]
|
|
1562
|
-
}
|
|
1563
|
-
),
|
|
1564
|
-
Object.keys(fields).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1565
|
-
"div",
|
|
1566
|
-
{
|
|
1567
|
-
style: {
|
|
1568
|
-
padding: "2rem",
|
|
1569
|
-
textAlign: "center",
|
|
1570
|
-
background: "#f9f9f9",
|
|
1571
|
-
borderRadius: "4px",
|
|
1572
|
-
border: "1px dashed #ccc"
|
|
1573
|
-
},
|
|
1574
|
-
children: [
|
|
1575
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1576
|
-
"p",
|
|
1577
|
-
{
|
|
1578
|
-
style: { color: "#666", fontStyle: "italic", margin: 0 },
|
|
1579
|
-
children: 'No fields yet. Click "+ Add Field" to start.'
|
|
1580
|
-
}
|
|
1581
|
-
),
|
|
1582
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1583
|
-
"small",
|
|
1584
|
-
{
|
|
1585
|
-
style: {
|
|
1586
|
-
color: "#999",
|
|
1587
|
-
marginTop: "0.5rem",
|
|
1588
|
-
display: "block"
|
|
1589
|
-
},
|
|
1590
|
-
children: "Add 'content' field for the main body"
|
|
1591
|
-
}
|
|
1592
|
-
)
|
|
1593
|
-
]
|
|
1594
|
-
}
|
|
1595
|
-
) : Object.entries(fields).map(([key, field]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1596
|
-
"div",
|
|
1597
|
-
{
|
|
1598
|
-
style: {
|
|
1599
|
-
marginBottom: "1.5rem",
|
|
1600
|
-
background: "#fff",
|
|
1601
|
-
border: "1px solid #eee",
|
|
1602
|
-
padding: "1rem",
|
|
1603
|
-
borderRadius: "6px"
|
|
1604
|
-
},
|
|
1605
|
-
children: [
|
|
1606
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1607
|
-
"div",
|
|
1608
|
-
{
|
|
1609
|
-
style: {
|
|
1610
|
-
display: "flex",
|
|
1611
|
-
justifyContent: "space-between",
|
|
1612
|
-
alignItems: "center",
|
|
1613
|
-
marginBottom: "0.5rem"
|
|
1614
|
-
},
|
|
1615
|
-
children: [
|
|
1616
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: key, style: { fontWeight: 500 }, children: [
|
|
1617
|
-
key,
|
|
1618
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1619
|
-
"span",
|
|
1620
|
-
{
|
|
1621
|
-
style: {
|
|
1622
|
-
marginLeft: "0.5rem",
|
|
1623
|
-
fontSize: "0.75rem",
|
|
1624
|
-
color: "#999",
|
|
1625
|
-
background: "#f0f0f0",
|
|
1626
|
-
padding: "0.1rem 0.4rem",
|
|
1627
|
-
borderRadius: "4px"
|
|
1628
|
-
},
|
|
1629
|
-
children: field.type
|
|
1630
|
-
}
|
|
1631
|
-
)
|
|
1632
|
-
] }),
|
|
1633
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1634
|
-
"button",
|
|
1635
|
-
{
|
|
1636
|
-
onClick: () => removeField(key),
|
|
1637
|
-
style: {
|
|
1638
|
-
background: "none",
|
|
1639
|
-
border: "none",
|
|
1640
|
-
color: "#e57373",
|
|
1641
|
-
cursor: "pointer",
|
|
1642
|
-
fontSize: "0.875rem"
|
|
1643
|
-
},
|
|
1644
|
-
children: "\u2715 Remove"
|
|
1645
|
-
}
|
|
1646
|
-
)
|
|
1647
|
-
]
|
|
1648
|
-
}
|
|
1649
|
-
),
|
|
1650
|
-
renderField(key, field)
|
|
1651
|
-
]
|
|
1652
|
-
},
|
|
1653
|
-
key
|
|
1654
|
-
))
|
|
1655
|
-
] }),
|
|
1656
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1657
|
-
"div",
|
|
1658
|
-
{
|
|
1659
|
-
style: {
|
|
1660
|
-
marginTop: "3rem",
|
|
1661
|
-
paddingTop: "1rem",
|
|
1662
|
-
borderTop: "1px solid #eee"
|
|
1663
|
-
},
|
|
1664
|
-
children: [
|
|
1665
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1666
|
-
"h3",
|
|
1667
|
-
{
|
|
1668
|
-
style: {
|
|
1669
|
-
fontSize: "1rem",
|
|
1670
|
-
marginBottom: "0.5rem",
|
|
1671
|
-
color: "#666"
|
|
1672
|
-
},
|
|
1673
|
-
children: "Quick File Upload"
|
|
1674
|
-
}
|
|
1675
|
-
),
|
|
1676
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "0.5rem" }, children: [
|
|
1677
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1678
|
-
"input",
|
|
1679
|
-
{
|
|
1680
|
-
type: "file",
|
|
1681
|
-
onChange: handleFileUpload,
|
|
1682
|
-
disabled: uploading,
|
|
1683
|
-
style: { flex: 1 }
|
|
1684
|
-
}
|
|
1685
|
-
),
|
|
1686
|
-
uploading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#666" }, children: "Uploading..." })
|
|
1687
|
-
] })
|
|
1688
|
-
]
|
|
1689
|
-
}
|
|
1690
|
-
)
|
|
1691
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1692
|
-
"div",
|
|
1693
|
-
{
|
|
1694
|
-
style: {
|
|
1695
|
-
textAlign: "center",
|
|
1696
|
-
padding: "5rem 2rem",
|
|
1697
|
-
color: "#999"
|
|
1698
|
-
},
|
|
1699
|
-
children: [
|
|
1700
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "3rem", marginBottom: "1rem" }, children: "\u{1F448}" }),
|
|
1701
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: "1.1rem" }, children: "Select a file from the sidebar to edit" }),
|
|
1702
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "or create a new file to get started" })
|
|
1703
|
-
]
|
|
1704
|
-
}
|
|
1705
|
-
)
|
|
1345
|
+
htmlFor: "content",
|
|
1346
|
+
className: "block text-sm font-medium mb-3 text-slate-900",
|
|
1347
|
+
children: "Content (Markdown)"
|
|
1706
1348
|
}
|
|
1707
|
-
)
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1349
|
+
),
|
|
1350
|
+
renderField("content", fields["content"])
|
|
1351
|
+
] })
|
|
1352
|
+
] })
|
|
1353
|
+
] })
|
|
1354
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center justify-center h-[500px] text-slate-500", children: [
|
|
1355
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-4xl mb-4", children: "\u{1F4C4}" }),
|
|
1356
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Select a file to edit or create a new one." })
|
|
1357
|
+
] }) }) })
|
|
1358
|
+
] })
|
|
1359
|
+
] });
|
|
1714
1360
|
}
|
|
1715
1361
|
|
|
1716
1362
|
// src/ui/Login.tsx
|
|
@@ -1743,133 +1389,67 @@ function Login() {
|
|
|
1743
1389
|
setLoading(false);
|
|
1744
1390
|
}
|
|
1745
1391
|
};
|
|
1746
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1747
|
-
"div",
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex min-h-screen items-center justify-center bg-slate-50 p-4 font-sans text-slate-900", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full max-w-[350px] rounded-xl border border-slate-200 bg-white shadow-sm", children: [
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col space-y-1.5 p-6", children: [
|
|
1394
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: "text-2xl font-semibold leading-none tracking-tight", children: "Admin Login" }),
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-slate-500", children: "Enter your credentials to access the CMS" })
|
|
1396
|
+
] }),
|
|
1397
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "p-6 pt-0", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-2", children: [
|
|
1399
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1400
|
+
"label",
|
|
1401
|
+
{
|
|
1402
|
+
htmlFor: "username",
|
|
1403
|
+
className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
1404
|
+
children: "Username"
|
|
1405
|
+
}
|
|
1406
|
+
),
|
|
1407
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1408
|
+
"input",
|
|
1409
|
+
{
|
|
1410
|
+
id: "username",
|
|
1411
|
+
type: "text",
|
|
1412
|
+
value: username,
|
|
1413
|
+
onChange: (e) => setUsername(e.target.value),
|
|
1414
|
+
required: true,
|
|
1415
|
+
autoFocus: true,
|
|
1416
|
+
className: "flex h-9 w-full rounded-md border border-slate-200 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-400 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:cursor-not-allowed disabled:opacity-50"
|
|
1417
|
+
}
|
|
1418
|
+
)
|
|
1419
|
+
] }),
|
|
1420
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-2", children: [
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1422
|
+
"label",
|
|
1423
|
+
{
|
|
1424
|
+
htmlFor: "password",
|
|
1425
|
+
className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
1426
|
+
children: "Password"
|
|
1427
|
+
}
|
|
1428
|
+
),
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1430
|
+
"input",
|
|
1431
|
+
{
|
|
1432
|
+
id: "password",
|
|
1433
|
+
type: "password",
|
|
1434
|
+
value: password,
|
|
1435
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1436
|
+
required: true,
|
|
1437
|
+
className: "flex h-9 w-full rounded-md border border-slate-200 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-400 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:cursor-not-allowed disabled:opacity-50"
|
|
1438
|
+
}
|
|
1439
|
+
)
|
|
1440
|
+
] }),
|
|
1441
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "rounded-md bg-red-50 p-3 text-sm text-red-500 border border-red-200", children: error }),
|
|
1442
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1443
|
+
"button",
|
|
1759
1444
|
{
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
background: "white",
|
|
1765
|
-
borderRadius: "8px",
|
|
1766
|
-
boxShadow: "0 4px 6px rgba(0,0,0,0.1)"
|
|
1767
|
-
},
|
|
1768
|
-
children: [
|
|
1769
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { style: { marginBottom: "0.5rem", textAlign: "center" }, children: "Admin Login" }),
|
|
1770
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { color: "#666", marginBottom: "2rem", textAlign: "center" }, children: "Enter your credentials to access the CMS" }),
|
|
1771
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, children: [
|
|
1772
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "1rem" }, children: [
|
|
1773
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1774
|
-
"label",
|
|
1775
|
-
{
|
|
1776
|
-
htmlFor: "username",
|
|
1777
|
-
style: {
|
|
1778
|
-
display: "block",
|
|
1779
|
-
marginBottom: "0.5rem",
|
|
1780
|
-
fontWeight: 500
|
|
1781
|
-
},
|
|
1782
|
-
children: "Username"
|
|
1783
|
-
}
|
|
1784
|
-
),
|
|
1785
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1786
|
-
"input",
|
|
1787
|
-
{
|
|
1788
|
-
id: "username",
|
|
1789
|
-
type: "text",
|
|
1790
|
-
value: username,
|
|
1791
|
-
onChange: (e) => setUsername(e.target.value),
|
|
1792
|
-
required: true,
|
|
1793
|
-
autoFocus: true,
|
|
1794
|
-
style: {
|
|
1795
|
-
width: "100%",
|
|
1796
|
-
padding: "0.75rem",
|
|
1797
|
-
border: "1px solid #ddd",
|
|
1798
|
-
borderRadius: "4px"
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
)
|
|
1802
|
-
] }),
|
|
1803
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "1.5rem" }, children: [
|
|
1804
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1805
|
-
"label",
|
|
1806
|
-
{
|
|
1807
|
-
htmlFor: "password",
|
|
1808
|
-
style: {
|
|
1809
|
-
display: "block",
|
|
1810
|
-
marginBottom: "0.5rem",
|
|
1811
|
-
fontWeight: 500
|
|
1812
|
-
},
|
|
1813
|
-
children: "Password"
|
|
1814
|
-
}
|
|
1815
|
-
),
|
|
1816
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1817
|
-
"input",
|
|
1818
|
-
{
|
|
1819
|
-
id: "password",
|
|
1820
|
-
type: "password",
|
|
1821
|
-
value: password,
|
|
1822
|
-
onChange: (e) => setPassword(e.target.value),
|
|
1823
|
-
required: true,
|
|
1824
|
-
style: {
|
|
1825
|
-
width: "100%",
|
|
1826
|
-
padding: "0.75rem",
|
|
1827
|
-
border: "1px solid #ddd",
|
|
1828
|
-
borderRadius: "4px"
|
|
1829
|
-
}
|
|
1830
|
-
}
|
|
1831
|
-
)
|
|
1832
|
-
] }),
|
|
1833
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1834
|
-
"div",
|
|
1835
|
-
{
|
|
1836
|
-
style: {
|
|
1837
|
-
marginBottom: "1rem",
|
|
1838
|
-
padding: "0.75rem",
|
|
1839
|
-
background: "#ffe6e6",
|
|
1840
|
-
color: "#d32f2f",
|
|
1841
|
-
borderRadius: "4px",
|
|
1842
|
-
fontSize: "0.875rem"
|
|
1843
|
-
},
|
|
1844
|
-
children: error
|
|
1845
|
-
}
|
|
1846
|
-
),
|
|
1847
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1848
|
-
"button",
|
|
1849
|
-
{
|
|
1850
|
-
type: "submit",
|
|
1851
|
-
disabled: loading,
|
|
1852
|
-
style: {
|
|
1853
|
-
width: "100%",
|
|
1854
|
-
padding: "0.75rem",
|
|
1855
|
-
background: "#0070f3",
|
|
1856
|
-
color: "white",
|
|
1857
|
-
border: "none",
|
|
1858
|
-
borderRadius: "4px",
|
|
1859
|
-
fontSize: "1rem",
|
|
1860
|
-
fontWeight: 500,
|
|
1861
|
-
cursor: "pointer",
|
|
1862
|
-
opacity: loading ? 0.7 : 1
|
|
1863
|
-
},
|
|
1864
|
-
children: loading ? "Logging in..." : "Login"
|
|
1865
|
-
}
|
|
1866
|
-
)
|
|
1867
|
-
] })
|
|
1868
|
-
]
|
|
1445
|
+
type: "submit",
|
|
1446
|
+
disabled: loading,
|
|
1447
|
+
className: "inline-flex h-9 w-full items-center justify-center whitespace-nowrap rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-slate-50 shadow transition-colors hover:bg-slate-900/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:pointer-events-none disabled:opacity-50",
|
|
1448
|
+
children: loading ? "Logging in..." : "Login"
|
|
1869
1449
|
}
|
|
1870
1450
|
)
|
|
1871
|
-
}
|
|
1872
|
-
);
|
|
1451
|
+
] }) })
|
|
1452
|
+
] }) });
|
|
1873
1453
|
}
|
|
1874
1454
|
|
|
1875
1455
|
// src/middleware/auth.ts
|
|
@@ -2153,20 +1733,48 @@ export const config = {
|
|
|
2153
1733
|
);
|
|
2154
1734
|
console.log("\u2705 Created middleware.ts");
|
|
2155
1735
|
}
|
|
2156
|
-
|
|
2157
|
-
await
|
|
2158
|
-
|
|
2159
|
-
|
|
1736
|
+
console.log("\n\u2699\uFE0F Configuration");
|
|
1737
|
+
const rl = await import("readline");
|
|
1738
|
+
const askQuestion = (query) => {
|
|
1739
|
+
const interface_ = rl.createInterface({
|
|
1740
|
+
input: process.stdin,
|
|
1741
|
+
output: process.stdout
|
|
1742
|
+
});
|
|
1743
|
+
return new Promise((resolve) => {
|
|
1744
|
+
interface_.question(query, (ans) => {
|
|
1745
|
+
interface_.close();
|
|
1746
|
+
resolve(ans);
|
|
1747
|
+
});
|
|
1748
|
+
});
|
|
1749
|
+
};
|
|
1750
|
+
const storageChoice = await askQuestion(
|
|
1751
|
+
"Select production storage provider:\n 1. GitHub (default)\n 2. S3 / Cloudflare R2 / Vercel Blob\nEnter choice [1]: "
|
|
1752
|
+
);
|
|
1753
|
+
const isS3 = storageChoice.trim() === "2";
|
|
1754
|
+
let envContent = `CMS_ADMIN_USERNAME=admin
|
|
2160
1755
|
CMS_ADMIN_PASSWORD=password
|
|
2161
1756
|
CMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string
|
|
2162
1757
|
|
|
2163
|
-
|
|
1758
|
+
`;
|
|
1759
|
+
if (isS3) {
|
|
1760
|
+
envContent += `# S3 / Cloudflare R2 / Vercel Blob Storage
|
|
1761
|
+
STORAGE_BUCKET=my-bucket
|
|
1762
|
+
STORAGE_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com
|
|
1763
|
+
STORAGE_ACCESS_KEY_ID=
|
|
1764
|
+
STORAGE_SECRET_ACCESS_KEY=
|
|
1765
|
+
STORAGE_REGION=auto
|
|
1766
|
+
STORAGE_PUBLIC_URL=https://pub-<id>.r2.dev
|
|
1767
|
+
`;
|
|
1768
|
+
} else {
|
|
1769
|
+
envContent += `# GitHub Storage (Production)
|
|
1770
|
+
# Generate at https://github.com/settings/tokens (Needs 'repo' or 'contents:write' scope)
|
|
2164
1771
|
GITHUB_TOKEN=
|
|
2165
1772
|
GITHUB_REPO=owner/repo
|
|
2166
1773
|
GITHUB_BRANCH=main
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
);
|
|
1774
|
+
`;
|
|
1775
|
+
}
|
|
1776
|
+
const envExamplePath = import_path3.default.join(process.cwd(), ".env.local.example");
|
|
1777
|
+
await import_promises2.default.writeFile(envExamplePath, envContent, "utf-8");
|
|
2170
1778
|
console.log("");
|
|
2171
1779
|
console.log("\u{1F389} CMS initialized successfully!");
|
|
2172
1780
|
console.log(
|