From f04968c854f220d2fd42c0e1194f20420dc613a0 Mon Sep 17 00:00:00 2001 From: Andrew Zambazos Date: Sat, 26 Jul 2025 10:51:20 +1200 Subject: [PATCH] Redesign add bookmark popup and improve icon picker Updated the add bookmark popup with a more modern Material card style, clearer field labels, and improved layout. The icon picker now fetches the full list of Material Icons asynchronously from Google Fonts, with a fallback to a minimal static set for immediate use. Enhanced the icon grid UI and selection logic for better usability. --- renderer/home.css | 124 +++++++++++++++++++++++++++++----- renderer/home.html | 25 ++++--- renderer/home.js | 25 +++++-- renderer/icons.js | 162 ++++++--------------------------------------- 4 files changed, 164 insertions(+), 172 deletions(-) diff --git a/renderer/home.css b/renderer/home.css index 7e41204..3ecbf75 100644 --- a/renderer/home.css +++ b/renderer/home.css @@ -202,48 +202,138 @@ body, html { align-items: center; justify-content: center; z-index: 99; + backdrop-filter: blur(4px); /* add subtle blur behind the overlay */ } .popup.hidden { display: none; } +/* Popup inner as white Material card */ .popup-inner { - background: var(--dark-purple); - padding: 2rem; - border-radius: 12px; display: flex; flex-direction: column; - gap: 1rem; - color: var(--text); - min-width: 300px; + gap: 1.5rem; + color: #222222; + min-width: 320px; + /* existing styling */ + background: #ffffff; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0,0,0,0.3); + padding: 1.5rem; + transition: transform 0.3s ease-out, opacity 0.3s ease-out; + transform: translateY(-10px) scale(0.95); + opacity: 0; + width: 500px; /* make popup wider */ + max-width: 90vw; /* keep it responsive on small screens */ } -.popup-inner input { +/* animate in when not hidden */ +.popup:not(.hidden) .popup-inner { + transform: translateY(0) scale(1); + opacity: 1; +} + +/* dialog title */ +.popup-inner h2 { + margin: 0 0 1rem; + font-size: 1.5rem; + text-align: center; + color: #333333; +} + +/* field labels */ +.popup-inner label { + display: block; + margin-bottom: 0.25rem; + font-size: 0.875rem; + color: #555555; +} + +/* text/url/icon inputs */ +.popup-inner input[type="text"], +.popup-inner input[type="url"] { + width: 100%; + background: #f5f5f5; + border: 1px solid #ccc; + border-radius: 4px; + padding: 0.75rem 1rem; + font-size: 1rem; + color: #222222; + margin-bottom: 1rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.popup-inner input[type="text"]:focus, +.popup-inner input[type="url"]:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(123,46,255,0.2); +} + +/* icon-grid container */ +.icon-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); + gap: 8px; + max-height: 200px; + overflow-y: auto; + margin: 0 -0.5rem 1rem; padding: 0.5rem; - background: var(--dark-blue); - border: none; - color: var(--text); - border-radius: 6px; + background: #fafafa; + border: 1px solid #eee; + border-radius: 4px; } +/* individual icon items */ +.icon-item { + background: #ffffff; + border: 1px solid #ddd; + box-shadow: 0 1px 2px rgba(0,0,0,0.05); + border-radius: 4px; + cursor: pointer; + padding: 4px; + text-align: center; +} + +.icon-item:hover { + background: #f0f0f0; +} + +/* action buttons container */ .popup-buttons { display: flex; justify-content: flex-end; - gap: 1rem; + gap: 0.75rem; } .popup-buttons button { + min-width: 80px; padding: 0.5rem 1rem; - background: var(--primary); + font-size: 0.875rem; + border-radius: 4px; border: none; - border-radius: 6px; - color: white; cursor: pointer; } -.popup-buttons button:hover { - background: var(--accent); +/* Cancel button */ +#cancelBtn { + background: #e0e0e0; + color: #222222; +} + +#cancelBtn:hover { + background: #d5d5d5; +} + +/* Add button */ +#saveBookmarkBtn { + background: var(--primary); + color: #ffffff; +} + +#saveBookmarkBtn:hover { + background: #6a24e5; } /* Color Palette */ diff --git a/renderer/home.html b/renderer/home.html index 27f5e01..eb111d5 100644 --- a/renderer/home.html +++ b/renderer/home.html @@ -30,18 +30,27 @@ diff --git a/renderer/home.js b/renderer/home.js index c9644b1..dc89d9a 100644 --- a/renderer/home.js +++ b/renderer/home.js @@ -1,4 +1,4 @@ -import { icons } from './icons.js'; +import { icons as initialIcons, fetchAllIcons } from './icons.js'; const BOOKMARKS_KEY = 'steamos_browser_bookmarks'; @@ -13,7 +13,8 @@ const searchInput = document.getElementById('searchInput'); const iconFilter = document.getElementById('iconFilter'); const iconGrid = document.getElementById('iconGrid'); const selectedIconInput= document.getElementById('selectedIcon'); -let selectedIcon = icons[0]; +let selectedIcon = initialIcons[0]; +let availableIcons = initialIcons; let bookmarks = JSON.parse(localStorage.getItem(BOOKMARKS_KEY)) || []; @@ -69,15 +70,17 @@ function renderBookmarks() { // draw the icon‐grid, filtering by the search term function renderIconGrid(filter = '') { iconGrid.innerHTML = ''; - icons + availableIcons .filter(name => name.includes(filter)) .forEach(name => { const span = document.createElement('span'); span.className = 'material-symbols-outlined icon-item'; span.textContent = name; span.onclick = () => { - iconGrid.querySelectorAll('.icon-item') - .forEach(el => el.classList.remove('selected')); + const currentSelected = iconGrid.querySelector('.icon-item.selected'); + if (currentSelected) { + currentSelected.classList.remove('selected'); + } span.classList.add('selected'); selectedIcon = name; selectedIconInput.value = name; @@ -96,6 +99,18 @@ iconFilter.addEventListener('input', () => // initial render renderIconGrid(); +// Asynchronously fetch all icons and update the grid +(async () => { + try { + const allIcons = await fetchAllIcons(); + availableIcons = allIcons; + // Re-render with the full list, preserving any filter text + renderIconGrid(iconFilter.value.trim().toLowerCase()); + } catch (error) { + console.error('Failed to fetch all icons:', error); + } +})(); + saveBookmarkBtn.onclick = () => { const title = titleInput.value.trim(); const url = urlInput.value.trim(); diff --git a/renderer/icons.js b/renderer/icons.js index dd332b0..988991a 100644 --- a/renderer/icons.js +++ b/renderer/icons.js @@ -1,143 +1,21 @@ -export const icons = [ - 'home', - 'star', - 'bookmark', - 'favorite', - 'public', - 'search', - 'settings', - '3d_rotation', - 'ac_unit', - 'access_alarm', - 'access_alarms', - 'access_time', - 'accessibility', - 'accessibility_new', - 'accessible', - 'accessible_forward', - 'account_balance', - 'account_balance_wallet', - 'account_box', - 'account_circle', - 'adb', - 'add', - 'add_a_photo', - 'add_alarm', - 'add_alert', - 'add_box', - 'add_business', - 'add_call', - 'add_circle', - 'add_circle_outline', - 'add_comment', - 'add_home', - 'add_ic_call', - 'add_link', - 'add_location', - 'add_photo_alternate', - 'add_road', - 'add_shopping_cart', - 'add_task', - 'add_to_drive', - 'add_to_home_screen', - 'add_to_photos', - 'add_to_queue', - 'adjust', - 'admin_panel_settings', - 'agriculture', - 'airline_seat_flat', - 'airline_seat_flat_angled', - 'airline_seat_individual_suite', - 'airline_seat_legroom_extra', - 'airline_seat_legroom_normal', - 'airline_seat_legroom_reduced', - 'airline_seat_recline_extra', - 'airline_seat_recline_normal', - 'airplanemode_active', - 'airplanemode_inactive', - 'airplay', - 'airport_shuttle', - 'alarm', - 'alarm_add', - 'alarm_off', - 'alarm_on', - 'album', - 'align_horizontal_center', - 'align_horizontal_left', - 'align_horizontal_right', - 'align_vertical_bottom', - 'align_vertical_center', - 'align_vertical_top', - 'all_inbox', - 'all_inclusive', - 'all_out', - 'alt_route', - 'analytics', - 'anchor', - 'android', - 'animation', - 'announcement', - 'apartment', - 'api', - 'app_blocking', - 'app_registration', - 'app_settings_alt', - 'approval', - 'apps', - 'archive', - 'area_chart', - 'arrow_back', - 'arrow_back_ios', - 'arrow_circle_down', - 'arrow_circle_up', - 'arrow_downward', - 'arrow_drop_down', - 'arrow_drop_down_circle', - 'arrow_drop_up', - 'arrow_forward', - 'arrow_forward_ios', - 'arrow_left', - 'arrow_right', - 'arrow_right_alt', - 'arrow_upward', - 'art_track', - 'article', - 'aspect_ratio', - 'assessment', - 'assignment', - 'assignment_ind', - 'assignment_late', - 'assignment_return', - 'assignment_returned', - 'assignment_turned_in', - 'assistant', - 'assistant_photo', - 'atm', - 'attach_email', - 'attach_file', - 'attach_money', - 'attachment', - 'attractions', - 'attribution', - 'audiotrack', - 'auto_awesome', - 'auto_awesome_mosaic', - 'auto_delete', - 'auto_fix_high', - 'auto_fix_normal', - 'auto_fix_off', - 'auto_graph', - 'auto_stories', - 'autorenew', - 'av_timer', - 'baby_changing_station', - 'backpack', - 'backspace', - 'backup', - 'badge', - 'zoom_in', - 'zoom_out', - 'zoom_out_map' -]; +// This file is automatically generated from Google's Material Icons. +/** + * Fetches the full list of Material Icon names from Google Fonts. + * Returns an array of strings like ["3d_rotation","access_alarm",…] + */ +export async function fetchAllIcons() { + const res = await fetch("https://fonts.google.com/metadata/icons"); + let txt = await res.text(); + // strip the weird prefix )]}'\n + txt = txt.replace(/^\)\]\}'\s*/, ""); + const json = JSON.parse(txt); + return json.icons.map(icon => icon.name); +} -//Icons from fonts.google.com/icons \ No newline at end of file +// Fallback static array for immediate use (e.g. the "+" button and bookmark icons) +export const icons = [ + 'add', + 'bookmark', + 'star', + // …add any other icons your components expect synchronously… +]; \ No newline at end of file