1
Fork 0

typescript(og-website): basic projects page

Signed-off-by: prescientmoon <git@moonythm.dev>
This commit is contained in:
Matei Adriel 2019-10-20 14:20:54 +03:00 committed by prescientmoon
parent 4b9d6c80ad
commit 79fea699a7
Signed by: prescientmoon
SSH key fingerprint: SHA256:UUF9JT2s8Xfyv76b8ZuVL7XrmimH4o49p4b+iexbVH4
15 changed files with 165 additions and 36 deletions

View file

@ -3,8 +3,9 @@ import { withCss } from '../helpers/withCss'
import { Nav } from './Nav' import { Nav } from './Nav'
import { buttons } from '../constants/navButtons' import { buttons } from '../constants/navButtons'
import { LayoutOptions } from '../types/LayoutOptions' import { LayoutOptions } from '../types/LayoutOptions'
import { ServiceWorker } from './ServiceWorker'
export const Layout = ({ title, body }: LayoutOptions) => html` export const Layout = ({ title, body, url }: LayoutOptions) => html`
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -14,8 +15,10 @@ export const Layout = ({ title, body }: LayoutOptions) => html`
${withCss('layout', 'config')} ${withCss('layout', 'config')}
</head> </head>
<body class="background"> <body class="background">
${Nav(buttons)} ${Nav(buttons, url)}
<div id="page-content">${body}</div> <div id="page-content">${body}</div>
${ServiceWorker('/static/js/service-worker.js')}
</body> </body>
</html> </html>
` `

View file

@ -2,17 +2,23 @@ import { TemplateResult, html } from '@popeindustries/lit-html-server'
import { withCss } from '../helpers/withCss' import { withCss } from '../helpers/withCss'
import { UrlConfig } from '../types/UrlConfig' import { UrlConfig } from '../types/UrlConfig'
export const NavButtons = (config: UrlConfig) => html` export const NavButtons = (config: UrlConfig, url: string) => {
<a class="nav-button" href=${config.url}>${config.name}</a> const className = ['nav-button', config.url === url && 'glow']
` .filter(Boolean)
.join(' ')
export const Nav = (buttons: UrlConfig[]) => return html`
<a class=${className} href=${config.url}>${config.name}</a>
`
}
export const Nav = (buttons: UrlConfig[], url: string) =>
html` html`
${withCss('nav')} ${withCss('nav')}
<div id="nav"> <div id="nav">
<div id="nav-buttons"> <div id="nav-buttons">
${buttons.map(NavButtons)} ${buttons.map(button => NavButtons(button, url))}
</div> </div>
</div> </div>
` `

View file

@ -8,7 +8,8 @@ export const Project = (project: ProjectConfig) => {
return html` return html`
<div class="project"> <div class="project">
<div class="project-thumbail background" style=${style}></div> <div class="project-thumbail background" style=${style}></div>
<div class="project-icons"> <div class="project-name">${project.name}</div>
<div class="project-links">
<a class="project-source" href=${project.source}>Source</a> <a class="project-source" href=${project.source}>Source</a>
<a class="project-demo" href=${project.demo}>Demo</a> <a class="project-demo" href=${project.demo}>Demo</a>
</div> </div>

View file

@ -0,0 +1,11 @@
import { html } from '@popeindustries/lit-html-server'
export const ServiceWorker = (url: string) => html`
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('${url}')
})
}
</script>
`

View file

@ -1,16 +1,22 @@
import { UrlConfig } from '../types/UrlConfig' import { UrlConfig } from '../types/UrlConfig'
import { Home } from '../components/Home'
import { Projects } from '../components/Projects'
import { html } from '@popeindustries/lit-html-server'
export const buttons: UrlConfig[] = [ export const buttons: UrlConfig[] = [
{ {
url: '/', url: '/',
name: 'Home' name: 'Home',
component: Home
}, },
{ {
url: '/projects', url: '/projects',
name: 'Projects' name: 'Projects',
component: Projects
}, },
{ {
url: '/blog', url: '/blog',
name: 'Blog' name: 'Blog',
component: () => html``
} }
] ]

View file

@ -5,10 +5,11 @@ import { Response } from 'express'
export const createComponentRenderer = ( export const createComponentRenderer = (
layout: (options: LayoutOptions) => TemplateResult, layout: (options: LayoutOptions) => TemplateResult,
name: string name: string
) => (res: Response, { body, title }: LayoutOptions) => { ) => (res: Response, { body, title, url }: LayoutOptions) => {
renderToStream( renderToStream(
layout({ layout({
body, body,
url,
title: `${name} | ${title}` title: `${name} | ${title}`
}) })
).pipe(res) ).pipe(res)

View file

@ -2,8 +2,7 @@ import express from 'express'
import { Layout } from './components/Layout' import { Layout } from './components/Layout'
import { resolve } from 'path' import { resolve } from 'path'
import { createPageMiddlewareFactory } from './middleware/servePage' import { createPageMiddlewareFactory } from './middleware/servePage'
import { Home } from './components/Home' import { buttons } from './constants/navButtons'
import { Projects } from './components/Projects'
const port = process.env.PORT || 8080 const port = process.env.PORT || 8080
const app = express() const app = express()
@ -12,21 +11,16 @@ const renderComponent = createPageMiddlewareFactory(Layout, 'Matei Adriel')
app.use('/static', express.static(resolve(__dirname, 'static'))) app.use('/static', express.static(resolve(__dirname, 'static')))
app.get( for (const button of buttons) {
'/', app.get(
renderComponent({ button.url,
body: Home(), renderComponent({
title: 'Home' body: button.component(),
}) title: button.name,
) url: button.url
})
app.get( )
'/projects', }
renderComponent({
body: Projects(),
title: 'Projects'
})
)
app.listen(port, () => { app.listen(port, () => {
console.log(`Listening on port ${port}`) console.log(`Listening on port ${port}`)

View file

@ -6,4 +6,8 @@
--on-bg: white; --on-bg: white;
--title-font: 'Permanent Marker', cursive; --title-font: 'Permanent Marker', cursive;
--home-bg: url(https://cdn.discordapp.com/attachments/485859146558865408/635409620537442325/Wallpaper_space_galaxy_planet_4k_Space_8652415352.jpg); --home-bg: url(https://cdn.discordapp.com/attachments/485859146558865408/635409620537442325/Wallpaper_space_galaxy_planet_4k_Space_8652415352.jpg);
--glow-color-1: white;
--glow-color-2: cyan;
--glow-color-3: blue;
--glow-duration: 2s;
} }

View file

@ -1,7 +1,3 @@
div#nav {
position: absolute;
}
div#home-title { div#home-title {
max-width: 80%; max-width: 80%;
font-size: 3em; font-size: 3em;

View file

@ -1,6 +1,7 @@
div#nav { div#nav {
width: 100%; width: 100%;
padding: var(--spacing, 1rem); padding: var(--spacing, 1rem);
position: absolute;
} }
div#nav-buttons { div#nav-buttons {
@ -11,3 +12,8 @@ a.nav-button {
margin: var(--spacing, 1rem); margin: var(--spacing, 1rem);
font-family: var(--title-font); font-family: var(--title-font);
} }
a.nav-button:hover {
animation: glow var(--glow-duration, 1s) ease-in-out infinite alternate;
--glow-color-3: red;
}

View file

@ -1,11 +1,38 @@
div.project-thumbail { div.project-thumbail {
width: 100px; width: 200px;
height: 100px; height: 200px;
display: block; display: block;
margin: var(--spacing, 1rem);
} }
div.project { div.project {
background-color: var(--bg-raised, black); background-color: var(--bg-raised, black);
margin: var(--spacing, 1rem); margin: var(--spacing, 1rem);
border-radius: var(--spacing, 1rem);
}
div.project > div {
margin: var(--spacing, 1rem);
text-align: center;
box-sizing: border-box;
}
div.project-name {
border-bottom: 1px solid #777777;
padding-bottom: var(--spacing, 1rem);
}
div.project-links {
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
div#projects {
flex-direction: row;
flex-wrap: wrap;
font-family: var(--title-font);
}
div.project-links *:hover {
animation: glow var(--glow-duration, 1s) ease-in-out infinite alternate;
} }

View file

@ -15,3 +15,28 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.glow {
animation: glow var(--glow-duration, 1s) ease-in-out infinite alternate;
}
@keyframes glow {
from {
text-shadow: 0 0 10px var(--glow-color-1, white),
0 0 20px var(--glow-color-1, white),
0 0 30px var(--glow-color-2, white),
0 0 40px var(--glow-color-2, white),
0 0 50px var(--glow-color-2, white),
0 0 60px var(--glow-color-2, white),
0 0 70px var(--glow-color-2, white);
}
to {
text-shadow: 0 0 20px var(--glow-color-1, white),
0 0 30px var(--glow-color-3, white),
0 0 40px var(--glow-color-3, white),
0 0 50px var(--glow-color-3, white),
0 0 60px var(--glow-color-3, white),
0 0 70px var(--glow-color-3, white),
0 0 80px var(--glow-color-3, white);
}
}

View file

@ -0,0 +1,45 @@
importScripts(
'https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js'
)
if (workbox) {
// Cache the Google Fonts stylesheets with a stale-while-revalidate strategy.
workbox.routing.registerRoute(
/^https:\/\/fonts\.googleapis\.com/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'google-fonts-stylesheets'
})
)
// Cache the underlying font files with a cache-first strategy for 1 year.
workbox.routing.registerRoute(
/^https:\/\/fonts\.gstatic\.com/,
new workbox.strategies.CacheFirst({
cacheName: 'google-fonts-webfonts',
plugins: [
new workbox.cacheableResponse.Plugin({
statuses: [0, 200]
}),
new workbox.expiration.Plugin({
maxAgeSeconds: 60 * 60 * 24 * 365,
maxEntries: 30
})
]
})
)
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|webp|svg)$/,
new workbox.strategies.CacheFirst({
cacheName: 'images',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60 // 30 Days
})
]
})
)
} else {
console.log(`Boo! Workbox didn't load 😬`)
}

View file

@ -2,5 +2,6 @@ import { TemplateResult } from '@popeindustries/lit-html-server'
export interface LayoutOptions { export interface LayoutOptions {
title: string title: string
url: string
body: TemplateResult | string body: TemplateResult | string
} }

View file

@ -1,4 +1,7 @@
import { TemplateResult } from '@popeindustries/lit-html-server'
export interface UrlConfig { export interface UrlConfig {
url: string url: string
name: string name: string
component: () => TemplateResult
} }