Theme editor UI refinement
This commit is contained in:
@ -96,8 +96,8 @@ function renderLocalFonts(fonts) {
|
|||||||
fonts.forEach(font => {
|
fonts.forEach(font => {
|
||||||
listDiv.innerHTML += `
|
listDiv.innerHTML += `
|
||||||
<div class="font-item">
|
<div class="font-item">
|
||||||
<span>${font}</span>
|
<span class="font-name">${font}</span>
|
||||||
<button type="button" class="remove-font-btn danger" data-font="${font}">Remove</button>
|
<button type="button" class="remove-font-btn danger remove-btn" data-font="${font}">🗑️</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
@ -170,30 +170,28 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fontUploadInput) {
|
if (fontUploadInput) {
|
||||||
fontUploadInput.addEventListener("change", async (e) => {
|
fontUploadInput.addEventListener("change", async (e) => {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const ext = file.name.split('.').pop().toLowerCase();
|
const ext = file.name.split('.').pop().toLowerCase();
|
||||||
if (!["woff", "woff2"].includes(ext)) {
|
if (!["woff", "woff2"].includes(ext)) {
|
||||||
fontUploadStatus.textContent = "Only .woff and .woff2 fonts are allowed.";
|
showToast("Only .woff and .woff2 fonts are allowed.", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
formData.append("file", file);
|
||||||
formData.append("theme", themeInfo.theme_name);
|
formData.append("theme", themeInfo.theme_name);
|
||||||
const res = await fetch("/api/font/upload", { method: "POST", body: formData });
|
const res = await fetch("/api/font/upload", { method: "POST", body: formData });
|
||||||
const result = await res.json();
|
const result = await res.json();
|
||||||
if (result.status === "ok") {
|
if (result.status === "ok") {
|
||||||
fontUploadStatus.textContent = "Font uploaded!";
|
showToast("✅ Font uploaded!", "success");
|
||||||
showToast("Font uploaded!", "success");
|
localFonts = await fetchLocalFonts(themeInfo.theme_name);
|
||||||
localFonts = await fetchLocalFonts(themeInfo.theme_name);
|
refreshLocalFonts();
|
||||||
refreshLocalFonts();
|
} else {
|
||||||
} else {
|
showToast("Error uploading font.", "error");
|
||||||
fontUploadStatus.textContent = "Error uploading font.";
|
}
|
||||||
showToast("Error uploading font.", "error");
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove font button triggers modal
|
// Remove font button triggers modal
|
||||||
if (localFontsList) {
|
if (localFontsList) {
|
||||||
@ -223,7 +221,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
if (!fontToDelete) return;
|
if (!fontToDelete) return;
|
||||||
const result = await removeFont(themeInfo.theme_name, fontToDelete);
|
const result = await removeFont(themeInfo.theme_name, fontToDelete);
|
||||||
if (result.status === "ok") {
|
if (result.status === "ok") {
|
||||||
showToast("Font removed!", "success");
|
showToast("Font removed!", "✅ success");
|
||||||
localFonts = await fetchLocalFonts(themeInfo.theme_name);
|
localFonts = await fetchLocalFonts(themeInfo.theme_name);
|
||||||
refreshLocalFonts();
|
refreshLocalFonts();
|
||||||
} else {
|
} else {
|
||||||
@ -282,7 +280,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
if (result.status === "ok") {
|
if (result.status === "ok") {
|
||||||
faviconInput.value = result.filename;
|
faviconInput.value = result.filename;
|
||||||
updateFaviconPreview(`/themes/${themeInfo.theme_name}/${result.filename}?t=${Date.now()}`);
|
updateFaviconPreview(`/themes/${themeInfo.theme_name}/${result.filename}?t=${Date.now()}`);
|
||||||
showToast("Favicon uploaded!", "success");
|
showToast("✅ Favicon uploaded!", "success");
|
||||||
} else {
|
} else {
|
||||||
showToast("Error uploading favicon", "error");
|
showToast("Error uploading favicon", "error");
|
||||||
}
|
}
|
||||||
@ -314,7 +312,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
if (result.status === "ok") {
|
if (result.status === "ok") {
|
||||||
faviconInput.value = "";
|
faviconInput.value = "";
|
||||||
updateFaviconPreview("");
|
updateFaviconPreview("");
|
||||||
showToast("Favicon removed!", "success");
|
showToast("✅ Favicon removed!", "success");
|
||||||
} else {
|
} else {
|
||||||
showToast("Error removing favicon", "error");
|
showToast("Error removing favicon", "error");
|
||||||
}
|
}
|
||||||
@ -393,7 +391,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
body: JSON.stringify({ theme_name: themeInfo.theme_name, theme_yaml: data })
|
body: JSON.stringify({ theme_name: themeInfo.theme_name, theme_yaml: data })
|
||||||
});
|
});
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
showToast("Theme saved!", "success");
|
showToast("✅ Theme saved!", "success");
|
||||||
} else {
|
} else {
|
||||||
showToast("Error saving theme.", "error");
|
showToast("Error saving theme.", "error");
|
||||||
}
|
}
|
||||||
|
@ -693,3 +693,28 @@ input[type="color"].color-input {
|
|||||||
top:0;
|
top:0;
|
||||||
opacity:0;
|
opacity:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fieldset p {
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: italic;
|
||||||
|
color: #b3b3b3;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-name {
|
||||||
|
background: #1f2223;
|
||||||
|
color: #b3b3b3;
|
||||||
|
border: 1px solid #585858;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
padding: 10px 14px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s, background 0.2s;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.07);
|
||||||
|
}
|
||||||
|
|
||||||
|
#theme-editor-form button[type="button"]#choose-font-btn {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
@ -50,6 +50,7 @@
|
|||||||
<!-- Colors Section -->
|
<!-- Colors Section -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<h2>Colors</h2>
|
<h2>Colors</h2>
|
||||||
|
<p>Set the color values for your theme</p>
|
||||||
<div class="fields">
|
<div class="fields">
|
||||||
<!-- Example for one color field, repeat for all -->
|
<!-- Example for one color field, repeat for all -->
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
@ -113,6 +114,7 @@
|
|||||||
<!-- Google Fonts Section -->
|
<!-- Google Fonts Section -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<h2>Google Fonts</h2>
|
<h2>Google Fonts</h2>
|
||||||
|
<p>Add Google Fonts to your theme</p>
|
||||||
<div class="fields" id="google-fonts-fields">
|
<div class="fields" id="google-fonts-fields">
|
||||||
<!-- JS will render font family and weights inputs here -->
|
<!-- JS will render font family and weights inputs here -->
|
||||||
</div>
|
</div>
|
||||||
@ -120,17 +122,16 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<!-- Custom Font Upload Section -->
|
<!-- Custom Font Upload Section -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<h2>Upload Custom Font (.woff, .woff2)</h2>
|
<h2>Upload Custom Font</h2>
|
||||||
<div class="fields">
|
<p>Supported formats: .woff, .woff2</p>
|
||||||
<input type="file" id="font-upload" accept=".woff,.woff2" style="display:none;">
|
<input type="file" id="font-upload" accept=".woff,.woff2" style="display:none;">
|
||||||
<button type="button" id="choose-font-btn" class="up-btn">🖋️ Upload font</button>
|
|
||||||
<div id="local-fonts-list" class="font-list"></div>
|
<div id="local-fonts-list" class="font-list"></div>
|
||||||
<span id="font-upload-status"></span>
|
<button type="button" id="choose-font-btn" class="up-btn">🖋️ Upload font</button>
|
||||||
</div>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<!-- Fonts Section -->
|
<!-- Fonts Section -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<h2>Fonts</h2>
|
<h2>Fonts</h2>
|
||||||
|
<p>Select where to apply your fonts</p>
|
||||||
<div class="fields">
|
<div class="fields">
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<label>Primary Font</label>
|
<label>Primary Font</label>
|
||||||
@ -155,6 +156,7 @@
|
|||||||
<!-- Favicon Section -->
|
<!-- Favicon Section -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<h2>Favicon</h2>
|
<h2>Favicon</h2>
|
||||||
|
<p>Supported formats: .png, .jpg, .jpeg</p>
|
||||||
<div class="fields">
|
<div class="fields">
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<label>Favicon Path</label>
|
<label>Favicon Path</label>
|
||||||
|
Reference in New Issue
Block a user