From 0d0b4a945a2210204d2def2cff3d2e2b9b4c45cd Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Mon, 25 Feb 2019 00:24:51 -0600 Subject: [PATCH] WIP on web UI: added nav, routing, basic page skeletons. --- api/personal_measure_api.config.json | 4 +- .../main/nim/personal_measure_apipkg/api.nim | 3 +- .../nim/personal_measure_apipkg/db_common.nim | 2 +- web/.sass-lint.yml | 5 ++ web/package-lock.json | 61 +++++++++++-------- web/package.json | 3 + web/src/App.vue | 5 +- web/src/app.scss | 43 ++++++++----- web/src/main.ts | 3 + web/src/router.ts | 26 +++++--- web/src/styles/reset.scss | 5 ++ web/src/styles/vars.scss | 53 ++++++++++++++++ web/src/views/About.vue | 5 -- web/src/views/Dashboard.vue | 6 ++ web/src/views/Home.vue | 6 -- web/src/views/Measures.vue | 6 ++ web/src/views/NavBar.vue | 25 +++++++- web/src/views/UserAccount.vue | 6 ++ web/src/views/{home.ts => dashboard.ts} | 0 web/src/views/dashobard.ts | 4 ++ web/src/views/measures.ts | 6 ++ web/src/views/nav-bar.scss | 49 +++++++++++++++ web/src/views/nav-bar.ts | 22 ++++++- web/src/views/user-account.ts | 4 ++ 24 files changed, 279 insertions(+), 73 deletions(-) create mode 100644 web/.sass-lint.yml create mode 100644 web/src/styles/reset.scss create mode 100644 web/src/styles/vars.scss delete mode 100644 web/src/views/About.vue create mode 100644 web/src/views/Dashboard.vue delete mode 100644 web/src/views/Home.vue create mode 100644 web/src/views/Measures.vue create mode 100644 web/src/views/UserAccount.vue rename web/src/views/{home.ts => dashboard.ts} (100%) create mode 100644 web/src/views/dashobard.ts create mode 100644 web/src/views/measures.ts create mode 100644 web/src/views/user-account.ts diff --git a/api/personal_measure_api.config.json b/api/personal_measure_api.config.json index 4e35e34..532bb41 100644 --- a/api/personal_measure_api.config.json +++ b/api/personal_measure_api.config.json @@ -1,7 +1,7 @@ { - "authSecret":"change me", + "authSecret":"bifekHuffIs3", "dbConnString":"host=localhost port=5500 dbname=personal_measure user=postgres password=password", "debug":true, - "port":8080, + "port":8081, "pwdCost":11 } diff --git a/api/src/main/nim/personal_measure_apipkg/api.nim b/api/src/main/nim/personal_measure_apipkg/api.nim index 2ed0ed0..8489639 100644 --- a/api/src/main/nim/personal_measure_apipkg/api.nim +++ b/api/src/main/nim/personal_measure_apipkg/api.nim @@ -293,7 +293,7 @@ proc start*(ctx: PMApiContext): void = try: if not ctx.db.deleteUser(user): raiseEx "unable to delete user" - makeJsonResp(Http200, "user " & user.email & " deleted") + jsonResp(Http200, "user " & user.email & " deleted") except: jsonResp(Http500, getCurrentExceptionMsg()) @@ -518,4 +518,3 @@ proc start*(ctx: PMApiContext): void = resp($(%"shutting down"), JSON) waitFor(stopFuture) - diff --git a/api/src/main/nim/personal_measure_apipkg/db_common.nim b/api/src/main/nim/personal_measure_apipkg/db_common.nim index 8503b8a..3854974 100644 --- a/api/src/main/nim/personal_measure_apipkg/db_common.nim +++ b/api/src/main/nim/personal_measure_apipkg/db_common.nim @@ -83,7 +83,7 @@ macro generateProcsForModels*(modelTypes: openarray[type]): untyped = for t in modelTypes: let modelName = $(t.getType[1]) let getName = ident("get" & modelName) - let getAllName = ident("getAll" & modelName) + let getAllName = ident("getAll" & modelName & "s") let findWhereName = ident("find" & modelName & "sWhere") let createName = ident("create" & modelName) let updateName = ident("update" & modelName) diff --git a/web/.sass-lint.yml b/web/.sass-lint.yml new file mode 100644 index 0000000..ae204f4 --- /dev/null +++ b/web/.sass-lint.yml @@ -0,0 +1,5 @@ +rules: + no-ids: 0 + no-url-protocols: 0 + no-url-domains: 0 + no-css-comments: 0 diff --git a/web/package-lock.json b/web/package-lock.json index cc2fcb9..d4537e8 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -816,6 +816,32 @@ "to-fast-properties": "^2.0.0" } }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.15.tgz", + "integrity": "sha512-ATBRyKJw1d2ko+0DWN9+BXau0EK3I/Q6pPzPv3LhJD7r052YFAkAdfb1Bd7ZqhBsJrdse/S7jKxWUOZ61qBD4g==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.15.tgz", + "integrity": "sha512-M/sHyl4g2VBtKYkay1Z+XImMyTVcaBPmehYtPw4HKD9zg2E7eovB7Yx98aUfZjPbroGqa+IL4/+KhWBMOGlHIQ==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.15" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.7.2.tgz", + "integrity": "sha512-iujcXMyAvIbWM8W3jkOLpvJbR+rPpdN1QyqhZeJaLRdHPH4JmuovIAYP4vx5Sa1csZVXfRD1eDWqVZ/jGM620A==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.15" + } + }, + "@fortawesome/vue-fontawesome": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-0.1.5.tgz", + "integrity": "sha512-tiNZCgh+ZkUsyFfm2MQMMdHKRrKj82M7g0XFPSNNY+s5nRB82soy0US+xj0jGRy433b0c4WpylCOhgle3294Uw==" + }, "@iamstarkov/listr-update-renderer": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@iamstarkov/listr-update-renderer/-/listr-update-renderer-0.4.1.tgz", @@ -6834,8 +6860,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -6863,7 +6888,6 @@ "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6878,8 +6902,7 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", @@ -6890,8 +6913,7 @@ "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -7008,8 +7030,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -7021,7 +7042,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7036,7 +7056,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7044,14 +7063,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -7070,7 +7087,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -7151,8 +7167,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -7164,7 +7179,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -7250,8 +7264,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -7287,7 +7300,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7307,7 +7319,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7351,14 +7362,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, diff --git a/web/package.json b/web/package.json index c428481..122e297 100644 --- a/web/package.json +++ b/web/package.json @@ -9,6 +9,9 @@ "test:unit": "vue-cli-service test:unit" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.15", + "@fortawesome/free-solid-svg-icons": "^5.7.2", + "@fortawesome/vue-fontawesome": "^0.1.5", "@types/lodash.merge": "^4.6.5", "axios": "^0.18.0", "keen-ui": "^1.1.2", diff --git a/web/src/App.vue b/web/src/App.vue index 22f2f4b..f36ee9f 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -1,9 +1,6 @@ diff --git a/web/src/app.scss b/web/src/app.scss index 465df78..c242729 100644 --- a/web/src/app.scss +++ b/web/src/app.scss @@ -1,18 +1,29 @@ -#app { - font-family: 'Avenir', Helvetica, Arial, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-align: center; - color: #2c3e50; -} -#nav { - padding: 30px; - a { - font-weight: bold; - color: #2c3e50; - &.router-link-exact-active { - color: #42b983; - } - } +@import '~@/styles/vars'; +@import '~@/styles/reset'; +@import url('https://fonts.googleapis.com/css?family=Dosis|Exo+2:600|Exo:700|Josefin+Sans:300|Montserrat:300|Raleway|Teko:500|Titillium+Web:200'); + +body { + background-color: $bg-primary; + color: $fg-primary; } +h1, h2, h3 { font-family: 'Exo 2'; } + +h1 { font-size: 2rem; } +h2 { font-size: 1.6rem; } +h3 { font-size: 1.3rem; } + +#app { + border: 0; + display: flex; + align-items: stretch; + font-family: 'Lato', 'Avenir', Helvetica, Arial, sans-serif; + margin: 0; + + min-height: 100vh; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + & > * { padding: 1rem 2rem; } +} diff --git a/web/src/main.ts b/web/src/main.ts index 32df3d3..efa5004 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -3,6 +3,9 @@ import App from './App.vue'; import router from './router'; import store from './store'; import './registerServiceWorker'; +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; + +Vue.component('fa-icon', FontAwesomeIcon); Vue.config.productionTip = false; diff --git a/web/src/router.ts b/web/src/router.ts index f008a3f..2a66df4 100644 --- a/web/src/router.ts +++ b/web/src/router.ts @@ -1,6 +1,8 @@ import Vue from 'vue'; import Router from 'vue-router'; -import Home from './views/Home.vue'; +import Dashboard from './views/Dashboard.vue'; +import Measures from './views/Measures.vue'; +import UserAccount from './views/UserAccount.vue'; Vue.use(Router); @@ -10,16 +12,22 @@ export default new Router({ routes: [ { path: '/', - name: 'home', - component: Home + redirect: '/dashboard' }, { - path: '/about', - name: 'about', - // route level code-splitting - // this generates a separate chunk (about.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => import(/* webpackChunkName: "about" */ './views/About.vue') + path: '/dashboard', + name: 'dashboard', + component: Dashboard + }, + { + path: '/measures', + name: 'measures', + component: Measures + }, + { + path: '/user-account', + name: 'user-account', + component: UserAccount } ] }); diff --git a/web/src/styles/reset.scss b/web/src/styles/reset.scss new file mode 100644 index 0000000..342899a --- /dev/null +++ b/web/src/styles/reset.scss @@ -0,0 +1,5 @@ +* { + border: 0; + box-sizing: border-box; + margin: 0; +} diff --git a/web/src/styles/vars.scss b/web/src/styles/vars.scss new file mode 100644 index 0000000..6ec9245 --- /dev/null +++ b/web/src/styles/vars.scss @@ -0,0 +1,53 @@ +/* Coolors Exported Palette - coolors.co/4f4e4d-1b998b-fffd82-ff9b71-e84855 */ + +/* HSL */ +// $color1: hsla(30%, 1%, 31%, 1); +// $color2: hsla(173%, 70%, 35%, 1); +// $color3: hsla(59%, 100%, 75%, 1); +// $color4: hsla(18%, 100%, 72%, 1); +// $color5: hsla(355%, 78%, 60%, 1); + +/* RGB */ +$color1: rgba(79, 78, 77, 1); +$color2: rgba(27, 153, 139, 1); +$color3: rgba(255, 253, 130, 1); +$color4: rgba(255, 155, 113, 1); +$color5: rgba(232, 72, 85, 1); + +$bg-primary: #333; +$fg-primary: #d8d8e0; + +$screen-x-small: 320px; +$screen-small: 640px; +$screen-wide: 1200px; +$screen-ultrawide: 1600px; + +/** ### forSize + * This mixin allows us to apply some rules selectively based on the screen + * size. There are three primary sizes: `small`, `medium`, and `large`, which + * are mutually exclusive. Additionally there are two additional sizes: + * `notSmall` and `ultraLarge`. `notSmall`, as the name implies matches any + * value which is not the small screen size, so it overlaps with medium, + * large, and ultraLarge. `ultraLarge` defines a wider minimum screen size + * than large, but neither large nor ultraLarge specify maximum widths, + * so ultraLarge is a strict subset of large. A screen large enough to match + * ultraLarge will also match large (compare with medium and large: matching + * medium means it will not match large, and vice versa). */ +@mixin for-size($size) { + + @if $size == xsmall { + @media screen and (max-width: $screen-x-small) { @content; } + } @else if $size == small { + @media screen and (max-width: $screen-small) { @content; } + } @else if $size == not-small { + @media screen and (min-width: $screen-small + 1) { @content; } + } @else if $size == medium { + @media screen and (min-width: $screen-small + 1) and (max-width: $screen-wide - 1) { @content; } + } @else if $size == large { + @media screen and (min-width: $screen-wide) { @content; } + } @else if $size == ultra-large { + @media screen and (min-width: $screen-ultrawide) { @content; } + } +} + + diff --git a/web/src/views/About.vue b/web/src/views/About.vue deleted file mode 100644 index 3fa2807..0000000 --- a/web/src/views/About.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/web/src/views/Dashboard.vue b/web/src/views/Dashboard.vue new file mode 100644 index 0000000..b3ff725 --- /dev/null +++ b/web/src/views/Dashboard.vue @@ -0,0 +1,6 @@ + + diff --git a/web/src/views/Home.vue b/web/src/views/Home.vue deleted file mode 100644 index c50a45d..0000000 --- a/web/src/views/Home.vue +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/web/src/views/Measures.vue b/web/src/views/Measures.vue new file mode 100644 index 0000000..99b9d78 --- /dev/null +++ b/web/src/views/Measures.vue @@ -0,0 +1,6 @@ + + diff --git a/web/src/views/NavBar.vue b/web/src/views/NavBar.vue index 99f1f60..f6cfd2e 100644 --- a/web/src/views/NavBar.vue +++ b/web/src/views/NavBar.vue @@ -1,5 +1,28 @@ diff --git a/web/src/views/UserAccount.vue b/web/src/views/UserAccount.vue new file mode 100644 index 0000000..44648dc --- /dev/null +++ b/web/src/views/UserAccount.vue @@ -0,0 +1,6 @@ + + diff --git a/web/src/views/home.ts b/web/src/views/dashboard.ts similarity index 100% rename from web/src/views/home.ts rename to web/src/views/dashboard.ts diff --git a/web/src/views/dashobard.ts b/web/src/views/dashobard.ts new file mode 100644 index 0000000..f9cbc82 --- /dev/null +++ b/web/src/views/dashobard.ts @@ -0,0 +1,4 @@ +import { Component, Vue } from 'vue-property-decorator'; + +@Component({}) +export default class Dashboard extends Vue {} diff --git a/web/src/views/measures.ts b/web/src/views/measures.ts new file mode 100644 index 0000000..432aaa8 --- /dev/null +++ b/web/src/views/measures.ts @@ -0,0 +1,6 @@ +import { Component, Vue } from 'vue-property-decorator'; + +@Component({ + components: { } +}) +export default class Measures extends Vue {} diff --git a/web/src/views/nav-bar.scss b/web/src/views/nav-bar.scss index e69de29..5d288f4 100644 --- a/web/src/views/nav-bar.scss +++ b/web/src/views/nav-bar.scss @@ -0,0 +1,49 @@ +@import '~@/styles/vars'; + +nav { + background-color: $color1; + color: $fg-primary; + display: flex; + flex-direction: column; + font-family: 'Exo 2'; + + &.expanded { + .collapsed { display: none; } + .collapse-handle { align-self: flex-end; } + } + + &.collapsed { + .expanded { display: none; } + svg { font-size: 2.2rem; } + .collapse-handle { align-self: center; } + } + + a { + color: inherit; + display: block; + font-size: 1.5rem; + padding: .5rem 0; + text-decoration: none; + width: 100%; + + &.router-link-active { color: $color3; } + + &:hover { color: $color3; } + + svg { + display: inline-block; + min-width: 1.5em; + } + } + + .logo { + color: $color4; + padding: 0 0 1rem; + } + + .collapse-handle { + cursor: pointer; + font-size: 1.5rem; + margin-top: auto; + } +} diff --git a/web/src/views/nav-bar.ts b/web/src/views/nav-bar.ts index 588ba66..eea0b56 100644 --- a/web/src/views/nav-bar.ts +++ b/web/src/views/nav-bar.ts @@ -1,6 +1,26 @@ import { Component, Vue } from 'vue-property-decorator'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faAngleDoubleLeft, faAngleDoubleRight, + faPencilRuler, faHome, faUser } from '@fortawesome/free-solid-svg-icons'; +// import UiIconButton from 'keen-ui/src/UiIconButton.vue'; + +library.add(faAngleDoubleLeft, faAngleDoubleRight, faPencilRuler, faHome, faUser); + @Component({ components: { + // UiIconButton } }) -export default class NavBar extends Vue {} +export default class NavBar extends Vue { + private collapsed: boolean; + + constructor() { + super(); + this.collapsed = false; + } + + public toggleCollapsed(): boolean { + this.collapsed = !this.collapsed; + return this.collapsed; + } +} diff --git a/web/src/views/user-account.ts b/web/src/views/user-account.ts new file mode 100644 index 0000000..a30a833 --- /dev/null +++ b/web/src/views/user-account.ts @@ -0,0 +1,4 @@ +import { Component, Vue } from 'vue-property-decorator'; + +@Component({}) +export default class UserAccount extends Vue {}