diff --git a/frontend/assets/icon-192.png b/frontend/assets/icon-192.png
index a2bf7ae..9177cb5 100644
Binary files a/frontend/assets/icon-192.png and b/frontend/assets/icon-192.png differ
diff --git a/frontend/assets/icon-512.png b/frontend/assets/icon-512.png
index b0fb81f..9177cb5 100644
Binary files a/frontend/assets/icon-512.png and b/frontend/assets/icon-512.png differ
diff --git a/frontend/css/main.css b/frontend/css/main.css
index e81b6c9..4d078f4 100644
--- a/frontend/css/main.css
+++ b/frontend/css/main.css
@@ -2,8 +2,17 @@
body {
display: flex;
overflow: hidden;
+ font-family: 'Michroma', sans-serif;
}
+h1, h2, h3, h4, h5, h6, .logo {
+ font-family: 'Goldman', sans-serif;
+}
+
+/* Responsiveness Utility Classes */
+@media (max-width: 767px) { .show-on-desktop { display: none !important; } }
+@media (min-width: 768px) { .show-on-mobile { display: none !important; } }
+
.sidebar {
width: var(--sidebar-width);
height: 100vh;
@@ -305,6 +314,17 @@ body {
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
+ position: sticky;
+ top: 0;
+ z-index: 50;
+ background: rgba(17, 17, 19, 0.8);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ padding: 16px 32px;
+ margin-left: -32px;
+ margin-right: -32px;
+ margin-top: -24px;
+ border-bottom: 1px solid var(--border);
}
.page-header h1 {
@@ -321,7 +341,7 @@ body {
/* Buttons */
.btn {
padding: 8px 16px;
- border-radius: var(--radius);
+ border-radius: var(--radius-xl);
font-weight: 500;
font-size: 13px;
transition: all var(--transition);
@@ -329,6 +349,9 @@ body {
align-items: center;
gap: 6px;
}
+.btn:active {
+ transform: scale(0.98);
+}
.btn-primary {
background: var(--accent);
diff --git a/frontend/css/variables.css b/frontend/css/variables.css
index cdd4c1a..2447a60 100644
--- a/frontend/css/variables.css
+++ b/frontend/css/variables.css
@@ -1,27 +1,45 @@
:root {
- --bg-primary: #111827;
- --bg-secondary: #1f2937;
- --bg-card: #1e293b;
- --bg-card-hover: #283548;
- --bg-input: #0f172a;
- --accent: #3b82f6;
- --accent-hover: #2563eb;
- --accent-dim: #1d4ed8;
- --text-primary: #f1f5f9;
- --text-secondary: #94a3b8;
- --text-muted: #64748b;
- --success: #22c55e;
- --success-dim: #15803d;
+ /* Cores de Destaque */
+ --accent: #ff6b00;
+ --accent-hover: #e65c00;
+ --accent-dim: rgba(255, 107, 0, 0.15);
+ --accent-glow: rgba(255, 107, 0, 0.35);
+
+ /* Sistema de Feedback */
+ --success: #34d399;
--danger: #ef4444;
- --danger-dim: #991b1b;
- --warning: #f59e0b;
- --warning-dim: #92400e;
- --border: #334155;
- --border-light: #475569;
- --radius: 8px;
- --radius-lg: 12px;
- --shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
- --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
+ --warning: #fbbf24;
+
+ /* Borda arredondada / Glassmorphism */
+ --radius-sm: 8px;
+ --radius-md: 14px;
+ --radius-lg: 20px;
+ --radius-xl: 28px;
+
+ --transition: 0.22s cubic-bezier(0.4, 0, 0.2, 1);
--sidebar-width: 220px;
- --transition: 0.2s ease;
+}
+
+[data-theme="dark"], :root {
+ --bg-base: #09090b;
+ --bg-surface: #111113;
+ --bg-card: #1a1a1e;
+ --bg-card-hover: #242429;
+ --bg-input: #0d0d10;
+ --text-primary: #ffffff;
+ --text-secondary: #a1a1aa;
+ --text-muted: #6b7280;
+ --border: #27272a;
+ --border-highlight: #3f3f46;
+ --shadow: rgba(0, 0, 0, 0.5);
+
+ /* Mapping old variables to new ones for compatibility */
+ --bg-primary: var(--bg-base);
+ --bg-secondary: var(--bg-surface);
+ --radius: var(--radius-sm);
+ --success-dim: rgba(52, 211, 153, 0.2);
+ --danger-dim: rgba(239, 68, 68, 0.2);
+ --warning-dim: rgba(251, 191, 36, 0.2);
+ --border-light: var(--border-highlight);
+ --shadow-sm: rgba(0, 0, 0, 0.3);
}
diff --git a/frontend/index.html b/frontend/index.html
index 44c36d0..3fb8e0f 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -1,16 +1,21 @@
-
+
-
-
+
+
- ScreenTinker
+ GoldenSignage
+
+
+
+
+
@@ -30,7 +35,7 @@
- ScreenTinker
+ GoldenSignage
diff --git a/frontend/js/app.js b/frontend/js/app.js
index f155577..3c02640 100644
--- a/frontend/js/app.js
+++ b/frontend/js/app.js
@@ -543,7 +543,7 @@ window.addEventListener('hashchange', () => { if (isAuthenticated()) refreshCurr
// Register PWA service worker
if ('serviceWorker' in navigator) {
- navigator.serviceWorker.register('/sw-admin.js').catch(() => {});
+ navigator.serviceWorker.register('/sw.js').catch(() => {});
}
// Mobile sidebar: open/close via hamburger, backdrop, nav tap, Escape
@@ -640,3 +640,45 @@ document.addEventListener('click', (e) => {
const modal = document.getElementById(id);
if (modal) modal.style.display = 'none';
});
+
+// Custom Pull-to-Refresh logic for mobile PWA standalone
+let pwaTouchStartY = 0;
+let pwaIsPulling = false;
+
+document.addEventListener('touchstart', (e) => {
+ // Only start pull-to-refresh if we are at the very top of the page
+ const scrollElement = document.querySelector('.content') || document.documentElement;
+ if (scrollElement.scrollTop === 0) {
+ pwaTouchStartY = e.changedTouches[0].screenY;
+ pwaIsPulling = true;
+ } else {
+ pwaIsPulling = false;
+ }
+}, { passive: true });
+
+document.addEventListener('touchend', (e) => {
+ if (!pwaIsPulling) return;
+ const pwaTouchEndY = e.changedTouches[0].screenY;
+
+ if (pwaTouchEndY - pwaTouchStartY > 150) {
+ if ('caches' in window) {
+ caches.keys().then((names) => {
+ Promise.all(names.map(name => caches.delete(name)))
+ .then(() => {
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.getRegistrations().then((registrations) => {
+ for (let registration of registrations) {
+ registration.unregister();
+ }
+ window.location.reload(true);
+ });
+ } else {
+ window.location.reload(true);
+ }
+ });
+ });
+ } else {
+ window.location.reload(true);
+ }
+ }
+}, { passive: true });
diff --git a/frontend/manifest.json b/frontend/manifest.json
index ad2b6ec..811093d 100644
--- a/frontend/manifest.json
+++ b/frontend/manifest.json
@@ -1,11 +1,11 @@
{
- "name": "ScreenTinker",
- "short_name": "ScreenTinker",
+ "name": "GoldenSignage",
+ "short_name": "GoldenSignage",
"description": "Digital Signage Management",
"start_url": "/",
"display": "standalone",
- "background_color": "#111827",
- "theme_color": "#3B82F6",
+ "background_color": "#09090b",
+ "theme_color": "#ff6b00",
"orientation": "any",
"icons": [
{
diff --git a/frontend/sw.js b/frontend/sw.js
new file mode 100644
index 0000000..f59d884
--- /dev/null
+++ b/frontend/sw.js
@@ -0,0 +1,54 @@
+const CACHE_NAME = 'goldensignage-v1';
+const ASSETS_TO_CACHE = [
+ '/',
+ '/index.html',
+ '/manifest.json',
+ '/css/reset.css',
+ '/css/variables.css',
+ '/css/main.css',
+ '/js/app.js',
+ '/assets/icon-192.png',
+ '/assets/icon-512.png',
+ 'https://fonts.googleapis.com/css2?family=Goldman:wght@400;700&family=Michroma&display=swap'
+];
+
+self.addEventListener('install', (event) => {
+ event.waitUntil(
+ caches.open(CACHE_NAME).then((cache) => {
+ return cache.addAll(ASSETS_TO_CACHE);
+ })
+ );
+ self.skipWaiting();
+});
+
+self.addEventListener('activate', (event) => {
+ event.waitUntil(
+ caches.keys().then((cacheNames) => {
+ return Promise.all(
+ cacheNames.map((cacheName) => {
+ if (cacheName !== CACHE_NAME) {
+ return caches.delete(cacheName);
+ }
+ })
+ );
+ })
+ );
+ self.clients.claim();
+});
+
+self.addEventListener('fetch', (event) => {
+ // Cache-First Strategy
+ event.respondWith(
+ caches.match(event.request).then((cachedResponse) => {
+ if (cachedResponse) {
+ return cachedResponse;
+ }
+ return fetch(event.request).then((networkResponse) => {
+ // Cache dynamic assets if needed, but for now just return network response
+ return networkResponse;
+ }).catch(() => {
+ // Handle offline fallback if needed
+ });
+ })
+ );
+});