From 9ce11fe589d32fe64d39bdd9f71e2671764213f9 Mon Sep 17 00:00:00 2001 From: Dietrich Rink Date: Sun, 30 Apr 2023 19:10:59 +0200 Subject: [PATCH] Initial commit --- .gitignore | 33 +++++++++++++++ README.md | 9 ++++ package.json | 14 +++++++ src/components/App.vue | 29 +++++++++++++ src/components/Content.vue | 33 +++++++++++++++ src/components/Footer.vue | 15 +++++++ src/components/Header.vue | 26 ++++++++++++ src/components/Navigation.vue | 32 ++++++++++++++ src/components/routes/About.vue | 14 +++++++ src/components/routes/Counter.vue | 40 ++++++++++++++++++ src/components/routes/Imprint.vue | 65 +++++++++++++++++++++++++++++ src/components/routes/Index.vue | 11 +++++ src/components/routes/Joke.vue | 43 +++++++++++++++++++ src/components/routes/NotFound.vue | 11 +++++ src/components/routes/routes.ts | 29 +++++++++++++ src/components/widgets/ErrorBox.vue | 11 +++++ src/components/widgets/Spinner.vue | 38 +++++++++++++++++ src/composables/jokeAPI.ts | 63 ++++++++++++++++++++++++++++ src/img/logo.svg | 2 + src/index.pug | 10 +++++ src/index.sass | 16 +++++++ src/index.ts | 18 ++++++++ 22 files changed, 562 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 package.json create mode 100644 src/components/App.vue create mode 100644 src/components/Content.vue create mode 100644 src/components/Footer.vue create mode 100644 src/components/Header.vue create mode 100644 src/components/Navigation.vue create mode 100644 src/components/routes/About.vue create mode 100644 src/components/routes/Counter.vue create mode 100644 src/components/routes/Imprint.vue create mode 100644 src/components/routes/Index.vue create mode 100644 src/components/routes/Joke.vue create mode 100644 src/components/routes/NotFound.vue create mode 100644 src/components/routes/routes.ts create mode 100644 src/components/widgets/ErrorBox.vue create mode 100644 src/components/widgets/Spinner.vue create mode 100644 src/composables/jokeAPI.ts create mode 100644 src/img/logo.svg create mode 100644 src/index.pug create mode 100644 src/index.sass create mode 100644 src/index.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb0354f --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Parcel cache +.parcel-cache + +# Node packages and builds +node_modules +dist +yarn.lock +yarn-error.log + +# User-specific files +*.user + +# Editor files +[._]*.sw[a-p] +.vscode +.vs/ + +# Temporary and system files +*~ +.fuse_hidden* +.directory +.nfs* +.DS_Store +.AppleDouble +.LSOverride +Icon +._* +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +*.stackdump +[Dd]esktop.ini diff --git a/README.md b/README.md new file mode 100644 index 0000000..45faece --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Example Vue Application + +This is an example single page application built in Vue.js. + +It uses nested components, routing, composables and the fancy language +extensions pug, typescript and sass, that compile to html, javascript and css. + +To make developing and building the project a breeze, the zero configuration +build tool parcel is used. diff --git a/package.json b/package.json new file mode 100644 index 0000000..8c66f31 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "vue-example-app", + "version": "0.0.1", + "license": "MIT", + "source": "src/index.pug", + "devDependencies": { + "@parcel/transformer-pug": "2.8.3", + "@parcel/transformer-sass": "2.8.3", + "@parcel/transformer-vue": "2.8.3", + "parcel": "^2.8.3", + "vue": "^3.2.47", + "vue-router": "^4.1.6" + } +} diff --git a/src/components/App.vue b/src/components/App.vue new file mode 100644 index 0000000..6dd8943 --- /dev/null +++ b/src/components/App.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/components/Content.vue b/src/components/Content.vue new file mode 100644 index 0000000..0d7ac26 --- /dev/null +++ b/src/components/Content.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/Footer.vue b/src/components/Footer.vue new file mode 100644 index 0000000..d962680 --- /dev/null +++ b/src/components/Footer.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/components/Header.vue b/src/components/Header.vue new file mode 100644 index 0000000..cd61e8b --- /dev/null +++ b/src/components/Header.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/Navigation.vue b/src/components/Navigation.vue new file mode 100644 index 0000000..19d5008 --- /dev/null +++ b/src/components/Navigation.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/components/routes/About.vue b/src/components/routes/About.vue new file mode 100644 index 0000000..73a4366 --- /dev/null +++ b/src/components/routes/About.vue @@ -0,0 +1,14 @@ + diff --git a/src/components/routes/Counter.vue b/src/components/routes/Counter.vue new file mode 100644 index 0000000..0a9c704 --- /dev/null +++ b/src/components/routes/Counter.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/components/routes/Imprint.vue b/src/components/routes/Imprint.vue new file mode 100644 index 0000000..1ec0b8c --- /dev/null +++ b/src/components/routes/Imprint.vue @@ -0,0 +1,65 @@ + diff --git a/src/components/routes/Index.vue b/src/components/routes/Index.vue new file mode 100644 index 0000000..5fe4196 --- /dev/null +++ b/src/components/routes/Index.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/routes/Joke.vue b/src/components/routes/Joke.vue new file mode 100644 index 0000000..e41382e --- /dev/null +++ b/src/components/routes/Joke.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/components/routes/NotFound.vue b/src/components/routes/NotFound.vue new file mode 100644 index 0000000..8f86246 --- /dev/null +++ b/src/components/routes/NotFound.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/routes/routes.ts b/src/components/routes/routes.ts new file mode 100644 index 0000000..9fbcd02 --- /dev/null +++ b/src/components/routes/routes.ts @@ -0,0 +1,29 @@ +import Index from './Index.vue' +import Counter from './Counter.vue' +import Joke from './Joke.vue' +import About from './About.vue' +import Imprint from './Imprint.vue' + +import NotFound from './NotFound.vue' + +export default [ + { + path: "/", component: Index, + meta: { nav: false, title: "Welcome to my Vue example" }, + }, { + path: "/counter", component: Counter, + meta: { nav: "Counter", title: "Vue counter" }, + }, { + path: "/joke", component: Joke, + meta: { nav: "Joke", title: "Vue joke API consumer" }, + }, { + path: "/about", component: About, + meta: { nav: "About", title: "About this lorem ipsum" }, + }, { + path: "/imprint", component: Imprint, + meta: { nav: false, title: "Vue example imprint" }, + }, { + path: "/:path(.*)", component: NotFound, + meta: { nav: false, title: "Vue example page not found" }, + }, +] diff --git a/src/components/widgets/ErrorBox.vue b/src/components/widgets/ErrorBox.vue new file mode 100644 index 0000000..6631cd2 --- /dev/null +++ b/src/components/widgets/ErrorBox.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/widgets/Spinner.vue b/src/components/widgets/Spinner.vue new file mode 100644 index 0000000..b9f1221 --- /dev/null +++ b/src/components/widgets/Spinner.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/src/composables/jokeAPI.ts b/src/composables/jokeAPI.ts new file mode 100644 index 0000000..18b73c6 --- /dev/null +++ b/src/composables/jokeAPI.ts @@ -0,0 +1,63 @@ +import { reactive } from 'vue' + +const DEFAULT_BASE = 'https://official-joke-api.appspot.com' +const DEFAULT_URL = `${DEFAULT_BASE}/jokes/programming/random` +const DEFAULT_CHAR_DELAY = 20 +const DEFAULT_PUNCHLINE_DELAY = 2000 + +export class Joke { + error : string | null = null + setup : string | null = null + punchline : string = "" + + reset() { + this.error = null + this.setup = null + this.punchline = "" + } +} + +export function useJokeAPI( + url: string = DEFAULT_URL, + charDelay: int = DEFAULT_CHAR_DELAY, + punchlineDelay: int = DEFAULT_PUNCHLINE_DELAY +) { + let joke = reactive(new Joke()) + + let working = false + async function loadJoke(): bool { + if (working) return false + working = true + + // Load joke + joke.reset() + try { + let res = await fetch(url) + var [{ setup, punchline }] = await res.json() + } catch (e) { + console.error(e) + } + + // Animate joke appearance + if (setup && punchline) { + for (let i = 0; i <= setup.length; i++) { + joke.setup = setup.substr(0, i) + await sleep(charDelay) + } + await sleep(punchlineDelay) + for (let i = 0; i <= punchline.length; i++) { + joke.punchline = punchline.substr(0, i) + await sleep(charDelay) + } + } else { + joke.error = "Loading joke failed" + } + working = false + } + + return { joke, loadJoke } +} + +async function sleep(ms: number) { + await new Promise((res, rej) => setTimeout(res, ms)) +} diff --git a/src/img/logo.svg b/src/img/logo.svg new file mode 100644 index 0000000..cb39865 --- /dev/null +++ b/src/img/logo.svg @@ -0,0 +1,2 @@ + + diff --git a/src/index.pug b/src/index.pug new file mode 100644 index 0000000..a3a4637 --- /dev/null +++ b/src/index.pug @@ -0,0 +1,10 @@ +doctype html + +html(lang="en") + head + meta(charset="utf-8") + title Hello Seb + link(rel="stylesheet" href="index.sass") + body + #app + script(src="index.ts" type="module") diff --git a/src/index.sass b/src/index.sass new file mode 100644 index 0000000..9682549 --- /dev/null +++ b/src/index.sass @@ -0,0 +1,16 @@ +html, body + margin: 0 + min-height: 100% + font-family: sans-serif + color: white + +* + box-sizing: border-box + +h1, h2, h3, h4, h5 + font-weight: normal + text-align: center + +a + text-decoration: none + color: inherit diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..9293cc8 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,18 @@ +import { createApp } from 'vue' +import { createRouter, createWebHistory } from 'vue-router' + +import App from './components/App.vue' + +import routes from './components/routes/routes.ts' +const history = createWebHistory() +const router = createRouter({ history, routes }) +router.afterEach((to, from) => { document.title = to.meta.title }) + +import ErrorBox from './components/widgets/ErrorBox.vue' +import Spinner from './components/widgets/Spinner.vue' + +const app = createApp(App) +app.use(router) +app.component('ErrorBox', ErrorBox) +app.component('Spinner', Spinner) +app.mount("#app")