add load spinner

add flag icons
add console icons
This commit is contained in:
Alexandra
2025-05-27 22:35:11 -06:00
parent c3df623b2b
commit 8538dfadcc
12 changed files with 172 additions and 16 deletions

22
lib/consoleicons.js Normal file
View File

@@ -0,0 +1,22 @@
export default class ConsoleIcons {
constructor(consoleData){
this.consoleData = consoleData
}
getConsoleImage(console){
return this.consoleData[console]?.icon
}
ifConsoleExists(console){
return this.consoleData[console] ? true : false
}
createConsoleImage(console){
//fixups
console = console.replace('Sony PlayStation', 'PlayStation')
console = console.replace('Microsoft Xbox', 'Xbox')
console = console.replace(/^Xbox$/, 'Xbox Classic')
if(this.ifConsoleExists(console)){
return `<img class='console' src='/proxy-image?url=${encodeURIComponent(this.getConsoleImage(console))}'>`
}
return ''
}
}

41
lib/flag.js Normal file
View File

@@ -0,0 +1,41 @@
import path from "path";
import { fileURLToPath } from "url";
import fs from "fs";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const flagsDir = path.join(__dirname, "../views/public/images/flags");
export default class Flags {
constructor() {
this.flags = this.getAvailableFlags();
this.basePath = '/public/images/flags/'
}
getAvailableFlags() {
try {
return fs
.readdirSync(flagsDir)
.filter((file) => file.endsWith(".png"))
.map((file) => path.basename(file, ".png"));
} catch (error) {
console.error("Error reading flags directory:", error);
return [];
}
}
ifFlagExists(string){
return this.flags.includes(string)
}
getFlagPath(string){
return `${this.basePath}${string}.png`
}
createFlag(string){
if(this.ifFlagExists(string)){
return `<img class="flag" src="${this.getFlagPath(string)}"></img>`
}
return ''
}
}

View File

@@ -22,6 +22,8 @@ import i18n, { locales } from "./config/i18n.js";
import { v4 as uuidv4 } from "uuid";
import { optimizeDatabaseKws } from "./lib/dboptimize.js";
import MetadataSearch from "./lib/metadatasearch.js";
import Flag from "./lib/flag.js";
import ConsoleIcons from "./lib/consoleicons.js";
let categoryListPath = "./lib/categories.json";
let nonGameTermsPath = "./lib/nonGameTerms.json";
@@ -33,6 +35,8 @@ let crawlTime = 0;
let queryCount = 0;
let fileCount = 0;
let indexPage = "pages/index";
let flags = new Flag();
let consoleIcons = new ConsoleIcons(emulatorsData);
// Initialize databases
await initDB();
@@ -200,7 +204,8 @@ app.get("/search", async function (req, res) {
if (settings.combineWith != "AND") {
delete settings.combineWith;
}
let loadOldResults = req.query.old === "true" || !metadataSearch.authorized ? true : false
let loadOldResults =
req.query.old === "true" || !metadataSearch.authorized ? true : false;
settings.pageSize = loadOldResults ? 100 : 10;
settings.page = pageNum - 1;
settings.sort = req.query.o || "";
@@ -225,6 +230,8 @@ app.get("/search", async function (req, res) {
indexing: search.indexing,
urlPrefix: urlPrefix,
settings: settings,
flags: flags,
consoleIcons: consoleIcons
};
let page = loadOldResults ? "resultsold" : "results";
options = buildOptions(page, options);
@@ -259,7 +266,7 @@ app.get("/lucky", async function (req, res) {
app.get("/settings", function (req, res) {
let options = { defaultSettings: defaultSettings };
let page = "settings";
options.oldSettingsAvailable = metadataSearch.authorized
options.oldSettingsAvailable = metadataSearch.authorized;
options = buildOptions(page, options);
res.render(indexPage, options);
});
@@ -328,6 +335,8 @@ app.get("/info/:id", async function (req, res) {
}
let options = {
romFile: romInfo[0],
flags: flags,
consoleIcons: consoleIcons
};
let page = "info";
options = buildOptions(page, options);

View File

@@ -17,7 +17,7 @@
<div class="col-12 col-lg-10 col-xl-8">
<div class="col-12 text-center">
<h2 class="text-white"><%= metadata.title %></h2>
<p class="text-secondary"><%= file.category %></p>
<p class="text-secondary"><%= file.category %> <%- consoleIcons.createConsoleImage(file.category) %></p>
</div>
<div class="row ml-1">
<img class="coverart col-md d-block mx-auto" src="<%= coverUrl %>" href="<%= file.path %>">
@@ -62,7 +62,7 @@
<% } %>
<% if(file.region) {%>
<div>
<p><span class="info"><%= __('search.region') %></span> <%= file.region %></p>
<p><span class="info"><%= __('search.region') %></span> <%= file.region %> <%- flags.createFlag(file.region) %></p>
</div>
<% } %>
<% if(metadata.genre) {%>

View File

@@ -6,7 +6,7 @@
%>
<link rel="stylesheet" href="/public/css/result.css">
<div class="row w-100 m-0">
<form class="ml-2 form-inline w-100" action="/search">
<form id="searchform" class="ml-2 form-inline w-100" action="/search">
<div class="w-100 align-items-center">
<div class="form-group">
<a href="/">
@@ -16,7 +16,7 @@
</a>
<input type="hidden" name="s" id="searchSettings">
<input id="search" type="text" class="w-50 form-control bg-dark text-white ml-2" name="q" value="<%= query %>" autocomplete="off" placeholder="<%= __('search.placeholder') %>">
<button type="submit" class="btn btn-secondary ml-2"><%= __('search.button') %></button>
<button type="submit" class="btn btn-secondary ml-2"><div id="loading" class="hidden spinner-border text-dark" role="status"></div><%= __('search.button') %></button>
</div>
<ul class="SuggestionList col-sm-12" id="suggestionList" style="width: 50%;left: 195px;"></ul>
@@ -91,4 +91,9 @@
</div>
<% } %>
</div>
</div>
</div>
<script defer>
$( "#searchform" ).on( "submit", function( event ) {
$("#loading").removeClass('hidden')
});
</script>

View File

@@ -22,7 +22,7 @@
</a>
<input type="hidden" name="s" id="searchSettings">
<input id="search" type="text" class="w-50 form-control bg-dark text-white ml-2" name="q" value="<%= query %>" autocomplete="off" placeholder="<%= __('search.placeholder') %>">
<button type="submit" class="btn btn-secondary ml-2"><%= __('search.button') %></button>
<button type="submit" class="btn btn-secondary ml-2"><div id="loading" class="hidden spinner-border text-dark" role="status"></div><%= __('search.button') %></button>
</div>
<ul class="SuggestionList col-sm-12" id="suggestionList" style="width: 50%;left: 195px;"></ul>
@@ -175,4 +175,9 @@
// window.location = location.protocol + '//' + location.host + location.pathname + '?' + URLParams.toString()
// })
// })
</script>
<script defer>
$( "#searchform" ).on( "submit", function( event ) {
$("#loading").removeClass('hidden')
});
</script>

View File

@@ -5,17 +5,22 @@
<%= __('nav.search') %>!
</pre>
<div class="text-center text-white">
<form>
<form id="searchform">
<input type="hidden" name="s" id="searchSettings">
<input type="hidden" name="old" id="oldResults">
<input id="search" type="text" style="width: 80%;display: inline;" class="form-control bg-dark text-white mb-2"
name="q" autocomplete="off" placeholder="<%= __('search.placeholder') %>">
<ul class="SuggestionList col-sm-12" id="suggestionList" style="width: 78%;left: 11%;"></ul>
<div>
<button type="submit" formaction="/search" class="btn btn-secondary"><%= __('search.button') %></button>
<button type="submit" formaction="/search" class="btn btn-secondary"><div id="loading" class="hidden spinner-border text-dark" role="status"></div><%= __('search.button') %></button>
<button type="submit" formaction="/lucky" class="btn btn-secondary"><%= __('search.lucky') %></button>
</div>
</div>
</form>
</div>
</div>
</div>
<script defer>
$( "#searchform" ).on( "submit", function( event ) {
$("#loading").removeClass('hidden')
});
</script>

View File

@@ -8,10 +8,10 @@
<img class="coverart" src="<%= coverUrl %>" href="<%= file.path %>">
</div>
<div class="col-md">
<p class="title"><a href="<%= file.path %>"><%= metadata.title || file.filename %></a></p>
<p class="info"><span class="infoitem badge badge-secondary"><%= __('search.released') %>: <%= metadata.releasedate || file.date %></span>
<span class="infoitem badge badge-secondary"><%= __('search.region') %> <%= file.region %></span>
<span class="infoitem badge badge-secondary"><%= __('search.platform') %> <%= file.category %></span>
<p class="title"><a href="/info/<%=file.id %>"><%= metadata.title || file.filename %></a></p>
<p class="info"><span class="infoitem badge badge-secondary"><%= __('search.released') %> <%= metadata.releasedate || file.date %></span>
<span class="infoitem badge badge-secondary"><%= __('search.region') %> <%= file.region %> <%- flags.createFlag(file.region) %></span>
<span class="infoitem badge badge-secondary"><%= __('search.platform') %> <%= file.category %> <%- consoleIcons.createConsoleImage(file.category) %></span>
<% if(metadata.genre){ %>
<span class="infoitem badge badge-secondary"><%= __('search.genre') %> <%= JSON.parse(metadata.genre).join(' / ') %></span>
<% } %>

View File

@@ -43,4 +43,11 @@
object-fit: contain;
height: auto;
width: 240px;
}
.console {
height: 1.5rem;
}
.text-secondary{
font-size: 1.5rem;
}

View File

@@ -20,13 +20,14 @@
font-weight: bold;
color: #f0a400;
margin-bottom: 0!important;
font-size: 1.25em;
}
.title a {
font-weight: bold;
color: #f0a400;
}
.info {
font-size: 0.8em;
font-size: 1em;
}
.file {
font-size: 0.8em;
@@ -36,7 +37,21 @@
}
.infoitem{
margin-right: 0;
padding-left: 0.5em;
padding-right: 0.5em;
height: 1.75em;
vertical-align: middle;
align-content: center;
}
.cover{
margin-left: 1rem;
}
.flag{
height: 1.25em;
vertical-align: middle;
}
.console {
height: 1.25em;
vertical-align: middle;
}

View File

@@ -144,3 +144,18 @@ td a {
position: relative;
z-index: 9999 !important;
}
.flag {
object-fit: contain;
}
.console {
object-fit: contain;
}
.spinner-border {
height: 1rem;
width: 1rem;
margin-right: 0.25em;
vertical-align: sub;
}
.hidden {
display: none;
}

32
views/public/js/video.js Normal file
View File

@@ -0,0 +1,32 @@
// index.js
const videos = [];
const tag = document.createElement("script");
const firstScriptTag = document.getElementsByTagName("script")[0];
tag.src = "https://www.youtube.com/iframe_api";
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// YouTube wants this function, don't rename it
function onYouTubeIframeAPIReady() {
const slides = Array.from(document.querySelectorAll(".carousel-item"));
slides.forEach((slide, index) => {
// does this slide have a video?
const video = slide.querySelector(".video-player");
if (video && video.dataset) {
const player = createPlayer({
id: video.id,
videoId: video.dataset.videoId,
});
videos.push({ player, index });
}
});
}
function createPlayer(playerInfo) {
return new YT.Player(playerInfo.id, {
videoId: playerInfo.videoId,
playerVars: {
showinfo: 0,
},
});
}