Merge branch 'simplify/front-end' into beta

- Ditched node_modules aka the blackhole in the client
master
Raymonzut 4 years ago
commit 8acedc284b
No known key found for this signature in database
GPG Key ID: 1E9BCC39EDD1DD53
  1. 32
      .github/workflows/nodejs.yml
  2. 1
      client/.dockerignore
  3. 9
      client/Dockerfile
  4. 3
      client/babel.config.js
  5. 25
      client/nginx.conf
  6. 13023
      client/package-lock.json
  7. 56
      client/package.json
  8. 15
      client/public/assets/styling/general.css
  9. 18
      client/public/assets/styling/themes.css
  10. 10
      client/public/error/404.html
  11. 55
      client/public/index.html
  12. 4
      client/public/index.mjs
  13. 6
      client/public/lib/me.mjs
  14. 24
      client/public/lib/remote.mjs
  15. 37
      client/public/posts.html
  16. 61
      client/public/posts.mjs
  17. 33
      client/public/qa.html
  18. 87
      client/src/App.vue
  19. BIN
      client/src/assets/logo.png
  20. 40
      client/src/components/AboutMe.vue
  21. 18
      client/src/components/Answer.vue
  22. 38
      client/src/components/QA.vue
  23. 27
      client/src/components/Question.vue
  24. 14
      client/src/main.js
  25. 23
      client/src/remote.js
  26. 46
      client/src/router/index.js
  27. 19
      client/src/views/Home.vue
  28. 45
      client/src/views/Post.vue
  29. 68
      client/src/views/Posts.vue
  30. 25
      client/src/views/QAPage.vue
  31. 4
      client/test/me.js
  32. 22
      client/test_runner.js

@ -1,32 +0,0 @@
name: Node.js CI
on:
push:
branches: [ master, beta ]
pull_request:
branches: [ master ]
jobs:
build:
env:
CLIENT_DIR: ./client
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x, 13.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
working-directory: ${{env.CLIENT_DIR}}
- run: npm run build --if-present
working-directory: ${{env.CLIENT_DIR}}
- run: npm test
working-directory: ${{env.CLIENT_DIR}}
env:
CI: true

@ -1,2 +1 @@
**/node_modules **/node_modules
**/dist

@ -1,11 +1,4 @@
FROM node:latest as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
RUN npm run build
FROM nginx as production-stage FROM nginx as production-stage
RUN mkdir /app RUN mkdir /app
COPY --from=build-stage /app/dist /app COPY /public /app
COPY nginx.conf /etc/nginx/nginx.conf COPY nginx.conf /etc/nginx/nginx.conf

@ -1,3 +0,0 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
}

@ -7,7 +7,10 @@ events {
} }
http { http {
include /etc/nginx/mime.types; include /etc/nginx/mime.types;
default_type application/octet-stream; types {
application/javascript mjs;
}
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" ' '$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; '"$http_user_agent" "$http_x_forwarded_for"';
@ -20,8 +23,26 @@ http {
location / { location / {
root /app; root /app;
index index.html; index index.html;
try_files $uri $uri/ /index.html; try_files $uri $uri/ $uri.html $uri/index.html =404;
}
location /css {
alias /app/assets/styling;
}
location /js {
alias /app/lib;
}
location /api {
proxy_pass https://raymon.dev/api;
proxy_buffering on;
}
error_page 404 /404.html;
location = /404.html {
root /app/error;
} }
error_page 500 502 503 504 /50x.html; error_page 500 502 503 504 /50x.html;
location = /50x.html { location = /50x.html {
root /usr/share/nginx/html; root /usr/share/nginx/html;

13023
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,56 +0,0 @@
{
"name": "personal-website",
"version": "1.1.0",
"private": true,
"description": "A nice introduction to my chaos",
"main": "src/main.js",
"scripts": {
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"serve": "vue-cli-service serve",
"test": "node test_runner"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Raymonzut/Personal-Website.git"
},
"author": "Raymonzut",
"license": "ISC",
"bugs": {
"url": "https://github.com/Raymonzut/Personal-Website/issues"
},
"homepage": "https://github.com/Raymonzut/Personal-Website#readme",
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-resource": "^1.5.1",
"vue-router": "^3.1.6"
},
"devDependencies": {
"babel-eslint": "^10.0.3",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.1.2",
"@vue/cli-plugin-babel": "~4.2.0",
"@vue/cli-plugin-eslint": "~4.2.0",
"@vue/cli-service": "~4.2.0",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}

@ -0,0 +1,15 @@
nav {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
@media (max-width: 420px) {
#app {
margin-left: 0vw;
margin-right: 0vw;
}
}
.question {
font-style: italic;
}

@ -0,0 +1,18 @@
:root {
--primary-color: #272736;
--text-color: #ffffeb;
/* Overriding DP DS */
--body-background: var(--primary-color);
--body-color: var(--text-color);
--nav-color: var(--primary-color);
--nav-background: var(--text-color);
}
@media (prefers-color-scheme: light) {
:root {
--primary-color: #ffffeb;
--text-color: #272736;
}
}

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>404</title>
</head>
<body>
This page could not be found, sorry for the inconvenience
</body>
</html>

@ -1,26 +1,49 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE-edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Personal Website</title> <title>Raymon Zutekouw</title>
<style> <link defer
body, html { rel="stylesheet"
padding: 0; href="https://cdn.statically.io/gh/dragonprojects/dragondesign/master/main.min.css"
margin: 0; media="all"
width: 100%; >
} <link defer rel="stylesheet" href="css/themes.css" media="all">
</style> <link defer rel="stylesheet" href="css/general.css" media="all">
</head>
<script defer type="module" src="index.mjs"></script>
</head>
<body> <body>
<noscript> <div id="app">
<strong>This site doesn't work properly without JavaScript enabled. Please enable to continue.</strong> <nav>
</noscript> <a href="/">Home</a>|
<div id="app"></div> <a href="/posts">Posts</a>|
</body> <a href="/qa">QA</a>
</nav>
<h1>Home</h1>
<div>
<h2>Who am I?</h2>
<p>
Hi there, good to see you on my website.
My name is Raymon Zutekouw (<span id="age">born on 29-08-2002</span>)
</p>
<p>
Building software and exploring the wide variety of tools (or making them) is my passion.
To see it in action, checkout the stuff I make on
<a href='https://github.com/Raymonzut'>GitHub</a>.
</p>
<p>
The projects that may be useful to others are open source; for inspiring others and improving each others work.
That is why I am a huge fan of
<a href='https://www.gnu.org/philosophy/free-sw.en.html'>free software</a>.
</p>
</div>
</div>
</body>
</html> </html>

@ -0,0 +1,4 @@
import { age } from "./lib/me.mjs"
const age_span = document.getElementById("age")
age_span.textContent = age().toString()

@ -1,8 +1,4 @@
module.exports = { export function age() {
age: age,
}
function age() {
let birthdate = new Date(2002, 8, 29) let birthdate = new Date(2002, 8, 29)
let now = new Date() let now = new Date()

@ -0,0 +1,24 @@
export async function getPosts(id) {
const BASE_URL = 'https://raymon.dev'
const BASE_ENDPOINT = '/api/posts'
const URL = BASE_URL + BASE_ENDPOINT + (id ? `/${id}` : '?sort=-1')
let posts = []
return await fetch(URL)
.then(res => res.json())
.then(res => {
if (id !== undefined) {
if (res === undefined) {
throw Error("Response body empty")
}
return [res]
}
else {
return res
}
})
.catch(err => {
console.log(`Error: ${err}`)
})
}

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Raymon Zutekouw</title>
<link defer
rel="stylesheet"
href="https://cdn.statically.io/gh/dragonprojects/dragondesign/master/main.min.css"
media="all"
>
<link defer rel="stylesheet" href="css/themes.css" media="all">
<link defer rel="stylesheet" href="css/general.css" media="all">
<script defer type="module" src="posts.mjs"></script>
</head>
<body>
<noscript>
<p>
This page isn't as fancy without JavaScript.
Some parts will not load, but this will be minimal.
</p>
</noscript>
<div id="app">
<nav>
<a href="/">Home</a>|
<a href="/posts">Posts</a>|
<a href="/qa">QA</a>
</nav>
<!-- Placeholder for posts -->
<div id="posts"></div>
</div>
</body>
</html>

@ -0,0 +1,61 @@
import { getPosts } from "./lib/remote.mjs"
function toMonthYearString(str) {
const date = new Date(str)
return `${date.toLocaleString('default', { month: 'long' })} ${date.getFullYear()}`
}
async function showPost(id) {
const post_list = await getPosts(id)
const post = post_list[0]
const title = document.createElement("h1")
title.textContent = post.title
const postsDOM = document.getElementById("posts")
postsDOM.appendChild(title)
post.content.split('\n').forEach(paragraph => {
const p = document.createElement("p")
p.textContent = paragraph
postsDOM.appendChild(p)
});
}
async function updatePosts() {
const posts = await getPosts()
const months = posts.map(post => toMonthYearString(post.date))
const uniques = Array.from(new Set(posts.map(post => toMonthYearString(post.date))))
const month_lists = uniques.map(month =>
posts.filter(
post => toMonthYearString(post.date) === month
)
)
const postsDOM = document.getElementById("posts")
uniques.forEach((month, i) => {
const month_DOM = document.createElement("h1")
month_DOM.textContent = month
month_lists[i].forEach((post, i) => {
const post_DOM = document.createElement("h6")
post_DOM.textContent = `${post.date.substring(0, 10)} - `
const post_link = document.createElement("a")
post_link.href = 'posts?post=' + post._id
post_link.textContent = post.title
post_DOM.appendChild(post_link)
month_DOM.appendChild(post_DOM)
})
postsDOM.appendChild(month_DOM)
})
}
// Check if a specific post is requested
let url = new URL(document.location.href);
url.searchParams.sort();
let post_id = url.searchParams.values().next().value;
const reg = /([0-9]|[a-f]){24}/
if (post_id && reg.test(post_id)) showPost(post_id)
else updatePosts()

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Raymon Zutekouw</title>
<link defer
rel="stylesheet"
href="https://cdn.statically.io/gh/dragonprojects/dragondesign/master/main.min.css"
media="all"
>
<link defer rel="stylesheet" href="css/themes.css" media="all">
<link defer rel="stylesheet" href="css/general.css" media="all">
</head>
<body>
<div id="app">
<nav>
<a href="/">Home</a>|
<a href="/posts">Posts</a>|
<a href="/qa">QA</a>
</nav>
<div>
<h4 class="question">What is this site about?</h4>
<h4>This site is about me and the stuff I make</h4>
<h4 class="question">Why is it still so empty?</h4>
<h4>Because I am framework hopping and now ditching frameworks all together</h4>
</div>
</div>
</body>
</html>

@ -1,87 +0,0 @@
<template>
<div id="app" :class="theme">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/posts">Posts</router-link> |
<router-link to="/qa">QA</router-link>
</div>
<div>
<button id="toggleThemeButton" @click="toggleTheme">{{ themeToggleVerb }} my eyes</button>
</div>
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
theme: 'dark'
}
},
computed: {
themeToggleVerb: function() {
return this.theme === 'light' ? "Save" : "Hurt"
}
},
methods: {
toggleTheme() {
const themes = ['light', 'dark']
this.theme = themes[(themes.indexOf(this.theme) + 1) % themes.length]
}
},
}
</script>
<style>
.light {
--primary-color: #ffffeb;
--text-color: #272736;
}
.dark {
--primary-color: #272736;
--text-color: #ffffeb;
}
.dark a {
color: #7e7e8f;
}
body {
background-color: var(--primary-color);
}
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: var(--text-color);
padding-top: 60px;
background-color: var(--primary-color);
min-height: 100vh;
}
#toggleThemeButton {
background: var(--primary-color);
border: 0px;
color: var(--text-color);
margin: 0 auto;
margin-right: 0px;
}
@media (min-width:420px) {
#toggleThemeButton {
float:right;
margin-right: 10px;
}
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

@ -1,40 +0,0 @@
<template>
<div>
<h2>Who am I?</h2>
<p>
Hi there, good to see you on my website.
My name is Raymon Zutekouw({{ age }}).
</p>
<p>
Building software and exploring the wide variety of tools (or making them) is my passion.
To see it in action, checkout the stuff I make on
<a href='https://github.com/Raymonzut'>GitHub</a>.
</p>
<p>
The projects that may be useful to others are open source; for inspiring others and improving each others work.
That is why I am a huge fan of
<a href='https://www.gnu.org/philosophy/free-sw.en.html'>free software</a>.
</p>
</div>
</template>
<script>
import me from '../me.js'
export default {
name: 'AboutMe',
computed: {
age: me.age
}
};
</script>
<style scoped>
p {
--margin-side: 12vw;
margin-left: var(--margin-side);
margin-right: var(--margin-side);
}
</style>

@ -1,18 +0,0 @@
<template>
<div>
{{ a }}
</div>
</template>
<script>
export default {
name: 'Answer',
props: {
a: {
type: String,
required: true,
}
}
}
</script>

@ -1,38 +0,0 @@
<template>
<div id='qa'>
<Question :q='q'></Question>
<Answer :a='a'></Answer>
</div>
</template>
<script>
import Question from './Question.vue'
import Answer from './Answer.vue'
export default {
name: 'QA',
components: {
Question,
Answer,
},
props: {
q: {
type: String,
required: true,
},
a: {
type: String,
required: true,
}
}
}
</script>
<style scoped>
#qa {
--block-spacing: 7.5em;
margin-top: var(--block-spacing);
margin-bottom: var(--block-spacing);
}
</style>

@ -1,27 +0,0 @@
<template>
<div id='question_box'>
{{ q }}
</div>
</template>
<script>
export default {
name: 'Question',
props: {
q: {
type: String,
required: true,
}
}
}
</script>
<style scoped>
#question_box {
--text-spacing: 0.75em;
font-style: italic;
margin-top: var(--text-spacing);
margin-bottom: var(--text-spacing);
}
</style>

@ -1,14 +0,0 @@
import Vue from 'vue'
import VueResource from 'vue-resource'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
Vue.use(VueResource)
new Vue({
render: h => h(App),
router,
}).$mount('#app')

@ -1,23 +0,0 @@
module.exports = {
getPosts: function(id) {
const BASE_URL = '/api/posts'
const URL = BASE_URL + (id ? `/${id}` : '?sort=-1')
this.$http
.get(URL)
.then(res => {
if (id) {
if (res.body.length === 0) {
throw Error("Response body empty")
}
this.post = res.body
}
else {
this.posts = res.body
}
})
.catch(err => {
console.log(`Error: ${err}`)
})
},
}

@ -1,46 +0,0 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Posts from '../views/Posts.vue'
import Post from '../views/Post.vue'
import QAPage from '../views/QAPage'
Vue.use(VueRouter)
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/posts",
name: "Posts",
component: Posts,
},
{
path: "/posts/:id",
name: "Post",
component: Post,
props: true,
},
{
path: "/qa",
name: "QA",
component: QAPage
},
]
const exclude_routes = [
{
path: "/api"
}
]
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes: routes.concat(exclude_routes),
})
export default router

@ -1,19 +0,0 @@
<template>
<div id="home">
<h1>Home</h1>
<AboutMe></AboutMe>
</div>
</template>
<script>
import AboutMe from '@/components/AboutMe'
export default {
name: "Home",
components: {
AboutMe
},
}
</script>
<style scoped></style>

@ -1,45 +0,0 @@
<template>
<div id="Post">
<div v-if="Object.keys(post).length">
<h1>{{ post.title }}</h1>
<h5>Written on {{ post.date.substring(0,10)}}</h5>
<p v-for="(p, i) in post.content.split('\n')" :key="i">{{ p }}</p>
</div>
<h2 v-else>Waiting for post</h2>
<br>
Read other <a href="/posts">posts</a>
<br>
</div>
</template>
<script>
import { getPosts } from '../remote'
export default {
name: "Post",
data() {
return {
post: {},
}
},
methods: {
getPosts
},
mounted() {
getPosts.call(this, this._props.id)
},
props: {
id: {
type: String,
name: "id",
validator: val => {
const reg = /([0-9]|[a-f]){24}/
return reg.test(val)
},
}
}
}
</script>
<style scoped></style>

@ -1,68 +0,0 @@
<template>
<div id="posts" v-if="months.length >= 0">
<h3 class="month" v-for="(month, i) in months" :key="i">
{{ month }}
<div>
<ul>
<li v-for="(postItem, j) in getPostItems(month)" :key="j">
{{ getPostItemDate(postItem) }}
<a :href="/posts/ + postItem._id">{{ postItem.title }}</a>
</li>
</ul>
</div>
<br>
</h3>
</div>
<h2 v-else>There are no posts yet, but don't worry they will be added soon</h2>
</template>
<script>
import { getPosts } from '../remote'
export default {
name: "Posts",
computed: {
months: function () {
const dates = this.posts.map(post => new Date(post.date))
// Contains the month followed by the year
const months = dates.map(date => `${date.toLocaleString('default', { month: 'long' })} ${date.getFullYear()}`)
const uniques = Array.from(new Set(months))
return uniques
}
},
data() {
return {
posts: []
}
},
methods: {
getPosts,
getPostItems: function (month) {
const month_index = new Date(`1 ${month}`).getMonth()
return this.posts.filter((post) => (new Date(post.date)).getMonth() === month_index)
},
getPostItemDate: function (postItem) {
const date = new Date(postItem.date)
return `${date.getFullYear()} ${date.toLocaleString('default', { month: 'short' })} ${date.getDate()}`
}
},
mounted() {
getPosts.call(this)
},
}
</script>
<style scoped>
ul {
text-align: left;
}
@media (min-width: 420px) {
.month {
text-indent: 1em;
text-align: left;
}
}
</style>

@ -1,25 +0,0 @@
<template>
<div id="QAPage">
<QA
q="What is this site about? "
a="This site is about me and the stuff I make "
></QA>
<QA
q="Why is it still so empty?"
a="Because I am framework hopping "
></QA>
</div>
</template>
<script>
import QA from '@/components/QA'
export default {
name: "QAPAge",
components: { QA }
}
</script>
<style scoped></style>

@ -1,4 +0,0 @@
const assert = require('assert').strict
const me = require('../src/me')
assert(me.age() > 0, 'age should return a positive number')

@ -1,22 +0,0 @@
const { spawn } = require('child_process')
const fs = require('fs')
const dirs = ['./test', './tests']
if (!dirs.some(fs.existsSync)) {
throw Error("Could not find any test directories, looked for: " + dirs)
}
const test_dirs = dirs.filter(fs.existsSync)
test_dirs.forEach(test_dir => {
const files = fs.readdirSync(test_dir)
if (files.length === 0) {
throw Error("Could not find test files in " + test_dir)
}
const childs = files.map(file =>
spawn('node', [`${test_dir}/${file}`], { stdio: 'inherit' })
)
})
Loading…
Cancel
Save