Compare commits
27 Commits
Author | SHA1 | Date |
---|---|---|
Jef Roosens | c1a68ff66c | |
Renovate Bot | 902c8a3884 | |
Jef Roosens | 2bcfeaae83 | |
Jef Roosens | abe6a938de | |
Jef Roosens | 63d9810f42 | |
Jef Roosens | 40d491284e | |
Jef Roosens | a1b35747af | |
Jef Roosens | 83ba3764c6 | |
Jef Roosens | 1f52afdfe2 | |
Jef Roosens | 13d0d08183 | |
Jef Roosens | 633a9f43c6 | |
Jef Roosens | 0c13f0991a | |
Jef Roosens | 0400a85297 | |
Jef Roosens | 66a7cd8def | |
Renovate Bot | d41b7b9d37 | |
Renovate Bot | 8c7ea5dc4f | |
Renovate Bot | 435722ead9 | |
Renovate Bot | 17fa4e962b | |
Jef Roosens | 9f61d8d48e | |
Jef Roosens | acb115bb0c | |
Jef Roosens | 243dc9fe17 | |
Jef Roosens | 81266f427b | |
Jef Roosens | 93a8313efd | |
Jef Roosens | e57909b318 | |
Jef Roosens | a1efeaf6f1 | |
Jef Roosens | 8d04aaffb0 | |
Renovate Bot | 5e37af3091 |
|
@ -0,0 +1,2 @@
|
|||
node_modules/
|
||||
dist/
|
|
@ -0,0 +1,7 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = false
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,15 @@
|
|||
env:
|
||||
browser: true
|
||||
es2021: true
|
||||
vue/setup-compiler-macros: true
|
||||
extends:
|
||||
- 'plugin:vue/vue3-recommended'
|
||||
- standard
|
||||
parserOptions:
|
||||
ecmaVersion: 13
|
||||
parser: '@typescript-eslint/parser'
|
||||
sourceType: module
|
||||
plugins:
|
||||
- vue
|
||||
- '@typescript-eslint'
|
||||
rules: {}
|
|
@ -0,0 +1,5 @@
|
|||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
|
@ -0,0 +1,19 @@
|
|||
pipeline:
|
||||
install:
|
||||
image: 'node:17.3.0'
|
||||
commands:
|
||||
- yarn install
|
||||
|
||||
# This step makes sure the project properly builds.
|
||||
build:
|
||||
image: 'node:17.3.0'
|
||||
group: test
|
||||
commands:
|
||||
- yarn run build
|
||||
|
||||
lint:
|
||||
image: 'node:17.3.0'
|
||||
group: test
|
||||
commands:
|
||||
- yarn run lint
|
||||
|
27
Dockerfile
27
Dockerfile
|
@ -1,3 +1,26 @@
|
|||
FROM nginx:1.21.4-alpine
|
||||
# ======Building the project=====
|
||||
FROM node:17.3.0 AS builder
|
||||
|
||||
COPY default.conf.template /etc/nginx/templates/default.conf.template
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install Node dependencies
|
||||
COPY package.json yarn.lock ./
|
||||
RUN yarn install
|
||||
|
||||
# Copy over source code & build project
|
||||
COPY vite.config.ts tsconfig.json index.html ./
|
||||
COPY src/ ./src
|
||||
COPY public/ ./public
|
||||
RUN yarn run build
|
||||
|
||||
|
||||
# =====Packaging inside an Nginx container=====
|
||||
FROM nginx:1.21.5-alpine
|
||||
|
||||
# Copy over the Nginx config files
|
||||
COPY nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY nginx/*.conf.template /etc/nginx/templates/
|
||||
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy over build artifacts
|
||||
COPY --from=builder /usr/src/app/dist /usr/share/nginx/html
|
||||
|
|
12
README.md
12
README.md
|
@ -1,3 +1,11 @@
|
|||
# web
|
||||
# Vue 3 + Typescript + Vite
|
||||
|
||||
Frontend microservice for the Rusty Bever blogging software.
|
||||
This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
|
||||
|
||||
## Type Support For `.vue` Imports in TS
|
||||
|
||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's `.vue` type support plugin by running `Volar: Switch TS Plugin on/off` from VSCode command palette.
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,20 @@
|
|||
# vim: ft=nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
# =====FRONTEND HOSTING=====
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# vim: ft=nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
location /api/v1/posts/ {
|
||||
proxy_pass http://${RB_BLOG}/v1/posts/;
|
||||
}
|
||||
|
||||
location /api/v1/sections/ {
|
||||
proxy_pass http://${RB_BLOG}/v1/sections/;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
# vim: ft=nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
# =====MATRIX WELL-KNOWN FILES=====
|
||||
# Used for server federation
|
||||
location = /.well-known/matrix/server {
|
||||
charset utf-8;
|
||||
default_type application/json;
|
||||
|
||||
if ($request_method = 'GET') {
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
|
||||
add_header Access-Control-Allow-Headers 'X-Requested-With, Content-Type, Authorization';
|
||||
|
||||
return 200 '{"m.server":"${MATRIX_SERVER}"}';
|
||||
}
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
|
||||
add_header Access-Control-Allow-Headers 'X-Requested-With, Content-Type, Authorization';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
return 405;
|
||||
}
|
||||
|
||||
location = /.well-known/matrix/client {
|
||||
charset utf-8;
|
||||
default_type application/json;
|
||||
|
||||
if ($request_method = 'GET') {
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
|
||||
add_header Access-Control-Allow-Headers 'X-Requested-With, Content-Type, Authorization';
|
||||
|
||||
return 200 '{"m.homeserver":{"base_url":"${MATRIX_CLIENT_SERVER}"}}';
|
||||
}
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
|
||||
add_header Access-Control-Allow-Headers 'X-Requested-With, Content-Type, Authorization';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
return 405;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
gzip on;
|
||||
|
||||
# This order is important, as the Matrix matches should be evaluated first
|
||||
include /etc/nginx/conf.d/matrix.conf;
|
||||
include /etc/nginx/conf.d/gateway.conf;
|
||||
include /etc/nginx/conf.d/default.conf;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "rb-web",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
"image": "docker build -t chewingbever/rb-blog .",
|
||||
"lint": "eslint --ext .js,.vue,.ts src",
|
||||
"format": "yarn run lint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.2.25"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||
"@typescript-eslint/parser": "^5.8.1",
|
||||
"@vitejs/plugin-vue": "^2.0.0",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"eslint-plugin-vue": "^8.2.0",
|
||||
"miragejs": "^0.1.43",
|
||||
"null-loader": "^4.0.1",
|
||||
"typescript": "^4.4.4",
|
||||
"vite": "^2.7.2",
|
||||
"vue-tsc": "^0.30.0"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<script setup lang="ts">
|
||||
// This starter template is using Vue 3 <script setup> SFCs
|
||||
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
|
||||
import SectionsList from './components/SectionsList.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<img
|
||||
alt="Vue logo"
|
||||
src="./assets/logo.png"
|
||||
>
|
||||
<SectionsList />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,15 @@
|
|||
const API_PREFIX = '/api/v1'
|
||||
|
||||
export class RbApi {
|
||||
async get_json (path) {
|
||||
const url = `${API_PREFIX}${path}`
|
||||
const res = await fetch(url)
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
async sections () {
|
||||
const res = await this.get_json('/sections')
|
||||
|
||||
return res.sections
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1,71 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps<{ msg: string }>()
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
fetch('/api/v1/sections').then(res => res.json()).then(res => console.log(res))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
|
||||
<p>
|
||||
Recommended IDE setup:
|
||||
<a
|
||||
href="https://code.visualstudio.com/"
|
||||
target="_blank"
|
||||
>VSCode</a>
|
||||
+
|
||||
<a
|
||||
href="https://github.com/johnsoncodehk/volar"
|
||||
target="_blank"
|
||||
>Volar</a>
|
||||
</p>
|
||||
|
||||
<p>See <code>README.md</code> for more information.</p>
|
||||
|
||||
<p>
|
||||
<a
|
||||
href="https://vitejs.dev/guide/features.html"
|
||||
target="_blank"
|
||||
>
|
||||
Vite Docs
|
||||
</a>
|
||||
|
|
||||
<a
|
||||
href="https://v3.vuejs.org/"
|
||||
target="_blank"
|
||||
>Vue 3 Docs</a>
|
||||
</p>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@click="count++"
|
||||
>
|
||||
count is: {{ count }}
|
||||
</button>
|
||||
<p>
|
||||
Edit
|
||||
<code>components/HelloWorld.vue</code> to test hot module replacement.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
|
||||
label {
|
||||
margin: 0 0.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #eee;
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
color: #304455;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { RbApi } from '../api/v1'
|
||||
import { Section } from '../models'
|
||||
|
||||
const sections = ref([])
|
||||
|
||||
const api = new RbApi()
|
||||
await api.sections().then(res => {
|
||||
sections.value = res
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p>yeet</p>
|
||||
<ul>
|
||||
<li v-for="section in sections">
|
||||
{{ section }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,8 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
// @ts-ignore
|
||||
import { makeServer } from './mirage/v1'
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
makeServer()
|
||||
}
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,52 @@
|
|||
export const sections = [
|
||||
{
|
||||
id: '837ba6a5-47ed-4682-bff5-90bc5c5f9646',
|
||||
title: 'Section One',
|
||||
shortname: 'one',
|
||||
description: 'The first section.',
|
||||
is_default: true,
|
||||
has_titles: true,
|
||||
is_private: false,
|
||||
is_archived: false
|
||||
},
|
||||
{
|
||||
id: '5e661b3f-61e6-4aed-a93b-8cae0896f656',
|
||||
title: 'Section Two',
|
||||
shortname: 'two',
|
||||
description: 'The second section.',
|
||||
is_default: true,
|
||||
has_titles: false,
|
||||
is_private: false,
|
||||
is_archived: false
|
||||
},
|
||||
{
|
||||
id: '5fcbeaca-1496-438e-ace2-18e99e11f384',
|
||||
title: 'Section Three',
|
||||
shortname: 'three',
|
||||
description: 'The third section.',
|
||||
is_default: false,
|
||||
has_titles: true,
|
||||
is_private: false,
|
||||
is_archived: false
|
||||
}
|
||||
]
|
||||
|
||||
export const posts = [
|
||||
{
|
||||
id: 'af08bbcd-f6eb-446e-b355-13e0a0ef008e',
|
||||
section_id: sections[0].id,
|
||||
is_private: false,
|
||||
is_archived: false
|
||||
}
|
||||
]
|
||||
|
||||
export const versions = [
|
||||
{
|
||||
id: '8c5bc2f9-e52f-4e19-bd76-119cc42ff863',
|
||||
post_id: posts[0].id,
|
||||
title: 'This Is A Title',
|
||||
publish_date: '2021-12-28',
|
||||
content: 'Hello. This is some content!',
|
||||
is_draft: false
|
||||
}
|
||||
]
|
|
@ -0,0 +1,37 @@
|
|||
import { createServer, Model } from 'miragejs'
|
||||
import { sections, posts, versions } from './models'
|
||||
|
||||
export function makeServer ({ environment = 'development' } = {}) {
|
||||
const server = createServer({
|
||||
environment,
|
||||
|
||||
models: {
|
||||
section: Model,
|
||||
Post: Model,
|
||||
version: Model
|
||||
},
|
||||
|
||||
seeds (server) {
|
||||
sections.forEach(s => server.create('section', s))
|
||||
posts.forEach(s => server.create('post', s))
|
||||
versions.forEach(s => server.create('version', s))
|
||||
},
|
||||
|
||||
routes () {
|
||||
this.namespace = 'api/v1'
|
||||
|
||||
// Offsets & limits don't need to be implemented here, as the data set isn't large enough to require this yet
|
||||
this.get('/sections', (schema) => {
|
||||
return schema.sections.all()
|
||||
})
|
||||
this.get('/posts', (schema) => {
|
||||
return schema.posts.all()
|
||||
})
|
||||
this.get('/versions', (schema) => {
|
||||
return schema.versions.all()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return server
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
export interface Section {
|
||||
id: str,
|
||||
shortname: str,
|
||||
description: str,
|
||||
is_default: bool,
|
||||
has_titles: bool,
|
||||
is_private: bool,
|
||||
is_archived: bool
|
||||
}
|
||||
|
||||
export interface Post {
|
||||
id: str,
|
||||
section_id: str,
|
||||
is_private: bool,
|
||||
is_archived: bool
|
||||
}
|
||||
|
||||
export interface Version {
|
||||
id: str,
|
||||
post_id: str,
|
||||
title: str,
|
||||
publish_date: Date,
|
||||
content: str,
|
||||
is_draft: bool
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// src/server.js
|
||||
import { createServer, Model } from 'miragejs'
|
||||
|
||||
export function makeServer ({ environment = 'development' } = {}) {
|
||||
const server = createServer({
|
||||
environment,
|
||||
|
||||
models: {
|
||||
user: Model
|
||||
},
|
||||
|
||||
seeds (server) {
|
||||
server.create('user', { name: 'Bob' })
|
||||
server.create('user', { name: 'Alice' })
|
||||
},
|
||||
|
||||
routes () {
|
||||
this.namespace = 'api'
|
||||
|
||||
this.get('/users', (schema) => {
|
||||
return schema.users.all()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return server
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["esnext", "dom"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()]
|
||||
})
|
|
@ -0,0 +1,14 @@
|
|||
module.exports = {
|
||||
chainWebpack: (config) => {
|
||||
if (
|
||||
process.env.NODE_ENV === "production" &&
|
||||
process.env.MIRAGE_ENABLED !== "true"
|
||||
) {
|
||||
config.module
|
||||
.rule("exclude-mirage")
|
||||
.test(/node_modules\/miragejs\//)
|
||||
.use("null-loader")
|
||||
.loader("null-loader")
|
||||
}
|
||||
},
|
||||
}
|
Loading…
Reference in New Issue