151 lines
6.6 KiB
JavaScript
151 lines
6.6 KiB
JavaScript
const { div, h2, h3, p, section, form, input, button, a, img, table, tr, td, th, span, iframe } = require("../server/node_modules/hyperaxe");
|
|
const { template, i18n, userLink} = require('./main_views');
|
|
const moment = require("../server/node_modules/moment");
|
|
|
|
const getGames = () => [
|
|
{ id: 'cocoland', title: () => i18n.gamesCocolandTitle, desc: () => i18n.gamesCocolandDesc },
|
|
{ id: 'ecoinflow', title: () => i18n.gamesTheFlowTitle, desc: () => i18n.gamesTheFlowDesc },
|
|
{ id: 'neoninfiltrator', title: () => i18n.gamesNeonInfiltratorTitle, desc: () => i18n.gamesNeonInfiltratorDesc },
|
|
{ id: 'audiopendulum', title: () => i18n.gamesAudioPendulumTitle, desc: () => i18n.gamesAudioPendulumDesc },
|
|
{ id: 'spaceinvaders', title: () => i18n.gamesSpaceInvadersTitle, desc: () => i18n.gamesSpaceInvadersDesc },
|
|
{ id: 'arkanoid', title: () => i18n.gamesArkanoidTitle, desc: () => i18n.gamesArkanoidDesc },
|
|
{ id: 'pingpong', title: () => i18n.gamesPingPongTitle, desc: () => i18n.gamesPingPongDesc },
|
|
{ id: 'asteroids', title: () => i18n.gamesAsteroidsTitle, desc: () => i18n.gamesAsteroidsDesc },
|
|
{ id: 'rockpaperscissors', title: () => i18n.gamesRockPaperScissorsTitle, desc: () => i18n.gamesRockPaperScissorsDesc },
|
|
{ id: 'tiktaktoe', title: () => i18n.gamesTikTakToeTitle, desc: () => i18n.gamesTikTakToeDesc },
|
|
{ id: 'flipflop', title: () => i18n.gamesFlipFlopTitle, desc: () => i18n.gamesFlipFlopDesc },
|
|
{ id: '8ball', title: () => i18n.games8BallTitle, desc: () => i18n.games8BallDesc },
|
|
{ id: 'artillery', title: () => i18n.gamesArtilleryTitle, desc: () => i18n.gamesArtilleryDesc },
|
|
{ id: 'labyrinth', title: () => i18n.gamesLabyrinthTitle, desc: () => i18n.gamesLabyrinthDesc },
|
|
{ id: 'cocoman', title: () => i18n.gamesCocomanTitle, desc: () => i18n.gamesCocomanDesc },
|
|
{ id: 'tetris', title: () => i18n.gamesTetrisTitle, desc: () => i18n.gamesTetrisDesc }
|
|
];
|
|
|
|
const shortId = (feedId) => feedId ? '@' + feedId.slice(1, 9) + '...' : '?';
|
|
|
|
const renderHallOfFame = (hall) => {
|
|
const games = getGames();
|
|
const gamesWithScores = games.filter(g => hall[g.id] && hall[g.id].length > 0);
|
|
if (gamesWithScores.length === 0) {
|
|
return p({ class: 'no-content' }, i18n.gamesNoScores || 'No scores yet.');
|
|
}
|
|
return div({ class: 'games-scoring-list' },
|
|
gamesWithScores.map(game =>
|
|
div({ class: 'game-scoring-section' },
|
|
div({ class: 'game-scoring-header' },
|
|
img({ src: `/game-assets/${game.id}/thumbnail.svg`, alt: game.title(), class: 'game-scoring-thumb', loading: 'lazy' }),
|
|
div({ class: 'game-scoring-info' },
|
|
h3({ class: 'game-card-title' }, game.title()),
|
|
p({ class: 'game-card-desc game-desc-yellow' }, game.desc())
|
|
)
|
|
),
|
|
table({ class: 'hall-of-fame-table' },
|
|
tr(th('#'), th(i18n.gamesHallPlayer), th(i18n.gamesHallScore), th(i18n.gamesHallDate || 'Date')),
|
|
...hall[game.id].map((entry, idx) =>
|
|
tr(
|
|
td(String(idx + 1)),
|
|
td(userLink(entry.author)),
|
|
td({ class: idx === 0 ? 'score-first' : '' }, String(entry.score)),
|
|
td(entry.ts ? moment(entry.ts).format('YYYY-MM-DD') : '\u2014')
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
};
|
|
|
|
const VALID_GAME_IDS = new Set(['cocoland','ecoinflow','neoninfiltrator','audiopendulum','spaceinvaders','arkanoid','pingpong','asteroids','rockpaperscissors','tiktaktoe','flipflop','8ball','artillery','labyrinth','cocoman','tetris']);
|
|
|
|
exports.gameShellView = (name) => {
|
|
if (!VALID_GAME_IDS.has(name)) {
|
|
return template(i18n.gamesTitle, section(p(i18n.notFound || 'Not found')));
|
|
}
|
|
const game = getGames().find(g => g.id === name);
|
|
const filterBar = div({ class: 'filter-group' },
|
|
form({ method: 'GET', action: '/games' },
|
|
input({ type: 'hidden', name: 'filter', value: 'all' }),
|
|
button({ type: 'submit', class: 'filter-btn' }, i18n.gamesFilterAll)
|
|
),
|
|
form({ method: 'GET', action: '/games' },
|
|
input({ type: 'hidden', name: 'filter', value: 'scoring' }),
|
|
button({ type: 'submit', class: 'filter-btn' }, i18n.gamesFilterScoring)
|
|
)
|
|
);
|
|
return template(
|
|
game ? game.title() : name,
|
|
section(
|
|
div({ class: 'tags-header' },
|
|
h2(i18n.gamesTitle),
|
|
p(i18n.gamesDescription || 'Discover and play some mini-games in your network.')
|
|
),
|
|
filterBar
|
|
),
|
|
section({ class: 'game-shell-section' },
|
|
iframe({
|
|
src: `/game-assets/${name}/index.html`,
|
|
class: `game-iframe game-iframe-${name}`,
|
|
scrolling: 'no',
|
|
allowfullscreen: true
|
|
})
|
|
)
|
|
);
|
|
};
|
|
|
|
exports.gamesView = (filter = 'all', hall = null) => {
|
|
const games = getGames();
|
|
|
|
const filterBar = div({ class: 'filter-group' },
|
|
form({ method: 'GET', action: '/games' },
|
|
input({ type: 'hidden', name: 'filter', value: 'all' }),
|
|
button({ type: 'submit', class: filter === 'all' ? 'filter-btn active' : 'filter-btn' },
|
|
i18n.gamesFilterAll
|
|
)
|
|
),
|
|
form({ method: 'GET', action: '/games' },
|
|
input({ type: 'hidden', name: 'filter', value: 'scoring' }),
|
|
button({ type: 'submit', class: filter === 'scoring' ? 'filter-btn active' : 'filter-btn' },
|
|
i18n.gamesFilterScoring
|
|
)
|
|
)
|
|
);
|
|
|
|
const content = filter === 'scoring' && hall
|
|
? renderHallOfFame(hall)
|
|
: div({ class: 'games-single-col' },
|
|
games.map(game => {
|
|
const topScore = hall && hall[game.id] && hall[game.id].length > 0 ? hall[game.id][0] : null;
|
|
return div({ class: 'game-row' },
|
|
div({ class: 'game-row-media' },
|
|
img({ src: `/game-assets/${game.id}/thumbnail.svg`, alt: game.title(), loading: 'lazy' })
|
|
),
|
|
div({ class: 'game-row-body' },
|
|
h2({ class: 'game-card-title' }, game.title()),
|
|
p({ class: 'game-card-desc game-desc-yellow' }, game.desc()),
|
|
topScore
|
|
? p({ class: 'game-top-score' },
|
|
userLink(topScore.author),
|
|
span({ class: 'game-new-record-label' }, ' - ' + (i18n.gamesNewRecord || 'New Record') + ': '),
|
|
String(topScore.score)
|
|
)
|
|
: null
|
|
),
|
|
div({ class: 'game-row-actions' },
|
|
a({ href: `/games/${game.id}`, class: 'filter-btn' }, i18n.gamesPlayButton)
|
|
)
|
|
);
|
|
})
|
|
);
|
|
|
|
return template(
|
|
i18n.gamesTitle,
|
|
section(
|
|
div({ class: 'tags-header' },
|
|
h2(i18n.gamesTitle),
|
|
p(filter === 'scoring' ? i18n.gamesHallOfFame : (i18n.gamesDescription || 'Discover and play some mini-games in your network.'))
|
|
),
|
|
filterBar
|
|
),
|
|
section(content)
|
|
);
|
|
};
|