Archived
0
0
Fork 0

basic website

This commit is contained in:
Daryl Ronningen 2021-07-12 22:03:28 -07:00
parent fc43dca665
commit 58ca081002
Signed by: Daryl Ronningen
GPG key ID: FD23F0C934A5EC6B
23 changed files with 9299 additions and 1 deletions

5
.browserslistrc Normal file
View file

@ -0,0 +1,5 @@
> 0.5%
last 2 major versions
Firefox ESR
not dead
not IE 11

4
.gitignore vendored
View file

@ -573,6 +573,7 @@ FodyWeavers.xsd
# Icon must end with two \r
Icon
# Thumbnails
._*
@ -633,3 +634,6 @@ $RECYCLE.BIN/
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
# ---> Local
!.yarn/releases
stats.json

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

55
.yarn/releases/yarn-2.4.2.cjs vendored Executable file

File diff suppressed because one or more lines are too long

9
.yarnrc.yml Normal file
View file

@ -0,0 +1,9 @@
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript"
yarnPath: .yarn/releases/yarn-2.4.2.cjs

11
babel.config.json Normal file
View file

@ -0,0 +1,11 @@
{
"presets": [["@babel/preset-env", {
"bugfixes": true,
"spec": true,
"useBuiltIns": "entry",
"shippedProposals": true
}], "@babel/preset-typescript"],
"plugins": [["@babel/plugin-transform-runtime", {
"corejs": 3
}]]
}

65
package.json Normal file
View file

@ -0,0 +1,65 @@
{
"name": "website",
"version": "0.0.1",
"description": "Source code for my personal website",
"main": "dist/index.js",
"repository": "https://code.relms.dev/Relms/website",
"author": "Daryl Ronningen <relms@relms.dev>",
"license": "GPL-3.0-or-later",
"private": true,
"sideEffects": false,
"scripts": {
"analyze": "webpack --config webpack.analyze.js --profile --json > stats.json && webpack-bundle-analyzer stats.json",
"build:dev": "webpack --config webpack.dev.js",
"build:prod": "webpack --config webpack.prod.js",
"dev": "webpack serve --open --config webpack.dev.js",
"prod": "serve --cors --single dist",
"update-browserlist": "yarn browserslist --update-db",
"update-supported-browsers": "echo \"export default $(browserslist-useragent-regexp --allowHigherVersions);\" > src/ts/supportedBrowsers.ts"
},
"dependencies": {
"@babel/runtime-corejs3": "^7.14.7",
"bulma": "^0.9.3",
"bulma-prefers-dark": "^0.1.0-beta.0",
"core-js": "^3.15.1",
"handlebars": "^4.7.7",
"i18next": "^20.3.2",
"i18next-browser-languagedetector": "^6.1.2",
"i18next-chained-backend": "^3.0.2",
"i18next-http-backend": "^1.2.6",
"i18next-localstorage-backend": "^3.1.3",
"regenerator-runtime": "^0.13.7"
},
"devDependencies": {
"@babel/core": "^7.14.6",
"@babel/plugin-transform-runtime": "^7.14.5",
"@babel/preset-env": "^7.14.7",
"@babel/preset-typescript": "^7.14.5",
"@types/csp-html-webpack-plugin": "^3.0.1",
"@types/mini-css-extract-plugin": "^1.4.3",
"@types/regenerator-runtime": "^0.13.0",
"@types/sass": "^1.16.0",
"@types/webpack-bundle-analyzer": "^4.4.0",
"babel-loader": "^8.2.2",
"browserslist": "^4.16.6",
"browserslist-useragent-regexp": "^3.0.0",
"compression-webpack-plugin": "^8.0.1",
"copy-webpack-plugin": "^9.0.1",
"csp-html-webpack-plugin": "^5.1.0",
"css-loader": "^5.2.6",
"handlebars-loader": "^1.7.1",
"html-webpack-plugin": "^5.3.2",
"inline-source-map": "^0.6.2",
"mini-css-extract-plugin": "^1.6.1",
"sass": "^1.35.1",
"sass-loader": "^12.1.0",
"serve": "^12.0.0",
"style-loader": "^3.0.0",
"typescript": "^4.3.4",
"webpack": "^5.40.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.8.0"
}
}

1
src/hbs/argonbot.hbs Normal file
View file

@ -0,0 +1 @@
<h1>Lorem Ipsum</h1>

25
src/hbs/header.hbs Normal file
View file

@ -0,0 +1,25 @@
<nav class="navbar is-fixed-top" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbar">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbar" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item" id="homeNavBar">{{i18n 'header.home'}}</a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless" id="currentProjectsNavBar">
{{i18n 'header.currentProjects'}}
</a>
<div class="navbar-dropdown">
<a class="navbar-item" id="argonBotNavBar">{{i18n 'header.argonBot'}}</a>
</div>
</div>
</div>
</div>
</nav>

3
src/hbs/home.hbs Normal file
View file

@ -0,0 +1,3 @@
<div class="container">
<h1>{{i18n 'placeholder'}}</h1>
</div>

1
src/hbs/projects.hbs Normal file
View file

@ -0,0 +1 @@
<h1>{{i18n 'placeholder'}}</h1>

39
src/styles/style.scss Normal file
View file

@ -0,0 +1,39 @@
@charset "utf-8";
@import '~bulma/bulma';
@import '~bulma-prefers-dark/bulma-prefers-dark';
.navbar-start {
flex-grow: 1;
justify-content: center;
text-align: center;
}
@media screen and (max-width: $desktop - 1px) {
#logo{
display: none;
}
.force-center{
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.navbar-end{
display: flex;
justify-content: center;
}
}
@media screen and (min-width: $desktop) {
.navbar-brand{
display: none;
}
.navbar-end {
padding: 20px;
right: 0;
position: absolute;
}
}

104
src/ts/index.ts Normal file
View file

@ -0,0 +1,104 @@
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import i18next from 'i18next';
import HttpBackend from 'i18next-http-backend';
import ChainedBackend from 'i18next-chained-backend';
import LocalStorageBackend from 'i18next-localstorage-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import Handlebars from 'handlebars/runtime';
import supportedBrowsers from './supportedBrowsers';
import { changeBodyData, changeState } from './utils';
import '../styles/style.scss';
const header = require("../hbs/header.hbs");
const jsonKeys = ['lngs', 'fallbackLng', 'ns', 'postProcess', 'interpolation'];
Handlebars.registerHelper('i18n', (key: any, {hash, data, fn}: any) => {
let parsed = {};
jsonKeys.forEach(key => {
if (hash[key]) {
// @ts-ignore
parsed[key] = JSON.parse(hash[key]);
delete hash[key];
}
});
let options = Object.assign({}, data.i18next, hash, parsed, {returnObjects: false});
let replace = options['replace'] = Object.assign({}, this, options['replace'], hash);
delete replace['i18next'];
if (fn) options['defaultValue'] = fn(replace);
return new Handlebars.SafeString(i18next.t(key, options));
});
document.addEventListener("DOMContentLoaded", async () => {
// @ts-ignore
await i18next.use(ChainedBackend).use(LanguageDetector).init({
supportedLngs: ['en-US'],
fallbackLng: 'en-US',
backend: {
backends: [
LocalStorageBackend,
HttpBackend,
],
backendOptions: [{
expirationTime: 7 * 24 * 60 * 60 * 1000,
}, {
loadPath: '/translations/{{lng}}.json',
}],
},
});
document.getElementsByTagName('html').item(0)!.classList.add('has-navbar-fixed-top');
const headerDiv = document.createElement('div');
const bodyDiv = document.createElement('div');
headerDiv.innerHTML = header();
document.body.appendChild(headerDiv);
const navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
if (navbarBurgers.length > 0) {
navbarBurgers.forEach(el => {
el.addEventListener('click', () => {
const target = el.dataset.target;
const $target = document.getElementById(target);
el.classList.toggle('is-active');
$target!.classList.toggle('is-active');
});
});
}
document.getElementById('homeNavBar')!.addEventListener('click', () => {
changeState('/');
});
document.getElementById('currentProjectsNavBar')!.addEventListener('click', () => {
changeState('/projects');
});
document.getElementById('argonBotNavBar')!.addEventListener('click', () => {
changeState('/argonBot');
});
window.addEventListener('onPushState', (e) => {
// @ts-ignore
changeBodyData(e.detail.url, bodyDiv);
});
changeBodyData(window.location.pathname, bodyDiv);
console.log(i18next.t('placeholder'));
});
if(!supportedBrowsers.test(navigator.userAgent)) {
alert('Your browser is not supported. The website may not work as intended.');
}

View file

@ -0,0 +1 @@
export default /((CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS)[ +]+(13[_.]0|13[_.]([1-9]|\d{2,})|13[_.]7|13[_.]([8-9]|\d{2,})|(1[4-9]|[2-9]\d|\d{3,})[_.]\d+|14[_.]0|14[_.]([1-9]|\d{2,})|14[_.]4|14[_.]([5-9]|\d{2,})|(1[5-9]|[2-9]\d|\d{3,})[_.]\d+)(?:[_.]\d+)?)|(Opera Mini(?:\/att)?\/?(\d+)?(?:\.\d+)?(?:\.\d+)?)|(Opera\/.+Opera Mobi.+Version\/(62\.0|62\.([1-9]|\d{2,})|(6[3-9]|[7-9]\d|\d{3,})\.\d+))|(Opera\/(62\.0|62\.([1-9]|\d{2,})|(6[3-9]|[7-9]\d|\d{3,})\.\d+).+Opera Mobi)|(Opera Mobi.+Opera(?:\/|\s+)(62\.0|62\.([1-9]|\d{2,})|(6[3-9]|[7-9]\d|\d{3,})\.\d+))|(SamsungBrowser\/(13\.0|13\.([1-9]|\d{2,})|(1[4-9]|[2-9]\d|\d{3,})\.\d+))|(Edge\/(90(?:\.0)?|90(?:\.([1-9]|\d{2,}))?|(9[1-9]|\d{3,})(?:\.\d+)?))|((Chromium|Chrome)\/(89\.0|89\.([1-9]|\d{2,})|(9\d|\d{3,})\.\d+)(?:\.\d+)?)|(Version\/(13\.0|13\.([1-9]|\d{2,})|(1[4-9]|[2-9]\d|\d{3,})\.\d+|14\.0|14\.([1-9]|\d{2,})|(1[5-9]|[2-9]\d|\d{3,})\.\d+)(?:\.\d+)? Safari\/)|(Firefox\/(78\.0|78\.([1-9]|\d{2,})|(79|[8-9]\d|\d{3,})\.\d+|88\.0|88\.([1-9]|\d{2,})|(89|9\d|\d{3,})\.\d+)\.\d+)|(Firefox\/(78\.0|78\.([1-9]|\d{2,})|(79|[8-9]\d|\d{3,})\.\d+|88\.0|88\.([1-9]|\d{2,})|(89|9\d|\d{3,})\.\d+)(pre|[ab]\d+[a-z]*)?)/;

30
src/ts/utils.ts Normal file
View file

@ -0,0 +1,30 @@
const home = require('../hbs/home.hbs');
const projects = require('../hbs/projects.hbs');
const argonBot = require('../hbs/argonbot.hbs');
export const changeState = (url: string) => {
window.history.pushState(null, '', url);
const event = new CustomEvent('onPushState', {detail: { url }});
window.dispatchEvent(event);
}
export const changeBodyData = (url: string, element: HTMLDivElement) => {
switch (url) {
case '/':
element.innerHTML = home();
document.body.appendChild(element);
break;
case '/projects':
element.innerHTML = projects();
document.body.appendChild(element);
break;
case '/argonBot':
element.innerHTML = argonBot();
document.body.appendChild(element);
break;
default:
changeState('/');
}
}

8
translations/en-US.json Normal file
View file

@ -0,0 +1,8 @@
{
"placeholder": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n\t\taliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\t\tDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n\t\tsint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"header": {
"home": "Home",
"currentProjects": "My Current Projects",
"argonBot": "Argon Bot"
}
}

90
tsconfig.json Normal file
View file

@ -0,0 +1,90 @@
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"composite": true,
"downlevelIteration": true,
"importHelpers": true,
"incremental": true,
"lib": [
"ESNext",
"DOM"
],
"module": "ESNext",
"outDir": "dist",
"tsBuildInfoFile": "dist/.tsbuildinfo",
"removeComments": true,
"target": "ESNext",
"alwaysStrict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strict": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"moduleResolution": "Node",
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"disableSizeLimit": true,
"explainFiles": false,
"extendedDiagnostics": false,
"forceConsistentCasingInFileNames": true,
"importsNotUsedAsValues": "error",
"listEmittedFiles": false,
"listFiles": false,
"newLine": "lf",
"noEmitOnError": true,
"preserveConstEnums": true,
"resolveJsonModule": true,
"traceResolution": false,
"baseUrl": ".",
"plugins": [
{
"name": "typescript-eslint-language-service"
}
],
"paths": {
"@/*": [
"*"
],
"@/src": [
"src/*"
],
"@lib/*": [
"src/lib/*"
],
"@utils/*": [
"src/lib/utils/*"
],
"@structures/*": [
"src/lib/structures/*"
]
}
},
"watchOptions": {
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
"fallbackPolling": "dynamicpriority",
"synchronousWatchDirectory": true,
"excludeDirectories": [
"node_modules",
"dist"
]
},
"include": [
"src/**/*.ts",
"translations/**/*.json"
]
}

68
webpack.analyze.js Normal file
View file

@ -0,0 +1,68 @@
const { merge } = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CspHtmlWebpackPlugin = require('csp-html-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
plugins: [
new CspHtmlWebpackPlugin({
'script-src': '',
'style-src': '',
}, {
hashingMethod: 'sha512',
}),
new MiniCssExtractPlugin({
filename: '[name].[chunkhash].css',
}),
],
module: {
rules: [
{
test: /\.[cs][ac]ss$/,
exclude: /node_modules/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
enforce: true,
},
js: {
test: /\.js$/,
name: 'js',
chunks: 'all',
enforce: true,
},
styles: {
test: /\.css$/,
name: 'styles',
chunks: 'all',
enforce: true,
},
},
},
runtimeChunk: true,
moduleIds: 'deterministic',
removeAvailableModules: true,
removeEmptyChunks: true,
usedExports: true,
innerGraph: true,
concatenateModules: true,
mergeDuplicateChunks: true,
portableRecords: true,
sideEffects: false,
flagIncludedChunks: true,
chunkIds: "deterministic",
realContentHash: true,
providedExports: true,
emitOnErrors: true,
mangleExports: "deterministic",
},
});

56
webpack.common.js Normal file
View file

@ -0,0 +1,56 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
index: './src/ts/index.ts',
supportedBrowsers: './src/ts/supportedBrowsers.ts',
utils: './src/ts/utils.ts',
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['@babel/preset-env', '@babel/preset-typescript'],
plugins: ['@babel/plugin-transform-runtime'],
},
},
},
{
test: /\.hbs$/,
exclude: /node_modules/,
use: {
loader: 'handlebars-loader',
options: {
knownHelpersOnly: false,
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin(),
new CopyPlugin({
patterns: [
{ from: 'translations', to: 'translations' },
],
}),
],
resolve: {
extensions: ['.js', '.ts'],
},
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
experiments: {
topLevelAwait: true,
},
};

36
webpack.dev.js Normal file
View file

@ -0,0 +1,36 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.[cs][ac]ss$/,
exclude: /node_modules/,
use: ['style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
}],
sideEffects: true,
},
],
},
devServer: {
contentBase: './dist',
compress: true,
liveReload: true,
watchContentBase: true,
historyApiFallback: true,
},
});

78
webpack.prod.js Normal file
View file

@ -0,0 +1,78 @@
const { merge } = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CspHtmlWebpackPlugin = require('csp-html-webpack-plugin');
const CompressionPlugin = require("compression-webpack-plugin");
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
plugins: [
new CspHtmlWebpackPlugin({
'script-src': '',
'style-src': '',
}, {
hashingMethod: 'sha512',
}),
new MiniCssExtractPlugin({
filename: '[name].[chunkhash].css',
}),
new CompressionPlugin({
filename: "[path][base].gz",
test: /\.(js|css|html|svg)$/,
compressionOptions: {
level: 9,
},
minRatio: Infinity,
deleteOriginalAssets: true,
}),
],
module: {
rules: [
{
test: /\.[cs][ac]ss$/,
exclude: /node_modules/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
enforce: true,
},
js: {
test: /\.js$/,
name: 'js',
chunks: 'all',
enforce: true,
},
styles: {
test: /\.css$/,
name: 'styles',
chunks: 'all',
enforce: true,
},
},
},
runtimeChunk: true,
moduleIds: 'deterministic',
removeAvailableModules: true,
removeEmptyChunks: true,
usedExports: true,
innerGraph: true,
concatenateModules: true,
mergeDuplicateChunks: true,
portableRecords: true,
sideEffects: false,
flagIncludedChunks: true,
chunkIds: "deterministic",
realContentHash: true,
providedExports: true,
emitOnErrors: true,
mangleExports: "deterministic",
},
});

8524
yarn.lock Normal file

File diff suppressed because it is too large Load diff