diff --git a/src/app/configs/app.config.ts b/src/app/configs/app.config.ts index 0c96d03..9c8ef17 100644 --- a/src/app/configs/app.config.ts +++ b/src/app/configs/app.config.ts @@ -1,9 +1,133 @@ import { env } from '@extollo/lib' +export interface ColorPalette { + displayName: string + background: string + backgroundOffset: string + backgroundOffset2: string + hero: string + font: string + fontMuted: string + box: string + link: string + noiseSize: string + line1: string + line2: string + line3: string +} + export default { name: env('APP_NAME', 'Garrett Mills'), analytics: { optOutCookie: env('ANALYTICS_OPT_OUT_COOKIE', 'analytics.opt-out'), - } + }, + + colors: { + lostInTheStars: { + displayName: "Lost in the Stars", + background: '#4a113c', + backgroundOffset: 'rgba(178, 127, 170, 0.1)', + backgroundOffset2: 'rgba(178, 127, 170, 0.2)', + hero: '#6ebbd5', + font: '#ffe3ff', + fontMuted: '#daa7d2', + box: '#b27faa', + link: 'var(--c-hero)', + noiseSize: '100px', + line1: 'rgba(178, 127, 170, 0.2)', + line2: 'rgba(110, 187, 213, 0.9)', + line3: 'rgba(218, 167, 210, 0.9)', + }, + tanOrangeAndRed: { + displayName: "Tan, Orange, & Red", + background: '#f8e4bf', + backgroundOffset: 'rgb(243, 210, 147, 0.4)', + backgroundOffset2: 'rgb(111, 71, 46, 0.15)', + hero: '#d96a59', + font: '#6f472e', + fontMuted: '#ae7813', + box: '#e0b95d', + link: 'var(--c-hero)', + noiseSize: '100px', + line1: '#edb34f', + line2: '#f88937', + line3: '#e86c36', + }, + blueAndTan: { + displayName: "Blue & Tan", + background: '#052653', + backgroundOffset: 'rgba(27, 111, 145, 0.3)', + backgroundOffset2: 'rgba(127, 167, 158, 0.15)', + hero: '#f6a56d', + font: '#f6dbb0', + fontMuted: '#dec99a', + box: '#87afa6', + link: 'var(--c-hero)', + noiseSize: '100px', + line1: '#fbad6f', + line2: '#f47139', + line3: '#de381e', + }, + teals: { + displayName: "Teals", + background: '#c6c2b9', + backgroundOffset: 'rgba(150, 171, 162, 0.3)', + backgroundOffset2: 'rgba(150, 171, 162, 0.7)', + hero: '#d05a40', + font: '#3f4962', + fontMuted: '#5d6780', + box: '#96aba2', + link: 'var(--c-hero)', + noiseSize: '100px', + line1: '#dcbb8e', + line2: '#95aaa3', + line3: '#3f4962', + }, + redAndGold: { + displayName: "Red & Gold", + background: '#510c00', + backgroundOffset: 'rgba(111, 42, 30, 0.4)', + backgroundOffset2: 'rgba(111, 42, 30, 1)', + hero: '#ee6156', + font: '#f2d7b4', + fontMuted: '#cb9866', + box: '#e9b1a0', + link: 'var(--c-hero)', + noiseSize: '100px', + line1: '#e9c8a0', + line2: '#f6bb4a', + line3: '#ef4c3f', + }, + mashGreen: { + displayName: "M*A*S*H Green", + background: '#202318', + backgroundOffset: 'rgba(46, 41, 22, 0.5)', + backgroundOffset2: 'rgb(105, 75, 1, 0.3)', + hero: '#7a7946', + font: '#e5ddae', + fontMuted: '#cb9866', + box: '#cbc87c', + link: 'var(--c-hero)', + noiseSize: '100px', + line1: '#b5a148', + line2: '#ecb653', + line3: '#71490b', + }, + purpleAndWhite: { + displayName: "Purple & White", + background: '#6669aa', + backgroundOffset: 'rgba(152, 155, 220, 0.4)', + backgroundOffset2: 'rgba(81, 84, 143, 0.6)', + hero: '#efe2df', + font: '#fff4ed', + fontMuted: '#b5b7ec', + box: '#989bdc', + link: 'var(--c-hero)', + noiseSize: '100px', + line1: '#979adb', + line2: '#b3b5f1', + line3: '#efe2df', + }, + } as Record, } diff --git a/src/app/http/controllers/Feed.controller.ts b/src/app/http/controllers/Feed.controller.ts index 95f0459..2e0bacb 100644 --- a/src/app/http/controllers/Feed.controller.ts +++ b/src/app/http/controllers/Feed.controller.ts @@ -1,6 +1,7 @@ import {Controller, view, Injectable, Collection, Inject, Routing, plaintext} from '@extollo/lib' import {FeedPost} from '../../models/FeedPost.model' import * as RSSFeed from 'feed' +import {Home} from './Home.controller' /** * Feed Controller @@ -13,8 +14,10 @@ export class Feed extends Controller { protected readonly routing!: Routing public async feed(feedPosts: Collection) { + const home = this.make(Home) return view('feed', { feedPosts: feedPosts.toArray(), + ...home.getThemeCSS(), }) } diff --git a/src/app/http/controllers/Home.controller.ts b/src/app/http/controllers/Home.controller.ts index 3cd616f..035dfdd 100644 --- a/src/app/http/controllers/Home.controller.ts +++ b/src/app/http/controllers/Home.controller.ts @@ -10,13 +10,14 @@ import { file, Application, make, - Valid, Logging, api, + Valid, Logging, api, Session, } from '@extollo/lib' import {WorkItem} from '../../models/WorkItem.model' import {FeedPost} from '../../models/FeedPost.model' import {ContactForm} from '../../types/ContactForm.type' import {ContactSubmission} from '../../models/ContactSubmission.model' import {Gotify} from 'gotify' +import {ColorPalette} from '../../configs/app.config' @Injectable() export class Home extends Controller { @@ -35,6 +36,9 @@ export class Home extends Controller { @Inject() protected readonly logging!: Logging + @Inject() + protected readonly session!: Session + public async welcome(feedPosts: Collection) { const workItems = await this.getWorkItems() @@ -44,6 +48,7 @@ export class Home extends Controller { .unique() return view('welcome', { + ...this.getThemeCSS(), feedPosts: feedPosts.toArray(), workItemGroups: workItems.groupBy(item => item.startDate.getFullYear()), workItemYears: workItemYears.toArray(), @@ -56,6 +61,7 @@ export class Home extends Controller { return view('technical', { isOptOut, + ...this.getThemeCSS(), }) } @@ -65,6 +71,7 @@ export class Home extends Controller { message: 'This will set a cookie to disable analytics recording in your browser on all *.garrettmills.dev sites. Continue?', buttonAction: this.routing.getNamedPath('opt-out').toRemote, buttonMethod: 'post', + ...this.getThemeCSS(), }) } @@ -84,6 +91,7 @@ export class Home extends Controller { title: 'Analytics Opt-Out', message: 'You have been opted-out of analytics recording.', buttonAction: this.routing.getNamedPath('home').toRemote, + ...this.getThemeCSS(), }) } @@ -117,6 +125,7 @@ export class Home extends Controller { title: 'Message Sent', message: 'Your message has been sent. Thanks! I\'ll be in touch soon.', buttonAction: this.routing.getNamedPath('home').toRemote, + ...this.getThemeCSS(), }) } @@ -145,4 +154,34 @@ export class Home extends Controller { }).then(x => this.logging.debug(x)) .catch(e => this.logging.error(e)) } + + public getThemeCSS(): any { + const themes = this.config.get('app.colors') as Record + const themeKeys = Object.keys(themes) + const themeName = this.session.get('theme.name') + // const themeName = this.request.safe('theme').or(themeKeys[Math.floor(Math.random()*themeKeys.length)]).in(themeKeys) + const theme = themes[themeName] + const themeCSS = ` + :root { + --c-background: ${theme.background}; + --c-background-offset: ${theme.backgroundOffset}; + --c-background-offset-2: ${theme.backgroundOffset2}; + --c-hero: ${theme.hero}; + --c-font: ${theme.font}; + --c-font-muted: ${theme.fontMuted}; + --c-box: ${theme.box}; + --c-link: ${theme.link}; + --c-noise-size: ${theme.noiseSize}; + --c-line-1: ${theme.line1}; + --c-line-2: ${theme.line2}; + --c-line-3: ${theme.line3}; + } + ` + return { + themeName, + themeCSS, + themeDisplayName: theme.displayName, + themeKeys, + } + } } diff --git a/src/app/http/controllers/Snippets.controller.ts b/src/app/http/controllers/Snippets.controller.ts index 2ff360f..3603985 100644 --- a/src/app/http/controllers/Snippets.controller.ts +++ b/src/app/http/controllers/Snippets.controller.ts @@ -1,5 +1,6 @@ import {Controller, http, HTTPStatus, Inject, Injectable, Logging, view} from '@extollo/lib' import {Snippet} from '../../models/Snippet.model' +import {Home} from './Home.controller' /** * Snippets Controller @@ -19,11 +20,14 @@ export class Snippets extends Controller { await snippet.delete() } + const home = this.make(Home) + return view('snippet', { snippet, needsAccessKey, needsConfirm, accessKey: this.request.input('accessKey'), + ...home.getThemeCSS(), }) } } diff --git a/src/app/http/middlewares/SiteTheme.middleware.ts b/src/app/http/middlewares/SiteTheme.middleware.ts new file mode 100644 index 0000000..f498694 --- /dev/null +++ b/src/app/http/middlewares/SiteTheme.middleware.ts @@ -0,0 +1,37 @@ +import {Middleware, Injectable, Inject, Config, Session} from '@extollo/lib' +import {ColorPalette} from '../../configs/app.config' + +/** + * SiteTheme Middleware + * -------------------------------------------- + * Determines the correct color theme for the request. + */ +@Injectable() +export class SiteTheme extends Middleware { + @Inject() + protected readonly config!: Config + + @Inject() + protected readonly session!: Session + + public async apply() { + const themes = this.config.get('app.colors') as Record + const themeKeys = Object.keys(themes) + + const existingThemeName = this.session.get('theme.name') + const forceNewTheme = Boolean(this.request.input('forceNewTheme')) + const explicitTheme = String(this.request.input('theme') || '') + + if ( explicitTheme && themeKeys.includes(explicitTheme) ) { + this.session.set('theme.name', explicitTheme) + return + } + + if ( existingThemeName && !forceNewTheme ) { + return + } + + const themeName = themeKeys[Math.floor(Math.random() * themeKeys.length)] + this.session.set('theme.name', themeName) + } +} diff --git a/src/app/http/routes/app.routes.ts b/src/app/http/routes/app.routes.ts index e251c9a..25080a2 100644 --- a/src/app/http/routes/app.routes.ts +++ b/src/app/http/routes/app.routes.ts @@ -8,6 +8,7 @@ import {LoadSnippet} from '../middlewares/parameters/LoadSnippet.middleware' import {LoadFeedPosts} from '../middlewares/parameters/LoadFeedPosts.middleware' import {ValidContactForm} from '../middlewares/parameters/ValidContactForm.middleware' import {RateLimit} from '../middlewares/RateLimit.middleware' +import {SiteTheme} from '../middlewares/SiteTheme.middleware' Route.endpoint('options', '**') .handledBy(() => api.one({})) @@ -15,6 +16,7 @@ Route.endpoint('options', '**') Route .group('/', () => { Route.get('/') + .pre(SiteTheme) .parameterMiddleware(LoadFeedPosts) .calls(Home, home => home.welcome) .alias('home') @@ -24,6 +26,7 @@ Route Route.post('/contact') .pre(RateLimit) + .pre(SiteTheme) .parameterMiddleware(ValidContactForm) .calls(Home, home => home.contact) .alias('contact') @@ -38,17 +41,21 @@ Route .calls(Home, home => home.humans) Route.get('/technical') + .pre(SiteTheme) .calls(Home, home => home.technical) Route.get('/analytics/opt-out') + .pre(SiteTheme) .calls(Home, home => home.optOutPrompt) .alias('opt-out-prompt') Route.post('/analytics/opt-out') + .pre(SiteTheme) .calls(Home, home => home.optOut) .alias('opt-out') Route.get('/snippet/:slug') + .pre(SiteTheme) .parameterMiddleware(LoadSnippet) .calls(Snippets, snippets => snippets.viewSnippet) @@ -56,10 +63,12 @@ Route .calls(GoLinks, go => go.launch) Route.get('/favicon.ico') + .pre(SiteTheme) .calls(Home, home => home.favicon) Route.group('feed', () => { Route.get('/') + .pre(SiteTheme) .parameterMiddleware(LoadFeedPosts, {all: true}) .calls(Feed, feed => feed.feed) .alias('feed') diff --git a/src/app/resources/assets/font/lora/Lora-Italic-VariableFont_wght.ttf b/src/app/resources/assets/font/lora/Lora-Italic-VariableFont_wght.ttf new file mode 100644 index 0000000..3ea0d1b Binary files /dev/null and b/src/app/resources/assets/font/lora/Lora-Italic-VariableFont_wght.ttf differ diff --git a/src/app/resources/assets/font/lora/Lora-VariableFont_wght.ttf b/src/app/resources/assets/font/lora/Lora-VariableFont_wght.ttf new file mode 100644 index 0000000..ede727a Binary files /dev/null and b/src/app/resources/assets/font/lora/Lora-VariableFont_wght.ttf differ diff --git a/src/app/resources/assets/font/lora/OFL.txt b/src/app/resources/assets/font/lora/OFL.txt new file mode 100644 index 0000000..0f6fdb1 --- /dev/null +++ b/src/app/resources/assets/font/lora/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Lora Project Authors (https://github.com/cyrealtype/Lora-Cyrillic), with Reserved Font Name "Lora". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/app/resources/assets/font/lora/README.txt b/src/app/resources/assets/font/lora/README.txt new file mode 100644 index 0000000..c5dd0eb --- /dev/null +++ b/src/app/resources/assets/font/lora/README.txt @@ -0,0 +1,71 @@ +Lora Variable Font +================== + +This download contains Lora as both variable fonts and static fonts. + +Lora is a variable font with this axis: + wght + +This means all the styles are contained in these files: + Lora-VariableFont_wght.ttf + Lora-Italic-VariableFont_wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Lora: + static/Lora-Regular.ttf + static/Lora-Medium.ttf + static/Lora-SemiBold.ttf + static/Lora-Bold.ttf + static/Lora-Italic.ttf + static/Lora-MediumItalic.ttf + static/Lora-SemiBoldItalic.ttf + static/Lora-BoldItalic.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (OFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/src/app/resources/assets/font/lora/static/Lora-Bold.ttf b/src/app/resources/assets/font/lora/static/Lora-Bold.ttf new file mode 100644 index 0000000..d976a41 Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-Bold.ttf differ diff --git a/src/app/resources/assets/font/lora/static/Lora-BoldItalic.ttf b/src/app/resources/assets/font/lora/static/Lora-BoldItalic.ttf new file mode 100644 index 0000000..f5538ca Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-BoldItalic.ttf differ diff --git a/src/app/resources/assets/font/lora/static/Lora-Italic.ttf b/src/app/resources/assets/font/lora/static/Lora-Italic.ttf new file mode 100644 index 0000000..69bbf97 Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-Italic.ttf differ diff --git a/src/app/resources/assets/font/lora/static/Lora-Medium.ttf b/src/app/resources/assets/font/lora/static/Lora-Medium.ttf new file mode 100644 index 0000000..92f9c16 Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-Medium.ttf differ diff --git a/src/app/resources/assets/font/lora/static/Lora-MediumItalic.ttf b/src/app/resources/assets/font/lora/static/Lora-MediumItalic.ttf new file mode 100644 index 0000000..b3bfef3 Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-MediumItalic.ttf differ diff --git a/src/app/resources/assets/font/lora/static/Lora-Regular.ttf b/src/app/resources/assets/font/lora/static/Lora-Regular.ttf new file mode 100644 index 0000000..2759f63 Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-Regular.ttf differ diff --git a/src/app/resources/assets/font/lora/static/Lora-SemiBold.ttf b/src/app/resources/assets/font/lora/static/Lora-SemiBold.ttf new file mode 100644 index 0000000..6b279be Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-SemiBold.ttf differ diff --git a/src/app/resources/assets/font/lora/static/Lora-SemiBoldItalic.ttf b/src/app/resources/assets/font/lora/static/Lora-SemiBoldItalic.ttf new file mode 100644 index 0000000..6086adf Binary files /dev/null and b/src/app/resources/assets/font/lora/static/Lora-SemiBoldItalic.ttf differ diff --git a/src/app/resources/assets/font/wobily/TheWobliy-rgeop.otf b/src/app/resources/assets/font/wobily/TheWobliy-rgeop.otf new file mode 100644 index 0000000..d4aa857 Binary files /dev/null and b/src/app/resources/assets/font/wobily/TheWobliy-rgeop.otf differ diff --git a/src/app/resources/assets/main-70s.css b/src/app/resources/assets/main-70s.css new file mode 100644 index 0000000..66227e8 --- /dev/null +++ b/src/app/resources/assets/main-70s.css @@ -0,0 +1,657 @@ +@font-face { + font-family: "TheWobliy"; + src: url("/assets/font/wobily/TheWobliy-rgeop.otf"); + font-weight: normal; + font-display: swap; +} +@font-face { + font-family: "Lora"; + src: url("/assets/font/lora/static/Lora-Regular.ttf"); + font-weight: normal; + font-display: swap; +} +/* These get injected by the view template */ +/* Purple & blue: */ +/*:root { + --c-background: #4a113c; + --c-background-offset: rgba(178, 127, 170, 0.1); + --c-background-offset-2: rgba(178, 127, 170, 0.2); + --c-hero: #6ebbd5; + --c-font: #ffe3ff; + --c-font-muted: #daa7d2; + --c-box: #b27faa; + --c-link: var(--c-hero); + --c-noise-size: 100px; + --c-line-1: rgba(178, 127, 170, 0.2); + --c-line-2: rgba(110, 187, 213, 0.9); + --c-line-3: rgba(218, 167, 210, 0.9); +}*/ +/* Tan, red, & orange */ +/*:root { + --c-background: #f8e4bf; + --c-background-offset: rgb(243, 210, 147, 0.4); + --c-background-offset-2: rgb(111, 71, 46, 0.15); + --c-hero: #d96a59; + --c-font: #6f472e; + --c-font-muted: #ae7813; + --c-box: #e0b95d; + --c-link: var(--c-hero); + --c-noise-size: 100px; + --c-line-1: #edb34f; + --c-line-2: #f88937; + --c-line-3: #e86c36; +}*/ +/** Blue & tan */ +/*:root { + --c-background: #052653; + --c-background-offset: rgba(27, 111, 145, 0.3); + --c-background-offset-2: rgba(127, 167, 158, 0.15); + --c-hero: #f6a56d; + --c-font: #f6dbb0; + --c-font-muted: #dec99a; + --c-box: #87afa6; + --c-link: var(--c-hero); + --c-noise-size: 100px; + --c-line-1: #fbad6f; + --c-line-2: #f47139; + --c-line-3: #de381e; +}*/ +/* Teal & dark blue text */ +/*:root { + --c-background: #c6c2b9; + --c-background-offset: rgba(150, 171, 162, 0.3); + --c-background-offset-2: rgba(150, 171, 162, 0.7); + --c-hero: #d05a40; + --c-font: #3f4962; + --c-font-muted: #5d6780; + --c-box: #96aba2; + --c-link: var(--c-hero); + --c-noise-size: 100px; + --c-line-1: #dcbb8e; + --c-line-2: #95aaa3; + --c-line-3: #3f4962; +}*/ +/* Red & gold */ +/*:root { + --c-background: #510c00; + --c-background-offset: rgba(111, 42, 30, 0.4); + --c-background-offset-2: rgba(111, 42, 30, 1); + --c-hero: #ee6156; + --c-font: #f2d7b4; + --c-font-muted: #cb9866; + --c-box: #e9b1a0; + --c-link: var(--c-hero); + --c-noise-size: 100px; + --c-line-1: #e9c8a0; + --c-line-2: #f6bb4a; + --c-line-3: #ef4c3f; +}*/ +/* Army green lol */ +/*:root { + --c-background: #202318; + --c-background-offset: rgba(46, 41, 22, 0.5); + --c-background-offset-2: rgb(105, 75, 1, 0.3); + --c-hero: #7a7946; + --c-font: #e5ddae; + --c-font-muted: #cb9866; + --c-box: #cbc87c; + --c-link: var(--c-hero); + --c-noise-size: 100px; + --c-line-1: #b5a148; + --c-line-2: #ecb653; + --c-line-3: #71490b; +}*/ +/* purple & white */ +/*:root { + --c-background: #6669aa; + --c-background-offset: rgba(152, 155, 220, 0.4); + --c-background-offset-2: rgba(81, 84, 143, 0.6); + --c-hero: #efe2df; + --c-font: #fff4ed; + --c-font-muted: #b5b7ec; + --c-box: #989bdc; + --c-link: var(--c-hero); + --c-noise-size: 100px; + --c-line-3: #979adb; + --c-line-2: #b3b5f1; + --c-line-1: #efe2df; +}*/ +.section-border { + width: 100vw; + position: absolute; + left: 0; +} +.section-border .section-border-inner-1 { + border-top: 15px solid var(--c-line-1); + border-bottom: 15px solid var(--c-line-3); + transform: rotate(3deg); + width: calc(100vw + 30px); + margin-left: -15px; + position: absolute; +} +.section-border.odd .section-border-inner-1 { + transform: rotate(-3deg); +} +.section-border .section-border-inner-2 { + border-top: 15px solid var(--c-line-2); +} +body { + background: var(--c-background); + color: var(--c-font); + font-family: "Lora", serif; + margin: 0; + padding: 0; + overflow-x: hidden; +} +section { + /*min-height: 100vh;*/ + z-index: 100; + /*display: flex;*/ + /*flex-direction: column;*/ + /*justify-content: center;*/ + padding-bottom: 150px; + margin-top: 100px; +} +.full-height { + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; +} +.text-noise { + background-image: url(data:image/png;base64,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); + background-size: var(--c-noise-size); + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + -webkit-font-smoothing: antialiased; + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ +} +.container { + display: flex; + justify-content: center; + width: 100%; + height: 100%; + text-align: left; + position: relative; +} +body:before { + content: ' '; + display: block; + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: 0.3; + background-image: url(data:image/png;base64,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); + background-size: var(--c-noise-size); + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ +} +h1, h2, h3, h4 { + /*line-height: 1.2em;*/ + font-family: "TheWobliy", serif; + color: var(--c-hero); + background-color: var(--c-hero); + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAUVBMVEWFhYWDg4N3d3dtbW17e3t1dXWBgYGHh4d5eXlzc3OLi4ubm5uVlZWPj4+NjY19fX2JiYl/f39ra2uRkZGZmZlpaWmXl5dvb29xcXGTk5NnZ2c8TV1mAAAAG3RSTlNAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAvEOwtAAAFVklEQVR4XpWWB67c2BUFb3g557T/hRo9/WUMZHlgr4Bg8Z4qQgQJlHI4A8SzFVrapvmTF9O7dmYRFZ60YiBhJRCgh1FYhiLAmdvX0CzTOpNE77ME0Zty/nWWzchDtiqrmQDeuv3powQ5ta2eN0FY0InkqDD73lT9c9lEzwUNqgFHs9VQce3TVClFCQrSTfOiYkVJQBmpbq2L6iZavPnAPcoU0dSw0SUTqz/GtrGuXfbyyBniKykOWQWGqwwMA7QiYAxi+IlPdqo+hYHnUt5ZPfnsHJyNiDtnpJyayNBkF6cWoYGAMY92U2hXHF/C1M8uP/ZtYdiuj26UdAdQQSXQErwSOMzt/XWRWAz5GuSBIkwG1H3FabJ2OsUOUhGC6tK4EMtJO0ttC6IBD3kM0ve0tJwMdSfjZo+EEISaeTr9P3wYrGjXqyC1krcKdhMpxEnt5JetoulscpyzhXN5FRpuPHvbeQaKxFAEB6EN+cYN6xD7RYGpXpNndMmZgM5Dcs3YSNFDHUo2LGfZuukSWyUYirJAdYbF3MfqEKmjM+I2EfhA94iG3L7uKrR+GdWD73ydlIB+6hgref1QTlmgmbM3/LeX5GI1Ux1RWpgxpLuZ2+I+IjzZ8wqE4nilvQdkUdfhzI5QDWy+kw5Wgg2pGpeEVeCCA7b85BO3F9DzxB3cdqvBzWcmzbyMiqhzuYqtHRVG2y4x+KOlnyqla8AoWWpuBoYRxzXrfKuILl6SfiWCbjxoZJUaCBj1CjH7GIaDbc9kqBY3W/Rgjda1iqQcOJu2WW+76pZC9QG7M00dffe9hNnseupFL53r8F7YHSwJWUKP2q+k7RdsxyOB11n0xtOvnW4irMMFNV4H0uqwS5ExsmP9AxbDTc9JwgneAT5vTiUSm1E7BSflSt3bfa1tv8Di3R8n3Af7MNWzs49hmauE2wP+ttrq+AsWpFG2awvsuOqbipWHgtuvuaAE+A1Z/7gC9hesnr+7wqCwG8c5yAg3AL1fm8T9AZtp/bbJGwl1pNrE7RuOX7PeMRUERVaPpEs+yqeoSmuOlokqw49pgomjLeh7icHNlG19yjs6XXOMedYm5xH2YxpV2tc0Ro2jJfxC50ApuxGob7lMsxfTbeUv07TyYxpeLucEH1gNd4IKH2LAg5TdVhlCafZvpskfncCfx8pOhJzd76bJWeYFnFciwcYfubRc12Ip/ppIhA1/mSZ/RxjFDrJC5xifFjJpY2Xl5zXdguFqYyTR1zSp1Y9p+tktDYYSNflcxI0iyO4TPBdlRcpeqjK/piF5bklq77VSEaA+z8qmJTFzIWiitbnzR794USKBUaT0NTEsVjZqLaFVqJoPN9ODG70IPbfBHKK+/q/AWR0tJzYHRULOa4MP+W/HfGadZUbfw177G7j/OGbIs8TahLyynl4X4RinF793Oz+BU0saXtUHrVBFT/DnA3ctNPoGbs4hRIjTok8i+algT1lTHi4SxFvONKNrgQFAq2/gFnWMXgwffgYMJpiKYkmW3tTg3ZQ9Jq+f8XN+A5eeUKHWvJWJ2sgJ1Sop+wwhqFVijqWaJhwtD8MNlSBeWNNWTa5Z5kPZw5+LbVT99wqTdx29lMUH4OIG/D86ruKEauBjvH5xy6um/Sfj7ei6UUVk4AIl3MyD4MSSTOFgSwsH/QJWaQ5as7ZcmgBZkzjjU1UrQ74ci1gWBCSGHtuV1H2mhSnO3Wp/3fEV5a+4wz//6qy8JxjZsmxxy5+4w9CDNJY09T072iKG0EnOS0arEYgXqYnXcYHwjTtUNAcMelOd4xpkoqiTYICWFq0JSiPfPDQdnt+4/wuqcXY47QILbgAAAABJRU5ErkJggg==); + background-size: var(--c-noise-size); + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + -webkit-font-smoothing: antialiased; + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ +} +h1 { + font-size: 80pt; + margin: 0; + padding: 0; +} +h2 { + font-size: 60pt; + padding-top: 70px; + padding-bottom: 0; + margin: 0; + font-weight: 300; +} +h3 { + font-size: 24pt; + /*text-transform: lowercase;*/ + margin: 0; + padding: 30px 0 0; + font-weight: 300; +} +h4 { + font-size: 18pt; + margin: 0; + padding: 40px 0 0; + font-weight: 300; +} +p { + font-size: 18pt; + font-weight: 300; +} +li { + font-size: 16pt; + font-weight: 300; +} +code { + font-size: 12pt; + background: var(--c-background-offset-2); + padding: 5px; + border-radius: 5px; +} +pre code { + display: block; +} +.inner { + padding-bottom: 10%; + max-width: min(70%, 1000px); + min-height: 100vh; +} +.theme-hide { + display: none !important; +} +button, +a.button, +a.button-small { + border: 0; + font-family: "TheWobliy", serif; + color: var(--c-hero); + background-color: var(--c-hero); + background-image: url(data:image/png;base64,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); + background-size: var(--c-noise-size); + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + -webkit-font-smoothing: antialiased; + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ + font-size: 16pt; + padding: 5px 20px; + transition: background-color 0.1s linear; + text-decoration: none; +} +button:hover, +a.button:hover, +a.button-small:hover { + cursor: pointer; + background-color: var(--c-font); +} +button:active, +a.button:active, +a.button-small:active { + background-color: var(--c-background-offset-2); +} +a { + color: var(--c-link); +} +/*a.button-small, +button.small { + padding: 1px 10px; + background: #c9d4e2; + border: none; + color: #3e4552; + margin: 5px; +}*/ +/*a.button-small:hover, +button.small:hover { + color: #c9d4e2; + background: #3e4552; +}*/ +.form-group { + margin: 10px; +} +.form-group label { + font-size: 14pt; + font-weight: 300; + text-transform: lowercase; +} +.form-group input, +.form-group textarea, +.form-group select { + /*border: 1px solid #3e4552;*/ + border: 0; + border-bottom: 2px solid var(--c-box); + /*border-radius: 5px;*/ + font-family: Lora, serif; + padding: 7px; + font-size: 16pt; + min-width: 400px; + background: rgba(0, 0, 0, 0); + color: var(--c-font); +} +.form-group input::placeholder, +.form-group textarea::placeholder, +.form-group select::placeholder { + color: var(--c-font-muted); +} +footer { + position: relative; + /*background: #3e4552;*/ + background: var(--c-background-offset); + display: flex; + flex-direction: row; + justify-content: center; + padding-bottom: 50px; +} +footer ul { + list-style-type: none; + margin: 0; + padding: 50px 0 0; +} +footer ul li { + display: inline; + padding-left: 20px; + padding-right: 20px; +} +footer ul li a { + text-decoration: none; + font-size: 16pt; + font-weight: 300; + transition: all 0.5s; + color: var(--c-font); +} +footer ul li a:hover { + color: var(--c-hero); +} +footer .col { + margin: 0 30px; +} +footer .by-line { + font-family: "TheWobliy", serif; + background-color: var(--c-hero); + background-image: url(data:image/png;base64,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); + background-size: var(--c-noise-size); + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + -webkit-font-smoothing: antialiased; + color: var(--c-hero); + display: flex; + flex-direction: column; + justify-content: center; + font-size: 42pt; + font-weight: 300; + text-align: right; + padding-top: 30px; + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ +} +footer .copy { + font-size: 14pt; + font-weight: 200; +} +footer ul li { + display: block; + margin: 10px 0; +} +footer #tagline:hover { + cursor: pointer; +} +footer .auth-container { + display: flex; + flex-direction: row; +} +footer .auth-container .profile { + margin-right: 15px; + margin-top: 15px; +} +.button-links { + margin: 20px; +} +.button-links a { + margin-right: 10px; +} +@media (max-width: 480px) { + .container { + justify-content: left; + padding: 20px; + width: calc(100% - 40px); + } + .inner { + width: 100%; + max-width: unset; + } + .form-group input, + .form-group textarea, + .form-group select { + min-width: 100%; + } + footer { + flex-direction: column; + } + footer .by-line { + /*text-align: left;*/ + padding: 30px; + line-height: 1.2em; + text-align: center; + } + footer .links { + padding: 20px 0 0; + } + h2 { + font-size: 48pt; + line-height: 1.2em; + } +} +.hero { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-top: 150px; +} +.hero-box { + border: 2px solid var(--c-box); + padding: 0 20px; + text-align: center; + background-color: var(--c-background-offset); +} +.hero h1 { + font-weight: 300; + font-size: 9em; + line-height: 1.2em; + font-family: "TheWobliy", serif; + background-image: url(data:image/png;base64,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); + background-size: var(--c-noise-size); + background-repeat: repeat; + background-color: var(--c-hero); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + -webkit-font-smoothing: antialiased; + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ +} +.hero h2 { + font-size: 36pt; + padding: 0; + font-weight: 300; + margin: 10px 0 0; + font-family: "TheWobliy", serif; + /*text-transform: lowercase;*/ +} +.hero p { + font-size: 20pt; + font-family: "TheWobliy", serif; + background-color: var(--c-font); + background-image: url(data:image/png;base64,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); + background-size: var(--c-noise-size); + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + -webkit-font-smoothing: antialiased; + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ +} +section#about .about-container { + display: flex; + flex-direction: row; +} +section#about .img { + flex-grow: 0; + flex-shrink: 0; +} +section#about .img img { + max-width: 300px; + margin-top: 30px; + margin-right: 20px; + border-radius: 5px; +} +section#work .timeline-group .timeline-year { + font-family: "TheWobliy", serif; + font-size: 24pt; + margin-top: 40px; + background-color: var(--c-font); + background-image: url(data:image/png;base64,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); + background-size: var(--c-noise-size); + background-repeat: repeat; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + -webkit-font-smoothing: antialiased; + image-rendering: crisp-edges; + image-rendering: -moz-crisp-edges; /* Firefox */ + image-rendering: -o-crisp-edges; /* Opera */ + image-rendering: -webkit-optimize-contrast; /* Webkit (non-standard naming)*/ + -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ +} +section#work .timeline-group .timeline-content { + /*background: #3e4552;*/ + padding: 20px; + /*border-radius: 5px;*/ + border: 2px solid var(--c-box); + background-color: var(--c-background-offset); + margin: 20px; +} +section#work .timeline-group .timeline-content h3 { + padding: 0; + font-size: 2.5em; +} +section#work .timeline-group .timeline-content p { + margin: 0; + font-size: 16pt; +} +section#contact .contact-container { + display: flex; + flex-direction: row; +} +section#contact .contact-container .message { + text-align: right; + margin-right: 20px; +} +section#recent .feed-item { + background: var(--c-background-offset); + padding: 20px; + margin: 20px; + /*border-radius: 5px;*/ + border: 2px solid var(--c-box); +} +section#recent .feed-item .feed-category { + display: flex; +} +section#recent .feed-item .feed-category .tag { + /*background: #5e6572;*/ + padding: 2px 5px; + /*border-radius: 2px;*/ + font-size: 14pt; + background: var(--c-background-offset-2); +} +section#recent .feed-item .bottom { + display: flex; + flex-direction: row; + justify-content: end; +} +section#recent .feed-item .bottom .stamp { + margin-left: 20px; + font-size: 14pt; + font-weight: 300; + text-align: right; + flex: 1; +} +section#recent a.button { + margin-left: 20px; +} +section#auth { + max-width: 500px; +} +section#auth h3 { + margin-bottom: 30px; +} +@media (max-width: 480px) { + .hero h1 { + font-size: 48pt; + } + section#about .about-container { + display: flex; + flex-direction: column; + } + section#work .timeline-content { + margin: 20px 0 !important; + } + section#contact .contact-container { + display: flex; + flex-direction: column; + } + section#contact .contact-container .message { + text-align: left; + } + section#recent .feed-item { + margin: 20px 0; + } + section#recent a.button { + margin-left: 0; + } + section#recent .bottom { + flex-wrap: wrap; + } + section#recent .bottom .stamp { + max-width: 100%; + white-space: pre-wrap; + word-wrap: break-word; + } +} +.theme-buttons .button { + white-space: nowrap; +} +.theme-buttons { + list-style-type: none; + margin: 0; + padding: 50px 0 0; +} +.theme-buttons li { + padding-left: 20px; + padding-right: 20px; +} +.theme-buttons li a { + text-decoration: none; + font-size: 16pt; + font-weight: 300; + transition: all 0.5s; + color: var(--c-font); +} +.theme-buttons li a:hover { + color: var(--c-hero); +} diff --git a/src/app/resources/assets/welcome.js b/src/app/resources/assets/welcome.js index 69590a6..e483942 100644 --- a/src/app/resources/assets/welcome.js +++ b/src/app/resources/assets/welcome.js @@ -3,18 +3,20 @@ window.glmdev = window.glmdev || {} window.glmdev.taglines = [ '...is proud that this site is Google-free', '...is a supporter of FLOSS', - '...prefers JavaScript, but Python will do', + '...prefers TypeScript, but C++ will do', '...occasionally rants about dependency injection', '...loves GNU/Linux', '(or as I\'ve recently taken to calling it, GNU+Linux)', '...uses spaces, not tabs', '...self-hosts all the things', + '...uses the Oxford comma', '...occasionally does contract work', '...reads the terms and conditions', - '...enjoys r/sysadmin', + '...is an RSS nerd', '...just lost the game', + '...listens to indie music', '...is running out of tag-line ideas', - `copyright © ${(new Date()).getFullYear()} garrett mills`, + `copyright © ${(new Date()).getFullYear()}`, ] document.querySelector('#tagline') diff --git a/src/app/resources/views/feed.pug b/src/app/resources/views/feed.pug index 3d28631..5c3aabc 100644 --- a/src/app/resources/views/feed.pug +++ b/src/app/resources/views/feed.pug @@ -1,10 +1,11 @@ -extends template_raj +extends template_70s block content .container#top .inner .hero - h1 garrettmills + .hero-box + h1 Garrett Mills section#recent h2 posts & updates .button-links diff --git a/src/app/resources/views/message.pug b/src/app/resources/views/message.pug index 3051651..d861840 100644 --- a/src/app/resources/views/message.pug +++ b/src/app/resources/views/message.pug @@ -1,4 +1,4 @@ -extends template_raj +extends template_70s block content .container#home diff --git a/src/app/resources/views/snippet.pug b/src/app/resources/views/snippet.pug index c3aec1d..31eec05 100644 --- a/src/app/resources/views/snippet.pug +++ b/src/app/resources/views/snippet.pug @@ -1,4 +1,4 @@ -extends template_raj +extends template_70s block append style link(rel='stylesheet' data-name='vs/editor/editor.main' href=asset('monaco/package/min/vs/editor/editor.main.css')) @@ -7,7 +7,8 @@ block content .container#home if needsAccessKey .inner - h2 Snippet: #{snippet.slug} + h2 Snippet + h3 #{snippet.slug} p This snippet is protected by an access key. Please enter it to view: form(method='get') .form-group @@ -15,7 +16,8 @@ block content button View else if needsConfirm .inner - h2 Snippet: #{snippet.slug} + h2 Snippet + h3 #{snippet.slug} p This snippet is single-access only. Once you view it, it will be permanently deleted. Continue? form(method='get') if accessKey @@ -24,7 +26,8 @@ block content button Continue else .inner(style='width: 100%') - h2 Snippet: #{snippet.slug} + h2 Snippet + h3 #{snippet.slug} #monaco-container(style="width: 100%; height: 100%") block append script diff --git a/src/app/resources/views/technical.pug b/src/app/resources/views/technical.pug index 6416468..db26e50 100644 --- a/src/app/resources/views/technical.pug +++ b/src/app/resources/views/technical.pug @@ -1,15 +1,29 @@ -extends template_raj +extends template_70s block content .container#top .inner .hero - h1 garrettmills + .hero-box + h1 Garrett Mills section#technical - h2 technical details for nerds + h2(style="font-size: 48pt") technical details for nerds .fira-p p This page contains a smattering of technical information that I think some people might find interesting, but not enough people for it to be included on the main page. + h3 Website Theme + p I was going for a retro/70s aesthetic for this site. The CSS theme is fully-parameterized over a set of color variables. + p The first time you visit the homepage, the server randomly selects a theme for your browser to use across the site. + p I'm using a combination of The Wobliy as a display font and Lora as a body font. + p For the curious, you can change the theme using the buttons below: + + ul.theme-buttons + each key in themeKeys + li + a.button(href=`../technical?theme=${key}`) #{config(`app.colors.${key}.displayName`)}#{key === themeName ? ' (current)' : ''} + br + br + h3 Source Code & Licensing a(href='https://creativecommons.org/licenses/by-nc-sa/4.0/' target='_blank' style='margin-top: 15px') img(src=asset('cc-by-nc-sa.png')) diff --git a/src/app/resources/views/template_70s.pug b/src/app/resources/views/template_70s.pug new file mode 100644 index 0000000..562d5d7 --- /dev/null +++ b/src/app/resources/views/template_70s.pug @@ -0,0 +1,77 @@ +doctype html +head + block meta + meta(charset='utf-8') + meta(name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no') + meta(http-equiv='x-ua-compatible' content='ie=edge') + meta(name='description' content='Hi, there! My name is Garrett. I am a computer scientist, software engineer, and speaker.') + meta(name='keywords' content='garrett mills glmdev developer speaker flitter extollo student') + meta(name='author' content=config('app.name', 'Garrett Mills')) + meta(name='robots' content='index, follow') + + block title + title #{config('app.name', 'Garrett Mills')} | Developer, Speaker, Designer + + block style + style !{themeCSS} + link(rel='stylesheet' href=asset('main-70s.css')) + + link(rel='author' href='/humans.txt') + link(rel="alternate" href="/feed/atom.xml" title="Garrett Mills - Posts & Updates" type="application/atom+xml") + link(rel="alternate" href="/feed/rss.xml" title="Garrett Mills - Posts & Updates" type="application/rss+xml") + link(rel="alternate" href="/feed/json.json" title="Garrett Mills - Posts & Updates" type="application/feed+json") + + link(rel='apple-touch-icon' sizes='180x180' href=asset('favicon/apple-touch-icon.png')) + link(rel='manifest' href=asset('favicon/site.webmanifest')) + link(rel='icon' type='image/png' sizes='32x32' href=asset('favicon/favicon-32x32.png')) + link(rel='icon' type='image/png' sizes='16x16' href=asset('favicon/favicon-16x16.png')) + link(rel='shortcut icon' href=asset('favicon/favicon.ico')) + +body + block content + + footer + .ff-tag(style="margin-right: 80px") + a(href="https://www.mozilla.org/en-US/firefox/browsers/" target="_blank") + img(src=asset('ffox.png') width="75" style="margin-top: -1px") + .by-line Garrett Mills + .copy#tagline(title="my, aren't you curious...") copyright © #{(new Date()).getFullYear()} + .copyright(style='display: flex; justify-content: right') + a(style='display: flex; padding-top: 10px' href='https://creativecommons.org/licenses/by-nc-sa/4.0/' target='_blank') + img(src=asset('cc-by-nc-sa-small.png') title='This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License') + if user() + div.auth-container(style="justify-content: end") + if user().profileUrl + div.profile + img(src=user().profileUrl width=50 style="border-radius: 50%") + p(style="font-family: Lora, serif") Welcome, #{user().getDisplay()}!  |  Log out + .col + ul.links + li + a(href='/#home') home + li + a(href='/#about') about me + li + a(href='/#work') what I'm working on + li + a(href='/#contact') get in touch + li + a(href='/#recent') latest updates + .col + ul.links + li + a(href='https://static.garrettmills.dev/Resume.pdf' target='_blank') résumé + li + a(href='/blog') blog + li + a(href='https://code.garrettmills.dev/garrettmills' target='_blank') my code + li + a(href='/technical') technical info + li + a(href='?forceNewTheme=true') random theme + if user() + li + a(href='/dash') dashboard + + block script + script(src=asset('welcome.js')) diff --git a/src/app/resources/views/welcome.pug b/src/app/resources/views/welcome.pug index 15aa59e..aa21ef8 100644 --- a/src/app/resources/views/welcome.pug +++ b/src/app/resources/views/welcome.pug @@ -1,10 +1,15 @@ -extends template_raj +extends template_70s block content .container#home .inner - .hero - h1 garrettmills - p Hi, there. My name is Garrett, and I'm a computer scientist, software engineer, and speaker. + section.hero.full-height + .hero-box + h1 Garrett Mills + p Software engineer, computer scientist, and nerd. + //p Hi, there. My name is Garrett, and I'm a computer scientist, software engineer, and speaker. + .section-border + .section-border-inner-1 + .section-border-inner-2 section#about h2 about me .about-container @@ -13,7 +18,9 @@ block content .about p Hi! My name is Garrett. Welcome to my corner of the internet. I'm a computer scientist, software engineer, and speaker. I like to build software to improve the developer/user experience. I created the Extollo framework, Noded, CoreID authentication server, and a couple other projects. I love to communicate my work, and help others pursue their projects. I write blog posts, hold talks, and publish code from my projects in the hope that others will find it useful. I also do a bit of consulting. p A bit more background: I grew up in the rural mid-west, and I got started by teaching myself everything I know. I'm a big fan of learning to code this way. I completed a bachelor of science in computer science at the University of Kansas, and I'm currently a graduate student studying programming languages and formal methods at KU. - + .section-border.odd + .section-border-inner-1 + .section-border-inner-2 if workItemYears && workItemYears.length section#work h2 what I'm working on @@ -32,7 +39,9 @@ block content p !{item.description} .work-container button#timeline-view-all show past work - + .section-border + .section-border-inner-1 + .section-border-inner-2 section#contact h2 get in touch .contact-container @@ -50,7 +59,9 @@ block content textarea.form-control#contactMessage(name='message' placeholder='Message' required rows=6) .form-group button Send - + .section-border.odd + .section-border-inner-1 + .section-border-inner-2 section#recent h2 latest updates each item in feedPosts