mirror of
https://github.com/shadoll/sLogos.git
synced 2026-02-04 11:03:24 +00:00
Enhance Header and List components with compact mode functionality
This commit is contained in:
@@ -663,28 +663,6 @@
|
|||||||
],
|
],
|
||||||
"brand": "PostgreSQL"
|
"brand": "PostgreSQL"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Privat24",
|
|
||||||
"path": "logos/privat24.svg",
|
|
||||||
"format": "SVG",
|
|
||||||
"disable": false,
|
|
||||||
"brand": "PrivatBank",
|
|
||||||
"tags": [
|
|
||||||
"bank",
|
|
||||||
"finance"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Privat24 Bussiness",
|
|
||||||
"path": "logos/privat24bussiness.svg",
|
|
||||||
"format": "SVG",
|
|
||||||
"disable": false,
|
|
||||||
"brand": "PrivatBank",
|
|
||||||
"tags": [
|
|
||||||
"bank",
|
|
||||||
"finance"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Privatbank",
|
"name": "Privatbank",
|
||||||
"path": "logos/privatbank.svg",
|
"path": "logos/privatbank.svg",
|
||||||
@@ -707,6 +685,28 @@
|
|||||||
"finance"
|
"finance"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Privat24",
|
||||||
|
"path": "logos/privat24.svg",
|
||||||
|
"format": "SVG",
|
||||||
|
"disable": false,
|
||||||
|
"brand": "PrivatBank",
|
||||||
|
"tags": [
|
||||||
|
"bank",
|
||||||
|
"finance"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Privat24 Bussiness",
|
||||||
|
"path": "logos/privat24bussiness.svg",
|
||||||
|
"format": "SVG",
|
||||||
|
"disable": false,
|
||||||
|
"brand": "PrivatBank",
|
||||||
|
"tags": [
|
||||||
|
"bank",
|
||||||
|
"finance"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Puma",
|
"name": "Puma",
|
||||||
"path": "logos/puma.svg",
|
"path": "logos/puma.svg",
|
||||||
|
|||||||
@@ -516,6 +516,7 @@ div.logo-image img {
|
|||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
|
padding-top: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-switcher {
|
.theme-switcher {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
let searchQuery = "";
|
let searchQuery = "";
|
||||||
let logos = [];
|
let logos = [];
|
||||||
let filteredLogos = [];
|
let filteredLogos = [];
|
||||||
|
let displayLogos = [];
|
||||||
let theme = "system";
|
let theme = "system";
|
||||||
let mq;
|
let mq;
|
||||||
let allTags = [];
|
let allTags = [];
|
||||||
@@ -16,11 +17,17 @@
|
|||||||
let tagDropdownOpen = false;
|
let tagDropdownOpen = false;
|
||||||
let showModal = false;
|
let showModal = false;
|
||||||
let selectedLogo = null;
|
let selectedLogo = null;
|
||||||
|
let compactMode = false;
|
||||||
|
|
||||||
function setSearchQuery(val) {
|
function setSearchQuery(val) {
|
||||||
searchQuery = val;
|
searchQuery = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setCompactMode(val) {
|
||||||
|
compactMode = val;
|
||||||
|
localStorage.setItem("compactMode", String(val));
|
||||||
|
}
|
||||||
|
|
||||||
// Load logos from JSON file with cache busting
|
// Load logos from JSON file with cache busting
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -72,6 +79,16 @@
|
|||||||
if (searchParam) {
|
if (searchParam) {
|
||||||
searchQuery = searchParam;
|
searchQuery = searchParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore view mode and compact mode from localStorage
|
||||||
|
const savedViewMode = localStorage.getItem("viewMode");
|
||||||
|
if (savedViewMode === "grid" || savedViewMode === "list") {
|
||||||
|
viewMode = savedViewMode;
|
||||||
|
}
|
||||||
|
const savedCompact = localStorage.getItem("compactMode");
|
||||||
|
if (savedCompact === "true" || savedCompact === "false") {
|
||||||
|
setCompactMode(savedCompact === "true");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure to apply theme whenever it changes
|
// Make sure to apply theme whenever it changes
|
||||||
@@ -104,6 +121,11 @@
|
|||||||
return matchesSearch && matchesTags;
|
return matchesSearch && matchesTags;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$: displayLogos = (!searchQuery && compactMode)
|
||||||
|
? filteredLogos.filter((logo, idx, arr) =>
|
||||||
|
arr.findIndex(l => (l.brand || l.name) === (logo.brand || logo.name)) === idx)
|
||||||
|
: filteredLogos;
|
||||||
|
|
||||||
// Compute the effective theme for children
|
// Compute the effective theme for children
|
||||||
$: effectiveTheme =
|
$: effectiveTheme =
|
||||||
theme === "system"
|
theme === "system"
|
||||||
@@ -115,11 +137,13 @@
|
|||||||
function setGridView() {
|
function setGridView() {
|
||||||
console.log("Setting view mode to: grid");
|
console.log("Setting view mode to: grid");
|
||||||
viewMode = "grid";
|
viewMode = "grid";
|
||||||
|
localStorage.setItem("viewMode", "grid");
|
||||||
}
|
}
|
||||||
|
|
||||||
function setListView() {
|
function setListView() {
|
||||||
console.log("Setting view mode to: list");
|
console.log("Setting view mode to: list");
|
||||||
viewMode = "list";
|
viewMode = "list";
|
||||||
|
localStorage.setItem("viewMode", "list");
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyUrl(logoPath) {
|
function copyUrl(logoPath) {
|
||||||
@@ -257,7 +281,8 @@
|
|||||||
|
|
||||||
<main class="container app-flex">
|
<main class="container app-flex">
|
||||||
<Header
|
<Header
|
||||||
{logos}
|
logos={logos}
|
||||||
|
displayLogos={displayLogos}
|
||||||
{theme}
|
{theme}
|
||||||
{setTheme}
|
{setTheme}
|
||||||
{viewMode}
|
{viewMode}
|
||||||
@@ -275,6 +300,8 @@
|
|||||||
{getTagObj}
|
{getTagObj}
|
||||||
{closeDropdown}
|
{closeDropdown}
|
||||||
{filteredLogos}
|
{filteredLogos}
|
||||||
|
{compactMode}
|
||||||
|
setCompactMode={setCompactMode}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Preview
|
<Preview
|
||||||
@@ -288,20 +315,22 @@
|
|||||||
<div class="logos-container main-content">
|
<div class="logos-container main-content">
|
||||||
{#if viewMode === "grid"}
|
{#if viewMode === "grid"}
|
||||||
<Grid
|
<Grid
|
||||||
logos={filteredLogos}
|
logos={displayLogos}
|
||||||
onCopy={copyUrl}
|
onCopy={copyUrl}
|
||||||
onDownload={downloadLogo}
|
onDownload={downloadLogo}
|
||||||
theme={effectiveTheme}
|
theme={effectiveTheme}
|
||||||
setSearchQuery={setSearchQuery}
|
setSearchQuery={setSearchQuery}
|
||||||
on:openPreview={(e) => openPreview(e.detail)}
|
on:openPreview={(e) => openPreview(e.detail)}
|
||||||
|
{compactMode}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<List
|
<List
|
||||||
logos={filteredLogos}
|
logos={displayLogos}
|
||||||
onCopy={copyUrl}
|
onCopy={copyUrl}
|
||||||
onDownload={downloadLogo}
|
onDownload={downloadLogo}
|
||||||
setSearchQuery={setSearchQuery}
|
setSearchQuery={setSearchQuery}
|
||||||
on:openPreview={(e) => openPreview(e.detail)}
|
on:openPreview={(e) => openPreview(e.detail)}
|
||||||
|
{compactMode}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
export let logos = [];
|
export let logos = [];
|
||||||
|
export let displayLogos = [];
|
||||||
export let theme;
|
export let theme;
|
||||||
export let setTheme;
|
export let setTheme;
|
||||||
export let viewMode;
|
export let viewMode;
|
||||||
@@ -16,6 +17,8 @@
|
|||||||
export let addTag;
|
export let addTag;
|
||||||
export let removeTag;
|
export let removeTag;
|
||||||
export let getTagObj;
|
export let getTagObj;
|
||||||
|
export let compactMode = false;
|
||||||
|
export let setCompactMode = () => {};
|
||||||
|
|
||||||
function onInput(event) {
|
function onInput(event) {
|
||||||
searchQuery = event.target.value;
|
searchQuery = event.target.value;
|
||||||
@@ -23,19 +26,27 @@
|
|||||||
// Update URL with search param
|
// Update URL with search param
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
if (searchQuery) {
|
if (searchQuery) {
|
||||||
params.set('search', searchQuery);
|
params.set("search", searchQuery);
|
||||||
} else {
|
} else {
|
||||||
params.delete('search');
|
params.delete("search");
|
||||||
}
|
}
|
||||||
const newUrl = window.location.pathname + (params.toString() ? '?' + params.toString() : '');
|
const newUrl =
|
||||||
history.replaceState(null, '', newUrl);
|
window.location.pathname +
|
||||||
|
(params.toString() ? "?" + params.toString() : "");
|
||||||
|
history.replaceState(null, "", newUrl);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="main-header">
|
<header class="main-header">
|
||||||
<div class="header-row">
|
<div class="header-row">
|
||||||
<h1>Logo Gallery</h1>
|
<h1>Logo Gallery</h1>
|
||||||
<span class="logo-count">{logos.length} images in gallery</span>
|
<span class="logo-count">
|
||||||
|
{#if displayLogos && logos && displayLogos.length === logos.length}
|
||||||
|
{logos.length} images in gallery
|
||||||
|
{:else}
|
||||||
|
{displayLogos ? displayLogos.length : 0} of {logos ? logos.length : 0} images displayed
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
<div class="theme-switcher">
|
<div class="theme-switcher">
|
||||||
<div class="theme-switch-group">
|
<div class="theme-switch-group">
|
||||||
<button
|
<button
|
||||||
@@ -117,9 +128,33 @@
|
|||||||
aria-label="Search logos"
|
aria-label="Search logos"
|
||||||
/>
|
/>
|
||||||
{#if searchQuery}
|
{#if searchQuery}
|
||||||
<button class="clear-btn" on:click={() => { searchQuery = ''; setSearchQuery(''); const params = new URLSearchParams(window.location.search); params.delete('search'); const newUrl = window.location.pathname + (params.toString() ? '?' + params.toString() : ''); history.replaceState(null, '', newUrl); }} aria-label="Clear search">
|
<button
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
class="clear-btn"
|
||||||
<path d="M4 4L12 12M12 4L4 12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
on:click={() => {
|
||||||
|
searchQuery = "";
|
||||||
|
setSearchQuery("");
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
params.delete("search");
|
||||||
|
const newUrl =
|
||||||
|
window.location.pathname +
|
||||||
|
(params.toString() ? "?" + params.toString() : "");
|
||||||
|
history.replaceState(null, "", newUrl);
|
||||||
|
}}
|
||||||
|
aria-label="Clear search"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M4 4L12 12M12 4L4 12"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -163,6 +198,47 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="view-toggle">
|
<div class="view-toggle">
|
||||||
|
<button
|
||||||
|
class="compact-switch-btn"
|
||||||
|
aria-label="Toggle compact mode"
|
||||||
|
class:active={compactMode}
|
||||||
|
on:click={() => setCompactMode(!compactMode)}
|
||||||
|
title="Show only one logo per brand (compact mode)"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10 11L3 11"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10 16H3"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14 13.5L16.1 16L20 11"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M3 6L13.5 6M20 6L17.75 6"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class:active={viewMode === "grid"}
|
class:active={viewMode === "grid"}
|
||||||
on:click={setGridView}
|
on:click={setGridView}
|
||||||
@@ -184,7 +260,8 @@
|
|||||||
x="11"
|
x="11"
|
||||||
y="11"
|
y="11"
|
||||||
width="6"
|
width="6"
|
||||||
height="6" fill="currentColor"
|
height="6"
|
||||||
|
fill="currentColor"
|
||||||
/></svg
|
/></svg
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
@@ -238,4 +315,24 @@
|
|||||||
.clear-btn:hover {
|
.clear-btn:hover {
|
||||||
color: #f44336;
|
color: #f44336;
|
||||||
}
|
}
|
||||||
|
.compact-switch-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.3em 0.6em;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
transition:
|
||||||
|
background 0.2s,
|
||||||
|
color 0.2s;
|
||||||
|
}
|
||||||
|
.compact-switch-btn.active,
|
||||||
|
.compact-switch-btn:hover {
|
||||||
|
background: var(--color-accent, #4f8cff);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -226,7 +226,7 @@
|
|||||||
margin-left: 0.5em;
|
margin-left: 0.5em;
|
||||||
}
|
}
|
||||||
.brand-filter-btn:hover {
|
.brand-filter-btn:hover {
|
||||||
background: var(--color-accent, #4f8cff);
|
background: var(--color-accent-light, #e0f0ff);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.brand-filter-btn.common-btn {
|
.brand-filter-btn.common-btn {
|
||||||
|
|||||||
Reference in New Issue
Block a user