Messy transition to Vue

This commit is contained in:
Ryan Pandya 2023-05-02 18:41:31 -07:00
parent aed2080b53
commit b0c3eaf33d
35 changed files with 4894 additions and 22 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/env /env
/node_modules

View File

@ -1,4 +1,5 @@
from flask import Flask from flask import Flask, jsonify
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
import os import os
@ -7,6 +8,9 @@ persistent_path = os.getenv(
app = Flask(__name__) app = Flask(__name__)
# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})
db_path = os.path.join(persistent_path, "sqlite.db") db_path = os.path.join(persistent_path, "sqlite.db")
app.config["SQLALCHEMY_DATABASE_URI"] = f'sqlite:///{db_path}' app.config["SQLALCHEMY_DATABASE_URI"] = f'sqlite:///{db_path}'

View File

@ -6,6 +6,7 @@
integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<!-- HTMX --> <!-- HTMX -->
<script src="https://unpkg.com/htmx.org@1.5.0"></script> <script src="https://unpkg.com/htmx.org@1.5.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js"></script> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.css" />
<link rel="stylesheet" href="/colors.css"/> <link rel="stylesheet" href="/colors.css"/>

View File

@ -1,26 +1,8 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% block content %} {% block content %}
<div id="app">
{{ message }}
</div>
<div id="container"></div>
<script language="javascript">
const container = document.querySelector('#container');
const data = [
{ id: 1, name: 'Ted Right', address: '' },
{ id: 2, name: 'Frank Honest', address: '' },
{ id: 3, name: 'Joan Well', address: '' },
{ id: 4, name: 'Gail Polite', address: '' },
{ id: 5, name: 'Michael Fair', address: '' },
];
const hot = new Handsontable(container, {
data,
colHeaders: false,
height: 'auto',
width: 'auto',
minSpareRows: 1,
licenseKey: 'non-commercial-and-evaluation'
});
</script>
{% endblock %} {% endblock %}

28
lifetracker-vue/.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}

40
lifetracker-vue/README.md Normal file
View File

@ -0,0 +1,40 @@
# lifetracker-vue
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```

1
lifetracker-vue/env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -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>Life Tracker Expanded</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

4199
lifetracker-vue/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
{
"name": "lifetracker-vue",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "run-p type-check build-only",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit"
},
"dependencies": {
"@handsontable/vue3": "^12.3.3",
"appwrite": "^11.0.0",
"handsontable": "^12.3.3",
"pinia": "^2.0.35",
"vue": "^3.2.47",
"vue-router": "^4.1.6"
},
"devDependencies": {
"@types/node": "^18.14.2",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/tsconfig": "^0.1.3",
"npm-run-all": "^4.1.5",
"typescript": "~4.8.4",
"vite": "^4.1.4",
"vue-tsc": "^1.2.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,28 @@
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import AuthNav from './components/AuthNav.vue'
</script>
<template>
<header>
<div class="title">
<h1>
<RouterLink to="/">
{{ year }} Tracker Expanded
</RouterLink>
</h1>
</div>
<nav>
<RouterLink to="/table">Table</RouterLink>
<RouterLink to="/database">Database Info</RouterLink>
</nav>
<AuthNav />
</header>
<RouterView />
</template>
<style scoped>
</style>

View File

@ -0,0 +1,101 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
--black: #273036;
--red: #c71634;
--cyan: #005744;
--pink: #ff65ae;
--blue: #00a9b3;
--green: #189749;
--yellow: #fff336;
--orange: #ff6d01;
--purple: #5b3ab1;
--darkred: #ff2816;
--lime: #bfff55;
}
/* semantic color variables for this project */
:root {
--color-background: var(--black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
--section-gap: 160px;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
position: relative;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition: color 0.5s, background-color 0.5s;
line-height: 1.6;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
header{
display: flex;
gap: 2em;
align-items: center;
/* border-bottom: 1px solid var(--vt-c-white-mute); */
}
h1{
color: var(--vt-c-text-dark-1);
}
nav{
display:flex;
gap: 1em;
}
a{
color: var(--color-text);
text-decoration: none;
}
a.router-link-active{
font-weight: bold;
border-bottom: 1px solid var(--color-text);
}
a:hover{
color: white;
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

After

Width:  |  Height:  |  Size: 276 B

View File

@ -0,0 +1,7 @@
@import './base.css';
#app {
padding: 1em 2rem;
font-weight: normal;
}

View File

@ -0,0 +1,8 @@
<script>
</script>
<template>
<div v-if="year == 2023">
You are not logged in.
</div>
</template>

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
defineProps<{
msg: string
}>()
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
</h3>
</div>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,13 @@
<script setup lang="ts">
defineProps<{
year: string
}>()
</script>
<template>
<h1 class="green">{{ year }} Tracker Expanded</h1>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,86 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>

View File

@ -0,0 +1,15 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import './assets/main.css'
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
app.mount('#app')

View File

@ -0,0 +1,26 @@
import { createRouter, createWebHistory } from 'vue-router'
import TableView from '../views/TableView.vue'
import DatabaseView from '../views/DatabaseView.vue'
import AboutView from '../views/AboutView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/table'
},
{
path: '/table',
name: 'table',
component: TableView
},
{
path: '/database',
name: 'database',
component: DatabaseView
}
]
})
export default router

View File

@ -0,0 +1,15 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>

View File

@ -0,0 +1,102 @@
<script>
// Try to connect
import { Client, Account, ID } from 'appwrite';
const appwriteclient = new Client()
.setEndpoint('http://ryanpandya.com:8080/v1') // Your API Endpoint
.setProject('lifetracker'); // Your project ID
const account = new Account(appwriteclient);
var email; var userId; var password; var session;
export default {
mounted(){
const promise = account.getSession('current');
var self = this;
promise.then(function (response) {
self.email = response.providerUid;
self.userId = response.userId;
self.session = response.$id;
}, function (error) {
self.email = null;
self.userId = null;
self.password = null;
self.session = false;
});
},
data(){
return {
userId: userId,
email: email,
password: password,
error: null,
session: session,
account: account
}
},
methods: {
connect() {
const promise = this.account.createEmailSession(this.email, this.password);
var self = this;
promise.then(function (response) {
self.session = response;
self.userId = response.userId;
self.error = false;
}, function (error) {
self.session = false;
self.error = error;
});
},
logout() {
const promise = this.account.deleteSession(this.session);
var self = this;
promise.then(function (response) {
self.userId = null; self.email = null; self.session = false;
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
}
}
}
</script>
<template>
<div v-if="session == null">
Loading...
</div>
<div v-if="session==false" id="form">
<h2>Not connected yet.</h2>
<div id="login">
<input name="email" type="text" v-model="email" placeholder="email" />
<input name="password" type="password" v-model="password" placeholder="password"/>
<button @click="connect">Connect to database</button>
<h3 class="error" v-if="error">{{ error }}</h3>
</div>
</div>
<div v-if="session">
<h2>Welcome back, {{ userId }}!</h2>
<div class="flex">
<button @click="logout">Log Out</button>
</div>
</div>
</template>
<style>
div#form{
display:flex;
flex-direction: column;
gap: 1em;
width: 200px;
}
h3.error{
color: var(--darkred);
}
div#login{
display: flex;
flex-direction: column;
}
</style>

View File

@ -0,0 +1,9 @@
<script setup lang="ts">
import TheWelcome from '../components/TheWelcome.vue'
</script>
<template>
<main>
<TheWelcome />
</main>
</template>

View File

@ -0,0 +1,49 @@
<template>
<hot-table :settings="hotSettings" :data="data"></hot-table>
</template>
<script scoped>
import { Client, Account, ID } from 'appwrite';
import { defineComponent } from 'vue';
import { HotTable } from '@handsontable/vue3';
import { registerAllModules } from 'handsontable/registry';
import 'handsontable/dist/handsontable.full.css';
// register Handsontable's modules
registerAllModules();
const appwriteclient = new Client();
appwriteclient
.setEndpoint('http://ryanpandya.com:8080/v1')
.setProject('lifetracker');
const ExampleComponent = defineComponent({
data() {
return {
hotSettings: {
data: [
['DATE', 'DAY',
'12 AM', '1 AM', '2 AM', '3 AM', '4 AM', '5 AM', '6 AM', '7 AM', '8 AM', '9 AM', '10 AM', '11 AM',
'12 PM', '1 PM', '2 PM', '3 PM', '4 PM', '5 PM', '6 PM', '7 PM', '8 PM', '9 PM', '10 PM', '11 PM',
'Mood', 'Notes'
],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6', 'J6'],
],
colHeaders: false,
height: 'auto',
licenseKey: 'non-commercial-and-evaluation'
}
};
},
components: {
HotTable,
}
});
export default ExampleComponent;
</script>

View File

@ -0,0 +1,17 @@
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"noImplicitAny": false
},
"references": [
{
"path": "./tsconfig.node.json"
}
]
}

View File

@ -0,0 +1,8 @@
{
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
"compilerOptions": {
"composite": true,
"types": ["node"]
}
}

View File

@ -0,0 +1,14 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})

47
package-lock.json generated Normal file
View File

@ -0,0 +1,47 @@
{
"name": "ltx",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"node": "^20.0.0"
}
},
"node_modules/node": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/node/-/node-20.0.0.tgz",
"integrity": "sha512-4R1vw5hKUjQw3x65x9g/ape/XlY/ZFHaQWB+jQLFJIJkVKJPDSY4oj3O6qgXOvv2wwgEpK9J2SvJUjuL6zu0uA==",
"hasInstallScript": true,
"dependencies": {
"node-bin-setup": "^1.0.0"
},
"bin": {
"node": "bin/node"
},
"engines": {
"npm": ">=5.0.0"
}
},
"node_modules/node-bin-setup": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.3.tgz",
"integrity": "sha512-opgw9iSCAzT2+6wJOETCpeRYAQxSopqQ2z+N6BXwIMsQQ7Zj5M8MaafQY8JMlolRR6R1UXg2WmhKp0p9lSOivg=="
}
},
"dependencies": {
"node": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/node/-/node-20.0.0.tgz",
"integrity": "sha512-4R1vw5hKUjQw3x65x9g/ape/XlY/ZFHaQWB+jQLFJIJkVKJPDSY4oj3O6qgXOvv2wwgEpK9J2SvJUjuL6zu0uA==",
"requires": {
"node-bin-setup": "^1.0.0"
}
},
"node-bin-setup": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.3.tgz",
"integrity": "sha512-opgw9iSCAzT2+6wJOETCpeRYAQxSopqQ2z+N6BXwIMsQQ7Zj5M8MaafQY8JMlolRR6R1UXg2WmhKp0p9lSOivg=="
}
}
}

5
package.json Normal file
View File

@ -0,0 +1,5 @@
{
"dependencies": {
"node": "^20.0.0"
}
}