mirror of
https://github.com/davegallant/rfd-fyi.git
synced 2026-03-03 17:46:35 +00:00
Compare commits
4 Commits
492f17a5f4
...
a2de5c96bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2de5c96bb | ||
| b6d6c23eeb | |||
| fb9f52cfc6 | |||
| 816438430e |
22
index.html
22
index.html
@@ -36,14 +36,32 @@
|
|||||||
<!-- Theme detection script - runs before Vue loads to prevent flash of unstyled content -->
|
<!-- Theme detection script - runs before Vue loads to prevent flash of unstyled content -->
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
// Check for saved theme preference or system preference
|
// Check for saved theme preference only
|
||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
|
if (!savedTheme) {
|
||||||
|
return; // Let Vue handle default theme
|
||||||
|
}
|
||||||
|
|
||||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
const theme = savedTheme || (prefersDark ? 'dark' : 'light');
|
let theme = savedTheme;
|
||||||
|
|
||||||
|
// Handle 'auto' theme preference
|
||||||
|
if (theme === 'auto') {
|
||||||
|
theme = prefersDark ? 'dark' : 'light';
|
||||||
|
}
|
||||||
|
|
||||||
// Apply theme to html element
|
// Apply theme to html element
|
||||||
document.documentElement.setAttribute('data-bs-theme', theme);
|
document.documentElement.setAttribute('data-bs-theme', theme);
|
||||||
document.documentElement.setAttribute('data-theme', theme);
|
document.documentElement.setAttribute('data-theme', theme);
|
||||||
|
|
||||||
|
// Apply theme classes
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark-theme');
|
||||||
|
document.documentElement.classList.remove('light-theme');
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add('light-theme');
|
||||||
|
document.documentElement.classList.remove('dark-theme');
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
69
src/App.vue
69
src/App.vue
@@ -13,11 +13,12 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ascending: this.ascending,
|
ascending: this.ascending,
|
||||||
filter: window.location.href.split("filter=")[1] || "",
|
filter: decodeURIComponent(window.location.href.split("filter=")[1] || ""),
|
||||||
sortColumn: this.sortColumn,
|
sortColumn: this.sortColumn,
|
||||||
|
sortMethod: 'score',
|
||||||
topics: [],
|
topics: [],
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
currentTheme: 'auto',
|
currentTheme: typeof localStorage !== 'undefined' ? (localStorage.getItem('theme') || 'auto') : 'auto',
|
||||||
mediaQueryListener: null,
|
mediaQueryListener: null,
|
||||||
vuetifyTheme: null,
|
vuetifyTheme: null,
|
||||||
darkModeQuery: null,
|
darkModeQuery: null,
|
||||||
@@ -28,11 +29,11 @@ export default {
|
|||||||
window.addEventListener("keydown", this.handleKeyDown);
|
window.addEventListener("keydown", this.handleKeyDown);
|
||||||
this.detectMobile();
|
this.detectMobile();
|
||||||
this.fetchDeals();
|
this.fetchDeals();
|
||||||
// Initialize theme on next tick
|
// Initialize sort method from local storage
|
||||||
this.$nextTick(() => {
|
this.initializeSortMethod();
|
||||||
|
// Initialize theme immediately to prevent flash
|
||||||
this.initializeTheme();
|
this.initializeTheme();
|
||||||
this.setupThemeListener();
|
this.setupThemeListener();
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
window.removeEventListener("keydown", this.handleKeyDown);
|
window.removeEventListener("keydown", this.handleKeyDown);
|
||||||
@@ -47,11 +48,11 @@ export default {
|
|||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
if (!savedTheme) {
|
if (!savedTheme) {
|
||||||
this.currentTheme = 'auto';
|
this.currentTheme = 'auto';
|
||||||
this.applyTheme('auto');
|
this.applyTheme('auto', true); // skipSave=true to avoid redundant write
|
||||||
} else {
|
} else {
|
||||||
this.currentTheme = savedTheme;
|
this.currentTheme = savedTheme;
|
||||||
// Apply saved theme
|
// Apply saved theme (skipSave=true since it's already saved)
|
||||||
this.applyTheme(savedTheme);
|
this.applyTheme(savedTheme, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setupThemeListener() {
|
setupThemeListener() {
|
||||||
@@ -172,7 +173,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
filteredTopics() {
|
filteredTopics() {
|
||||||
return this.topics
|
let filtered = this.topics
|
||||||
.filter((row) => {
|
.filter((row) => {
|
||||||
const titles = (
|
const titles = (
|
||||||
row.title.toString() +
|
row.title.toString() +
|
||||||
@@ -182,8 +183,16 @@ export default {
|
|||||||
).toLowerCase();
|
).toLowerCase();
|
||||||
const filterTerm = this.filter.toLowerCase();
|
const filterTerm = this.filter.toLowerCase();
|
||||||
return titles.includes(filterTerm);
|
return titles.includes(filterTerm);
|
||||||
})
|
});
|
||||||
.sort((a, b) => b.score - a.score); // Always sort by score descending
|
|
||||||
|
// Sort based on selected method
|
||||||
|
if (this.sortMethod === 'score') {
|
||||||
|
return filtered.sort((a, b) => b.score - a.score);
|
||||||
|
} else if (this.sortMethod === 'views') {
|
||||||
|
return filtered.sort((a, b) => b.total_views - a.total_views);
|
||||||
|
} else {
|
||||||
|
return filtered.sort((a, b) => new Date(b.last_post_time) - new Date(a.last_post_time));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
highlightMatches() {
|
highlightMatches() {
|
||||||
return (v) => {
|
return (v) => {
|
||||||
@@ -223,6 +232,41 @@ export default {
|
|||||||
return 'Theme: Dark (click for Auto)';
|
return 'Theme: Dark (click for Auto)';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
initializeSortMethod() {
|
||||||
|
const saved = localStorage.getItem('sortMethod');
|
||||||
|
if (saved) {
|
||||||
|
this.sortMethod = saved;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggleSort() {
|
||||||
|
// Cycle through: score -> views -> recency -> score
|
||||||
|
if (this.sortMethod === 'score') {
|
||||||
|
this.sortMethod = 'views';
|
||||||
|
} else if (this.sortMethod === 'views') {
|
||||||
|
this.sortMethod = 'recency';
|
||||||
|
} else {
|
||||||
|
this.sortMethod = 'score';
|
||||||
|
}
|
||||||
|
localStorage.setItem('sortMethod', this.sortMethod);
|
||||||
|
},
|
||||||
|
getSortIcon() {
|
||||||
|
if (this.sortMethod === 'score') {
|
||||||
|
return 'trending_up';
|
||||||
|
} else if (this.sortMethod === 'views') {
|
||||||
|
return 'visibility';
|
||||||
|
} else {
|
||||||
|
return 'schedule';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSortTitle() {
|
||||||
|
if (this.sortMethod === 'score') {
|
||||||
|
return 'Sort by Score (click for Views)';
|
||||||
|
} else if (this.sortMethod === 'views') {
|
||||||
|
return 'Sort by Views (click for Recency)';
|
||||||
|
} else {
|
||||||
|
return 'Sort by Recency (click for Score)';
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -242,6 +286,9 @@ export default {
|
|||||||
@keyup.esc="$refs.filter.blur()"
|
@keyup.esc="$refs.filter.blur()"
|
||||||
class="search-input"
|
class="search-input"
|
||||||
/>
|
/>
|
||||||
|
<button @click="toggleSort" class="sort-toggle" :title="getSortTitle">
|
||||||
|
<span class="material-symbols-outlined">{{ getSortIcon }}</span>
|
||||||
|
</button>
|
||||||
<button @click="toggleTheme" class="theme-toggle" :title="getThemeTitle">
|
<button @click="toggleTheme" class="theme-toggle" :title="getThemeTitle">
|
||||||
<span class="material-symbols-outlined">{{ getThemeIcon }}</span>
|
<span class="material-symbols-outlined">{{ getThemeIcon }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -155,6 +155,43 @@ html.dark-theme .search-input:focus {
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sort-toggle {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: var(--text-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-toggle:hover {
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
border-color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-toggle:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark-theme .sort-toggle {
|
||||||
|
border-color: #555555;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark-theme .sort-toggle:hover {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border-color: #777777;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-toggle {
|
.theme-toggle {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user