aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/app/components
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2025-11-19 22:34:07 +0100
committerAriel Costas Guerrero <ariel@costas.dev>2025-11-19 22:34:20 +0100
commit747c579b15c54dc5dbc50482d3361761853e007a (patch)
tree13587e5825bd5353fe75f4129c0746f28bba4cea /src/frontend/app/components
parentd51169f6411b68a226d76d2d39826904de484929 (diff)
feat: Refactor layout and styles for StopList and related components; add ThemeColorManager for dynamic theme support
Diffstat (limited to 'src/frontend/app/components')
-rw-r--r--src/frontend/app/components/ServiceAlerts.css5
-rw-r--r--src/frontend/app/components/ServiceAlerts.tsx2
-rw-r--r--src/frontend/app/components/StopGallery.css51
-rw-r--r--src/frontend/app/components/StopGallery.tsx42
-rw-r--r--src/frontend/app/components/StopItem.tsx15
-rw-r--r--src/frontend/app/components/ThemeColorManager.tsx20
-rw-r--r--src/frontend/app/components/layout/AppShell.tsx2
-rw-r--r--src/frontend/app/components/layout/Header.css1
8 files changed, 91 insertions, 47 deletions
diff --git a/src/frontend/app/components/ServiceAlerts.css b/src/frontend/app/components/ServiceAlerts.css
index 7c271f9..c0f67f5 100644
--- a/src/frontend/app/components/ServiceAlerts.css
+++ b/src/frontend/app/components/ServiceAlerts.css
@@ -1,6 +1,9 @@
/* Service Alerts Container */
.service-alerts-container {
- margin-bottom: 1.5rem;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
}
.service-alert {
diff --git a/src/frontend/app/components/ServiceAlerts.tsx b/src/frontend/app/components/ServiceAlerts.tsx
index eba8a92..a6a1ee8 100644
--- a/src/frontend/app/components/ServiceAlerts.tsx
+++ b/src/frontend/app/components/ServiceAlerts.tsx
@@ -6,7 +6,7 @@ const ServiceAlerts: React.FC = () => {
const { t } = useTranslation();
return (
- <div className="service-alerts-container">
+ <div className="service-alerts-container stoplist-section">
<h2 className="page-subtitle">{t("stoplist.service_alerts")}</h2>
<div className="service-alert info">
<div className="alert-icon">â„šī¸</div>
diff --git a/src/frontend/app/components/StopGallery.css b/src/frontend/app/components/StopGallery.css
index bc9b955..070a01f 100644
--- a/src/frontend/app/components/StopGallery.css
+++ b/src/frontend/app/components/StopGallery.css
@@ -1,13 +1,16 @@
/* Gallery Container */
.gallery-container {
- margin-bottom: 1.5rem;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
}
.gallery-header {
display: flex;
align-items: center;
justify-content: space-between;
- margin-bottom: 0.75rem;
+ margin-bottom: 0.5rem;
}
.gallery-counter {
@@ -24,6 +27,15 @@
font-weight: 600;
}
+/* Empty State */
+.gallery-empty-state {
+ text-align: center;
+}
+
+.gallery-empty-state .message {
+ font-size: 0.85rem;
+}
+
/* Scroll Container */
.gallery-scroll-container {
overflow-x: auto;
@@ -32,7 +44,6 @@
scroll-snap-type: x mandatory;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
- padding: 0 1rem;
}
.gallery-scroll-container::-webkit-scrollbar {
@@ -48,14 +59,15 @@
/* Gallery Item */
.gallery-item {
- flex: 0 0 100%;
+ flex: 0 0 90%;
+ max-width: 320px;
scroll-snap-align: start;
scroll-snap-stop: always;
}
.gallery-item-link {
display: block;
- padding: 1rem;
+ padding: 0.75rem;
background-color: var(
--card-background-color,
var(--message-background-color)
@@ -64,7 +76,7 @@
border-radius: 12px;
text-decoration: none;
color: var(--text-color);
- min-height: 120px;
+ min-height: 100px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
@@ -72,24 +84,24 @@
display: flex;
align-items: center;
gap: 0.5rem;
- margin-bottom: 0.5rem;
+ margin-bottom: 0.25rem;
}
.gallery-item-header .favourite-icon {
color: var(--star-color);
- font-size: 1rem;
+ font-size: 0.9rem;
}
.gallery-item-code {
- font-size: 0.85rem;
+ font-size: 0.8rem;
color: var(--subtitle-color);
font-weight: 500;
}
.gallery-item-name {
- font-size: 1rem;
+ font-size: 0.95rem;
font-weight: 600;
- margin-bottom: 0.75rem;
+ margin-bottom: 0.5rem;
line-height: 1.3;
display: -webkit-box;
/* Standard property for compatibility */
@@ -97,7 +109,7 @@
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
- min-height: 2.6em;
+ min-height: 2.5em;
}
.gallery-item-lines {
@@ -117,23 +129,22 @@
}
/* Gallery Indicators */
-.gallery-indicators {
+.gallery-dots {
display: flex;
justify-content: center;
- gap: 0.5rem;
- margin-top: 1rem;
- padding: 0.5rem 0;
+ gap: 0.35rem;
+ margin-top: 0.25rem;
}
-.gallery-indicator {
- width: 8px;
- height: 8px;
+.dot {
+ width: 6px;
+ height: 6px;
border-radius: 50%;
background-color: var(--border-color);
transition: background-color 0.2s ease-in-out;
}
-.gallery-indicator.active {
+.dot.active {
background-color: var(--button-background-color);
}
diff --git a/src/frontend/app/components/StopGallery.tsx b/src/frontend/app/components/StopGallery.tsx
index 18d0725..500ea20 100644
--- a/src/frontend/app/components/StopGallery.tsx
+++ b/src/frontend/app/components/StopGallery.tsx
@@ -1,7 +1,7 @@
-import React, { useRef, useState, useEffect } from "react";
+import React, { useEffect, useRef, useState } from "react";
import { type Stop } from "../data/StopDataProvider";
-import StopGalleryItem from "./StopGalleryItem";
import "./StopGallery.css";
+import StopGalleryItem from "./StopGalleryItem";
interface StopGalleryProps {
stops: Stop[];
@@ -19,7 +19,9 @@ const StopGallery: React.FC<StopGalleryProps> = ({
useEffect(() => {
const element = scrollRef.current;
- if (!element) return;
+ if (!element || stops.length === 0) {
+ return;
+ }
const handleScroll = () => {
const scrollLeft = element.scrollLeft;
@@ -34,9 +36,11 @@ const StopGallery: React.FC<StopGalleryProps> = ({
if (stops.length === 0 && emptyMessage) {
return (
- <div className="gallery-container">
- <h2 className="page-subtitle">{title}</h2>
- <p className="message">{emptyMessage}</p>
+ <div className="gallery-container stoplist-section">
+ <h3 className="page-subtitle">{title}</h3>
+ <div className="gallery-empty-state">
+ <p className="message">{emptyMessage}</p>
+ </div>
</div>
);
}
@@ -46,29 +50,27 @@ const StopGallery: React.FC<StopGalleryProps> = ({
}
return (
- <div className="gallery-container">
+ <div className="gallery-container stoplist-section">
<div className="gallery-header">
- <h2 className="page-subtitle">{title}</h2>
+ <h3 className="page-subtitle">{title}</h3>
+ <span className="gallery-counter">{stops.length}</span>
</div>
- <div className="gallery-scroll-container" ref={scrollRef}>
+ <div ref={scrollRef} className="gallery-scroll-container">
<div className="gallery-track">
{stops.map((stop) => (
<StopGalleryItem key={stop.stopId} stop={stop} />
))}
</div>
</div>
-
- {stops.length > 1 && (
- <div className="gallery-indicators">
- {stops.map((_, index) => (
- <div
- key={index}
- className={`gallery-indicator ${index === activeIndex ? "active" : ""}`}
- />
- ))}
- </div>
- )}
+ <div className="gallery-dots">
+ {stops.map((_, index) => (
+ <span
+ key={index}
+ className={`dot ${index === activeIndex ? "active" : ""}`}
+ ></span>
+ ))}
+ </div>
</div>
);
};
diff --git a/src/frontend/app/components/StopItem.tsx b/src/frontend/app/components/StopItem.tsx
index ae51df8..de51576 100644
--- a/src/frontend/app/components/StopItem.tsx
+++ b/src/frontend/app/components/StopItem.tsx
@@ -1,8 +1,8 @@
import React from "react";
import { Link } from "react-router";
+import { useApp } from "../AppContext";
import StopDataProvider, { type Stop } from "../data/StopDataProvider";
import LineIcon from "./LineIcon";
-import { useApp } from "../AppContext";
interface StopItemProps {
stop: Stop;
@@ -14,9 +14,16 @@ const StopItem: React.FC<StopItemProps> = ({ stop }) => {
return (
<li className="list-item">
<Link className="list-item-link" to={`/estimates/${stop.stopId}`}>
- {stop.favourite && <span className="favourite-icon">★</span>} (
- {stop.stopId}) {StopDataProvider.getDisplayName(region, stop)}
- <div className="line-icons">
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
+ <span style={{ fontWeight: 600 }}>
+ {stop.favourite && <span className="favourite-icon">★</span>}
+ {StopDataProvider.getDisplayName(region, stop)}
+ </span>
+ <span style={{ fontSize: "0.85em", color: "var(--subtitle-color)", marginLeft: "0.5rem" }}>
+ ({stop.stopId})
+ </span>
+ </div>
+ <div className="line-icons" style={{ marginTop: "0.25rem" }}>
{stop.lines?.map((line) => (
<LineIcon key={line} line={line} region={region} />
))}
diff --git a/src/frontend/app/components/ThemeColorManager.tsx b/src/frontend/app/components/ThemeColorManager.tsx
new file mode 100644
index 0000000..c138dc9
--- /dev/null
+++ b/src/frontend/app/components/ThemeColorManager.tsx
@@ -0,0 +1,20 @@
+import { useEffect } from "react";
+import { useSettings } from "../contexts/SettingsContext";
+
+export const ThemeColorManager = () => {
+ const { resolvedTheme } = useSettings();
+
+ useEffect(() => {
+ const color = resolvedTheme === "dark" ? "#121212" : "#ffffff";
+
+ let meta = document.querySelector('meta[name="theme-color"]');
+ if (!meta) {
+ meta = document.createElement('meta');
+ meta.setAttribute('name', 'theme-color');
+ document.head.appendChild(meta);
+ }
+ meta.setAttribute('content', color);
+ }, [resolvedTheme]);
+
+ return null;
+};
diff --git a/src/frontend/app/components/layout/AppShell.tsx b/src/frontend/app/components/layout/AppShell.tsx
index d0c0121..e0559ac 100644
--- a/src/frontend/app/components/layout/AppShell.tsx
+++ b/src/frontend/app/components/layout/AppShell.tsx
@@ -2,6 +2,7 @@ import React, { useState } from "react";
import { Outlet } from "react-router";
import { PageTitleProvider, usePageTitleContext } from "~/contexts/PageTitleContext";
import NavBar from "../NavBar";
+import { ThemeColorManager } from "../ThemeColorManager";
import "./AppShell.css";
import { Drawer } from "./Drawer";
import { Header } from "./Header";
@@ -12,6 +13,7 @@ const AppShellContent: React.FC = () => {
return (
<div className="app-shell">
+ <ThemeColorManager />
<Header
className="app-shell__header"
title={title}
diff --git a/src/frontend/app/components/layout/Header.css b/src/frontend/app/components/layout/Header.css
index c95226f..4ff492e 100644
--- a/src/frontend/app/components/layout/Header.css
+++ b/src/frontend/app/components/layout/Header.css
@@ -4,7 +4,6 @@
justify-content: space-between;
padding: 0.5rem 1rem;
background-color: var(--background-color);
- border-bottom: 1px solid var(--border-color);
height: 60px;
box-sizing: border-box;
width: 100%;