diff --git a/app.ts b/app.ts index e8279913..0c2040f2 100644 --- a/app.ts +++ b/app.ts @@ -9,13 +9,14 @@ import dotenv from 'dotenv'; dotenv.config(); // import routes -import spa from './routes/spa'; import error from './routes/error'; +import home from './routes/home'; +import ipfs from './routes/ipfs'; import migrate from './routes/migrate'; import nfts from './routes/nfts'; import ppts from './routes/ppts'; -import ipfs from './routes/ipfs'; import robots from './routes/robots'; +import spa from './routes/spa'; // register view engine for pigs import { Pig } from './source/engines'; @@ -40,8 +41,9 @@ app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // register views -app.use('/', spa); app.use('/migrate', migrate); +app.use('/', home); +app.use('/', spa); app.use('/nfts', nfts); app.use('/ppts', ppts); app.use('/robots.txt', robots); diff --git a/public/images/jpg/desktop-mine.jpg b/public/images/jpg/desktop-mine.jpg new file mode 100644 index 00000000..f478b3b2 Binary files /dev/null and b/public/images/jpg/desktop-mine.jpg differ diff --git a/public/images/jpg/desktop-nfts.jpg b/public/images/jpg/desktop-nfts.jpg new file mode 100644 index 00000000..031438ec Binary files /dev/null and b/public/images/jpg/desktop-nfts.jpg differ diff --git a/public/images/jpg/desktop-ppts.jpg b/public/images/jpg/desktop-ppts.jpg new file mode 100644 index 00000000..39269285 Binary files /dev/null and b/public/images/jpg/desktop-ppts.jpg differ diff --git a/public/images/jpg/desktop-swap.jpg b/public/images/jpg/desktop-swap.jpg new file mode 100644 index 00000000..bf1f5552 Binary files /dev/null and b/public/images/jpg/desktop-swap.jpg differ diff --git a/routes/functions/env-of-mine.test.ts b/routes/functions/env-of-mine.test.ts index 3c2677c1..2cf668eb 100644 --- a/routes/functions/env-of-mine.test.ts +++ b/routes/functions/env-of-mine.test.ts @@ -10,6 +10,7 @@ describe('env_of_mine', () => { expect(env_of_mine(req as any)).toEqual({ ...{ HEADER_ABOUT: '', + HEADER_HOME: '', HEADER_MINE: '', HEADER_NFTS: '', HEADER_PPTS: '', diff --git a/routes/functions/env-of.test.ts b/routes/functions/env-of.test.ts index 67803bf1..618e77e5 100644 --- a/routes/functions/env-of.test.ts +++ b/routes/functions/env-of.test.ts @@ -10,6 +10,7 @@ describe('env_of', () => { expect(env_of(req as any)).toEqual({ ...{ HEADER_ABOUT: '', + HEADER_HOME: '', HEADER_MINE: '', HEADER_NFTS: '', HEADER_PPTS: '', diff --git a/routes/functions/env-of.ts b/routes/functions/env-of.ts index 2fefefb0..6088ee57 100644 --- a/routes/functions/env-of.ts +++ b/routes/functions/env-of.ts @@ -83,6 +83,8 @@ const header_page = ( ) => { const page = Pager.parse(req.path); return { + HEADER_HOME: + page === Page.Home ? 'active' : '', HEADER_MINE: page === Page.Mine ? 'active' : '', HEADER_NFTS: diff --git a/routes/home.test.ts b/routes/home.test.ts new file mode 100644 index 00000000..3a2f239b --- /dev/null +++ b/routes/home.test.ts @@ -0,0 +1,39 @@ +import request from 'supertest'; +import app from '../app'; + +describe('GET /', () => { + let get: request.Test; + beforeEach(() => { + get = request(app).get('/'); + }); + it('should return w/an HTTP code = 302 Found', async () => { + await get.expect(302); + }); +}); +describe('GET /*/manifest.json', () => { + let get: request.Test; + beforeEach(() => { + get = request(app).get('/home/manifest.json'); + }); + it('should return w/an HTTP code = 302 Found', async () => { + await get.expect(302); + }); +}); +describe('GET /home', () => { + let get: request.Test; + beforeEach(() => { + get = request(app).get('/home'); + }); + it('should return w/an HTTP code = 200 OK', async () => { + await get.expect(200); + }); + it('should return w/a Content-Type ~ html', async () => { + await get.expect('Content-Type', /html/) + }); + it('should return w/a Content-Length > 0', async () => { + await get.expect((res) => { + const length = BigInt(res.headers['content-length']); + expect(length).toBeGreaterThan(0); + }); + }); +}); diff --git a/routes/home.ts b/routes/home.ts new file mode 100644 index 00000000..93a31ccc --- /dev/null +++ b/routes/home.ts @@ -0,0 +1,20 @@ +import { Router } from 'express'; +import { env_of } from './functions'; +const router = Router(); + +/** REDIRECT to manifest.json. */ +router.get(/\/[^/]+\/manifest\.json$/, (req, res) => { + res.redirect('/manifest.json'); +}); +/** REDIRECT to home page. */ +router.get('/', (req, res) => { + res.redirect('/home'); +}); +/** GET home page. */ +router.get('/home', (req, res) => { + res.render('home/home.pig', { + DESCRIPTION: 'Mine & Mint Proof-of-Work XPower Tokens', + TITLE: 'XPower', ...env_of(req), + }); +}); +export default router; diff --git a/routes/spa.test.ts b/routes/spa.test.ts index cb8292b2..72686998 100644 --- a/routes/spa.test.ts +++ b/routes/spa.test.ts @@ -1,24 +1,6 @@ import request from 'supertest'; import app from '../app'; -describe('GET /', () => { - let get: request.Test; - beforeEach(() => { - get = request(app).get('/'); - }); - it('should return w/an HTTP code = 302 Found', async () => { - await get.expect(302); - }); -}); -describe('GET /*/manifest.json', () => { - let get: request.Test; - beforeEach(() => { - get = request(app).get('/mine/manifest.json'); - }); - it('should return w/an HTTP code = 302 Found', async () => { - await get.expect(302); - }); -}); describe('GET /mine', () => { let get: request.Test; beforeEach(() => { diff --git a/routes/spa.ts b/routes/spa.ts index 14125513..22ed05c8 100644 --- a/routes/spa.ts +++ b/routes/spa.ts @@ -9,19 +9,11 @@ import { join, sep } from 'path'; function routes( spa_env: Record ) { - /** REDIRECT to manifest.json. */ - router.get(/\/[^/]+\/manifest\.json$/, (req, res) => { - res.redirect('/manifest.json'); - }); - /** REDIRECT to home page. */ - router.get('/', (req, res) => { - res.redirect('/mine'); - }); /** GET mine page. */ router.get('/mine', (req, res) => { res.render('mine/mine.pig', { DESCRIPTION: 'Mine & Mint Proof-of-Work XPower Tokens', - TITLE: 'XPower', ...env_of_mine(req), ...spa_env, + TITLE: 'XPower: Mine', ...env_of_mine(req), ...spa_env, }); }); /** GET nfts page. */ @@ -35,7 +27,7 @@ function routes( router.get('/stake', (req, res) => { res.render('ppts/ppts.pig', { DESCRIPTION: 'Stake minted XPower NFTs', - TITLE: 'XPower: Staking', ...env_of(req), ...spa_env + TITLE: 'XPower: Stake', ...env_of(req), ...spa_env }); }); /** GET swap page. */ diff --git a/source/redux/types/page.ts b/source/redux/types/page.ts index 105bb923..3621532a 100644 --- a/source/redux/types/page.ts +++ b/source/redux/types/page.ts @@ -1,5 +1,6 @@ export enum Page { None = 'none', + Home = 'home', Mine = 'mine', Nfts = 'nfts', Ppts = 'stake', @@ -22,6 +23,8 @@ export class Pager { const suffix = path.length ? path[path.length - 1] : ''; switch (suffix.toLowerCase()) { + case 'home': + return Page.Home; case 'mine': return Page.Mine; case 'nfts': diff --git a/source/services/location-service.ts b/source/services/location-service.ts index c1c494ba..70deca81 100644 --- a/source/services/location-service.ts +++ b/source/services/location-service.ts @@ -20,9 +20,10 @@ export const LocationService = ( onPageSwitch(store, function syncLocationTitle(page) { const titles: Record = { [Page.None]: 'XPower', - [Page.Mine]: 'XPower', + [Page.Home]: 'XPower', + [Page.Mine]: 'XPower: Mine', [Page.Nfts]: 'XPower: NFTs', - [Page.Ppts]: 'XPower: Staking', + [Page.Ppts]: 'XPower: Stake', [Page.Swap]: 'XPower: Swap', [Page.About]: 'XPower: About', }; @@ -35,6 +36,7 @@ export const LocationService = ( ); const descriptions: Record = { [Page.None]: 'Mine & Mint Proof-of-Work XPower Tokens', + [Page.Home]: 'Mine & Mint Proof-of-Work XPower Tokens', [Page.Mine]: 'Mine & Mint Proof-of-Work XPower Tokens', [Page.Nfts]: 'Mint stakeable XPower NFTs', [Page.Ppts]: 'Stake minted XPower NFTs', diff --git a/views/header/header.pug b/views/header/header.pug index ab0e1335..2fed9b1a 100644 --- a/views/header/header.pug +++ b/views/header/header.pug @@ -1,5 +1,9 @@ header nav#menu.btn-group.nav.nav-pills.nav-justified.mb-3 + a.btn.btn-outline-warning.flex-sm-fill.text-sm-center.nav-link.home( + class="{{HEADER_HOME}}" href="/home?token={{TOKEN}}" + ) + i.bi-house-fill a.btn.btn-outline-warning.flex-sm-fill.text-sm-center.nav-link.mine( class="{{HEADER_MINE}}" href="/mine?token={{TOKEN}}" ) diff --git a/views/header/header.scss b/views/header/header.scss index c660a9d5..a2a221e6 100644 --- a/views/header/header.scss +++ b/views/header/header.scss @@ -5,4 +5,12 @@ header { color: var(--xp-gray-dark); } } -} + @media (min-width: 575px) { + nav#menu { + a.nav-link.home { + padding: 8px 0; + width: 0.5em; + } + } + } +} \ No newline at end of file diff --git a/views/header/header.tsx b/views/header/header.tsx index ade15026..da99ed06 100644 --- a/views/header/header.tsx +++ b/views/header/header.tsx @@ -22,6 +22,7 @@ export function UiHeader(