Add sidebar drawer icons and favicon
This commit is contained in:
+11
-1
@@ -19,6 +19,8 @@ const mappingList = document.querySelector("#mappingList");
|
|||||||
const mappingDetails = document.querySelector("#mappingDetails");
|
const mappingDetails = document.querySelector("#mappingDetails");
|
||||||
const findSourcesButton = document.querySelector("#findSourcesButton");
|
const findSourcesButton = document.querySelector("#findSourcesButton");
|
||||||
const getPicturesButton = document.querySelector("#getPicturesButton");
|
const getPicturesButton = document.querySelector("#getPicturesButton");
|
||||||
|
const parserDrawerToggle = document.querySelector("#parserDrawerToggle");
|
||||||
|
const parserDrawer = document.querySelector("#parserDrawer");
|
||||||
const sourceModal = document.querySelector("#sourceModal");
|
const sourceModal = document.querySelector("#sourceModal");
|
||||||
const sourceTitle = document.querySelector("#sourceTitle");
|
const sourceTitle = document.querySelector("#sourceTitle");
|
||||||
const sourceList = document.querySelector("#sourceList");
|
const sourceList = document.querySelector("#sourceList");
|
||||||
@@ -143,6 +145,7 @@ loadProductButton.title = "Load existing product attribute info.";
|
|||||||
loadProductButton.addEventListener("click", loadProductInfoForCurrentProduct);
|
loadProductButton.addEventListener("click", loadProductInfoForCurrentProduct);
|
||||||
findSourcesButton.addEventListener("click", findSourcesForCurrentProduct);
|
findSourcesButton.addEventListener("click", findSourcesForCurrentProduct);
|
||||||
getPicturesButton.addEventListener("click", getPicturesForCurrentProduct);
|
getPicturesButton.addEventListener("click", getPicturesForCurrentProduct);
|
||||||
|
parserDrawerToggle.addEventListener("click", toggleParserDrawer);
|
||||||
|
|
||||||
previousProductButton.addEventListener("click", () => {
|
previousProductButton.addEventListener("click", () => {
|
||||||
if (!manufacturerSelect.value || currentPosition <= 1) return;
|
if (!manufacturerSelect.value || currentPosition <= 1) return;
|
||||||
@@ -826,10 +829,17 @@ function openSettings() {
|
|||||||
settingsModal.hidden = false;
|
settingsModal.hidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleParserDrawer() {
|
||||||
|
const isOpen = !parserDrawer.hidden;
|
||||||
|
parserDrawer.hidden = isOpen;
|
||||||
|
parserDrawerToggle.setAttribute("aria-expanded", String(!isOpen));
|
||||||
|
parserDrawerToggle.querySelector(".drawer-chevron").textContent = isOpen ? "⌄" : "⌃";
|
||||||
|
}
|
||||||
|
|
||||||
function loadTheme() {
|
function loadTheme() {
|
||||||
const isDark = localStorage.getItem("catalog-maker:theme") === "dark";
|
const isDark = localStorage.getItem("catalog-maker:theme") === "dark";
|
||||||
document.documentElement.classList.toggle("dark", isDark);
|
document.documentElement.classList.toggle("dark", isDark);
|
||||||
themeToggle.textContent = isDark ? "Light theme" : "Dark theme";
|
themeToggle.querySelector("span").textContent = isDark ? "Light theme" : "Dark theme";
|
||||||
themeToggle.setAttribute("aria-pressed", String(isDark));
|
themeToggle.setAttribute("aria-pressed", String(isDark));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||||
|
<rect width="64" height="64" rx="12" fill="#22272e"/>
|
||||||
|
<path d="M16 14h32v8H24v8h18v8H24v12h-8z" fill="#7ee34d"/>
|
||||||
|
<circle cx="47" cy="46" r="7" fill="#f4f6f8"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 234 B |
@@ -0,0 +1,15 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<symbol id="search" viewBox="0 0 24 24"><path d="m21 21-4.35-4.35m1.35-5.4a6.75 6.75 0 1 1-13.5 0 6.75 6.75 0 0 1 13.5 0Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="image" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="2" fill="none" stroke="currentColor" stroke-width="1.8"/><circle cx="8" cy="9" r="1.5" fill="currentColor"/><path d="m4 17 4.5-4.5 3 3 2.5-2.5L20 17" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="sliders" viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h16M8 4v4M15 10v4M11 16v4" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="text" viewBox="0 0 24 24"><path d="M5 5h14M8 19h8M9 5v14m6-14v14" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="eye" viewBox="0 0 24 24"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z" fill="none" stroke="currentColor" stroke-width="1.8"/><circle cx="12" cy="12" r="2.5" fill="none" stroke="currentColor" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="save" viewBox="0 0 24 24"><path d="M5 3h11l3 3v15H5zM8 3v6h8V3M8 21v-7h8v7" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="info" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M12 11v5m0-8h.01" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="layers" viewBox="0 0 24 24"><path d="m12 4 9 5-9 5-9-5 9-5Zm-9 9 9 5 9-5M3 17l9 5 9-5" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="menu" viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="scan" viewBox="0 0 24 24"><path d="M4 7V5a1 1 0 0 1 1-1h2M17 4h2a1 1 0 0 1 1 1v2M20 17v2a1 1 0 0 1-1 1h-2M7 20H5a1 1 0 0 1-1-1v-2M7 12h10" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="erase" viewBox="0 0 24 24"><path d="m4 15 8-8a2 2 0 0 1 2.8 0l4.2 4.2a2 2 0 0 1 0 2.8l-5 5H7zM13 19h7" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="moon" viewBox="0 0 24 24"><path d="M20 15.5A8.5 8.5 0 0 1 8.5 4 8.5 8.5 0 1 0 20 15.5Z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="1.8"/></symbol>
|
||||||
|
<symbol id="settings" viewBox="0 0 24 24"><path d="M12 8.5a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7Z" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="m19 13.5 1.2 1-.2 2-1.5.8-.3 1.6-1.8.9-1.4-.7-1.5.7-1.8-.9-.3-1.6-1.5-.8-.2-2 1.2-1-.1-1.5-1.2-1 .2-2 1.5-.8.3-1.6 1.8-.9 1.4.7 1.5-.7 1.8.9.3 1.6 1.5.8.2 2-1.2 1.1.1 1.5Z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="1.4"/></symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
+23
-14
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Catalog Maker</title>
|
<title>Catalog Maker</title>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<link rel="stylesheet" href="/styles.css" />
|
<link rel="stylesheet" href="/styles.css" />
|
||||||
<script src="/app.js" type="module"></script>
|
<script src="/app.js" type="module"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -17,17 +18,25 @@
|
|||||||
<button class="arrow-button arrow-button-next" id="nextProductButton" type="button" title="Next product" aria-label="Next product"></button>
|
<button class="arrow-button arrow-button-next" id="nextProductButton" type="button" title="Next product" aria-label="Next product"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sidebar-section parser-actions" aria-label="Parser actions">
|
<button class="drawer-trigger" id="parserDrawerToggle" type="button" aria-expanded="true" aria-controls="parserDrawer">
|
||||||
<button class="action-button" id="findSourcesButton" type="button">Find sources</button>
|
<svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#sliders"></use></svg>
|
||||||
<button class="action-button" id="getPicturesButton" type="button">Get pictures</button>
|
<span>Parser tools</span>
|
||||||
<button class="action-button" type="button">Get features</button>
|
<span class="drawer-chevron" aria-hidden="true">⌃</span>
|
||||||
<button class="action-button" type="button">Get texts</button>
|
</button>
|
||||||
<button class="action-button" type="button">Preview parsed data</button>
|
|
||||||
<button class="action-button" type="button" disabled>Apply / Save</button>
|
<div class="sidebar-section parser-drawer" id="parserDrawer">
|
||||||
|
<div class="parser-actions" aria-label="Parser actions">
|
||||||
|
<button class="action-button" id="findSourcesButton" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#search"></use></svg><span>Find sources</span></button>
|
||||||
|
<button class="action-button" id="getPicturesButton" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#image"></use></svg><span>Get pictures</span></button>
|
||||||
|
<button class="action-button" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#sliders"></use></svg><span>Get features</span></button>
|
||||||
|
<button class="action-button" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#text"></use></svg><span>Get texts</span></button>
|
||||||
|
<button class="action-button" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#eye"></use></svg><span>Preview parsed data</span></button>
|
||||||
|
<button class="action-button" type="button" disabled><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#save"></use></svg><span>Apply / Save</span></button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="action-button" id="loadProductButton" type="button">Get product info - 00</button>
|
<button class="action-button" id="loadProductButton" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#info"></use></svg><span>Get product info - 00</span></button>
|
||||||
<button class="action-button" type="button">Creat combin. - 02</button>
|
<button class="action-button" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#layers"></use></svg><span>Creat combin. - 02</span></button>
|
||||||
|
|
||||||
<input class="input-like" id="scanInput" aria-label="Scan EAN" placeholder="Scan EAN" />
|
<input class="input-like" id="scanInput" aria-label="Scan EAN" placeholder="Scan EAN" />
|
||||||
|
|
||||||
@@ -53,15 +62,15 @@
|
|||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="action-button primary" type="button">Show menu (20)</button>
|
<button class="action-button primary" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#menu"></use></svg><span>Show menu (20)</span></button>
|
||||||
<button class="action-button" type="button">Scraper - 03</button>
|
<button class="action-button" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#scan"></use></svg><span>Scraper - 03</span></button>
|
||||||
<button class="action-button" type="button">BG remover - 04</button>
|
<button class="action-button" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#erase"></use></svg><span>BG remover - 04</span></button>
|
||||||
<div class="sidebar-footer">
|
<div class="sidebar-footer">
|
||||||
<div class="app-status">
|
<div class="app-status">
|
||||||
<span class="safe-mode" id="databaseStatus">DB read-only</span>
|
<span class="safe-mode" id="databaseStatus">DB read-only</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="action-button" id="themeToggle" type="button" aria-pressed="false">Dark theme</button>
|
<button class="action-button" id="themeToggle" type="button" aria-pressed="false"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#moon"></use></svg><span>Dark theme</span></button>
|
||||||
<button class="action-button" id="settingsButton" type="button">Settings</button>
|
<button class="action-button" id="settingsButton" type="button"><svg class="sidebar-icon" aria-hidden="true"><use href="/icons.svg#settings"></use></svg><span>Settings</span></button>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -44,6 +44,12 @@
|
|||||||
.catalog-screen { @apply grid min-h-screen grid-cols-[172px_292px_minmax(720px,1fr)] bg-catalog-surface; }
|
.catalog-screen { @apply grid min-h-screen grid-cols-[172px_292px_minmax(720px,1fr)] bg-catalog-surface; }
|
||||||
.control-panel { @apply flex min-h-screen flex-col gap-1.5 overflow-y-auto bg-slate-900 p-1.5 text-[11px] text-slate-200; }
|
.control-panel { @apply flex min-h-screen flex-col gap-1.5 overflow-y-auto bg-slate-900 p-1.5 text-[11px] text-slate-200; }
|
||||||
.sidebar-section { @apply border-t border-slate-700 pt-1; }
|
.sidebar-section { @apply border-t border-slate-700 pt-1; }
|
||||||
|
.drawer-trigger { @apply flex min-h-8 w-full items-center gap-2 rounded border border-slate-700 bg-slate-800 px-2 text-left text-[11px] font-semibold text-slate-100 transition hover:border-slate-500 hover:bg-slate-700; }
|
||||||
|
.drawer-trigger .drawer-chevron { @apply ml-auto text-sm text-slate-400; }
|
||||||
|
.parser-drawer[hidden] { display: none; }
|
||||||
|
.sidebar-icon { @apply inline-flex h-4 w-4 shrink-0 items-center justify-center text-sm leading-none text-slate-300; }
|
||||||
|
.action-button { @apply flex items-center justify-center gap-1.5; }
|
||||||
|
.action-button .sidebar-icon { @apply text-slate-400; }
|
||||||
.sidebar-footer { @apply mt-auto grid gap-1 border-t border-slate-700 pt-2; }
|
.sidebar-footer { @apply mt-auto grid gap-1 border-t border-slate-700 pt-2; }
|
||||||
.app-status { @apply rounded border border-slate-700 bg-slate-950 p-1 text-[10px] leading-tight text-slate-100; }
|
.app-status { @apply rounded border border-slate-700 bg-slate-950 p-1 text-[10px] leading-tight text-slate-100; }
|
||||||
.safe-mode, #modePill { @apply inline-block rounded bg-slate-100 px-1 py-0.5 text-[10px] font-semibold text-slate-800; }
|
.safe-mode, #modePill { @apply inline-block rounded bg-slate-100 px-1 py-0.5 text-[10px] font-semibold text-slate-800; }
|
||||||
|
|||||||
@@ -31,6 +31,14 @@ test("catalog maker remains usable on a narrow viewport", async ({ page }) => {
|
|||||||
await page.screenshot({ path: "test-results/catalog-maker-mobile.png", fullPage: true });
|
await page.screenshot({ path: "test-results/catalog-maker-mobile.png", fullPage: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("parser tools open in a sidebar drawer", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await expect(page.locator("#parserDrawer")).toBeVisible();
|
||||||
|
await page.locator("#parserDrawerToggle").click();
|
||||||
|
await expect(page.locator("#parserDrawer")).toBeHidden();
|
||||||
|
await expect(page.locator("#parserDrawerToggle")).toHaveAttribute("aria-expanded", "false");
|
||||||
|
});
|
||||||
|
|
||||||
test("theme toggle switches and persists dark mode", async ({ page }) => {
|
test("theme toggle switches and persists dark mode", async ({ page }) => {
|
||||||
await page.goto("/");
|
await page.goto("/");
|
||||||
await expect(page.locator("html")).not.toHaveClass(/dark/);
|
await expect(page.locator("html")).not.toHaveClass(/dark/);
|
||||||
|
|||||||
Reference in New Issue
Block a user