diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..3647ee6
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "editor.inlayHints.enabled": "offUnlessPressed"
+}
\ No newline at end of file
diff --git a/src/JobsJobsJobs/App/package-lock.json b/src/JobsJobsJobs/App/package-lock.json
index ec16ba4..e7b5b54 100644
--- a/src/JobsJobsJobs/App/package-lock.json
+++ b/src/JobsJobsJobs/App/package-lock.json
@@ -18,9 +18,9 @@
"date-fns-tz": "^1.1.6",
"dompurify": "^2.3.1",
"marked": "^4.0.18",
- "vue": "^3.2.6",
- "vue-router": "^4.0.11",
- "vuex": "^4.0.0-0"
+ "vue": "^3.2.45",
+ "vue-router": "^4.1.6",
+ "vuex": "^4.1.0"
},
"devDependencies": {
"@types/bootstrap": "^5.1.2",
@@ -3090,36 +3090,36 @@
}
},
"node_modules/@vue/compiler-core": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.37.tgz",
- "integrity": "sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
+ "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==",
"dependencies": {
"@babel/parser": "^7.16.4",
- "@vue/shared": "3.2.37",
+ "@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"source-map": "^0.6.1"
}
},
"node_modules/@vue/compiler-dom": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz",
- "integrity": "sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz",
+ "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==",
"dependencies": {
- "@vue/compiler-core": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-core": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"node_modules/@vue/compiler-sfc": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz",
- "integrity": "sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz",
+ "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==",
"dependencies": {
"@babel/parser": "^7.16.4",
- "@vue/compiler-core": "3.2.37",
- "@vue/compiler-dom": "3.2.37",
- "@vue/compiler-ssr": "3.2.37",
- "@vue/reactivity-transform": "3.2.37",
- "@vue/shared": "3.2.37",
+ "@vue/compiler-core": "3.2.45",
+ "@vue/compiler-dom": "3.2.45",
+ "@vue/compiler-ssr": "3.2.45",
+ "@vue/reactivity-transform": "3.2.45",
+ "@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7",
"postcss": "^8.1.10",
@@ -3127,12 +3127,12 @@
}
},
"node_modules/@vue/compiler-ssr": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz",
- "integrity": "sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz",
+ "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==",
"dependencies": {
- "@vue/compiler-dom": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-dom": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"node_modules/@vue/component-compiler-utils": {
@@ -3200,9 +3200,9 @@
"dev": true
},
"node_modules/@vue/devtools-api": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.2.0.tgz",
- "integrity": "sha512-pF1G4wky+hkifDiZSWn8xfuLOJI1ZXtuambpBEYaf7Xaf6zC/pM29rvAGpd3qaGXnr4BAXU1Pxz/VfvBGwexGA=="
+ "version": "6.4.5",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.4.5.tgz",
+ "integrity": "sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ=="
},
"node_modules/@vue/eslint-config-standard": {
"version": "7.0.0",
@@ -3253,60 +3253,60 @@
}
},
"node_modules/@vue/reactivity": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.37.tgz",
- "integrity": "sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz",
+ "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==",
"dependencies": {
- "@vue/shared": "3.2.37"
+ "@vue/shared": "3.2.45"
}
},
"node_modules/@vue/reactivity-transform": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz",
- "integrity": "sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz",
+ "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==",
"dependencies": {
"@babel/parser": "^7.16.4",
- "@vue/compiler-core": "3.2.37",
- "@vue/shared": "3.2.37",
+ "@vue/compiler-core": "3.2.45",
+ "@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7"
}
},
"node_modules/@vue/runtime-core": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.37.tgz",
- "integrity": "sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz",
+ "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==",
"dependencies": {
- "@vue/reactivity": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/reactivity": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"node_modules/@vue/runtime-dom": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz",
- "integrity": "sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz",
+ "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==",
"dependencies": {
- "@vue/runtime-core": "3.2.37",
- "@vue/shared": "3.2.37",
+ "@vue/runtime-core": "3.2.45",
+ "@vue/shared": "3.2.45",
"csstype": "^2.6.8"
}
},
"node_modules/@vue/server-renderer": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.37.tgz",
- "integrity": "sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz",
+ "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==",
"dependencies": {
- "@vue/compiler-ssr": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-ssr": "3.2.45",
+ "@vue/shared": "3.2.45"
},
"peerDependencies": {
- "vue": "3.2.37"
+ "vue": "3.2.45"
}
},
"node_modules/@vue/shared": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.37.tgz",
- "integrity": "sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw=="
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz",
+ "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg=="
},
"node_modules/@vue/vue-loader-v15": {
"name": "vue-loader",
@@ -5190,9 +5190,9 @@
}
},
"node_modules/csstype": {
- "version": "2.6.20",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz",
- "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
+ "version": "2.6.21",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
+ "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
},
"node_modules/date-fns": {
"version": "2.28.0",
@@ -11263,7 +11263,8 @@
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
- "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "deprecated": "Please use @jridgewell/sourcemap-codec instead"
},
"node_modules/spdx-correct": {
"version": "3.1.1",
@@ -12156,15 +12157,15 @@
}
},
"node_modules/vue": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.37.tgz",
- "integrity": "sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz",
+ "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==",
"dependencies": {
- "@vue/compiler-dom": "3.2.37",
- "@vue/compiler-sfc": "3.2.37",
- "@vue/runtime-dom": "3.2.37",
- "@vue/server-renderer": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-dom": "3.2.45",
+ "@vue/compiler-sfc": "3.2.45",
+ "@vue/runtime-dom": "3.2.45",
+ "@vue/server-renderer": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"node_modules/vue-demi": {
@@ -12345,11 +12346,11 @@
}
},
"node_modules/vue-router": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.2.tgz",
- "integrity": "sha512-5BP1qXFncVRwgV/XnqzsKApdMjQPqWIpoUBdL1ynz8HyLxIX/UDAx7Ql2BjmA5CXT/p61JfZvkpiFWFpaqcfag==",
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",
+ "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==",
"dependencies": {
- "@vue/devtools-api": "^6.1.4"
+ "@vue/devtools-api": "^6.4.5"
},
"funding": {
"url": "https://github.com/sponsors/posva"
@@ -12381,14 +12382,14 @@
"dev": true
},
"node_modules/vuex": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
- "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz",
+ "integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==",
"dependencies": {
"@vue/devtools-api": "^6.0.0-beta.11"
},
"peerDependencies": {
- "vue": "^3.0.2"
+ "vue": "^3.2.0"
}
},
"node_modules/watchpack": {
@@ -15415,36 +15416,36 @@
}
},
"@vue/compiler-core": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.37.tgz",
- "integrity": "sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
+ "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==",
"requires": {
"@babel/parser": "^7.16.4",
- "@vue/shared": "3.2.37",
+ "@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz",
- "integrity": "sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz",
+ "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==",
"requires": {
- "@vue/compiler-core": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-core": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"@vue/compiler-sfc": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz",
- "integrity": "sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz",
+ "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==",
"requires": {
"@babel/parser": "^7.16.4",
- "@vue/compiler-core": "3.2.37",
- "@vue/compiler-dom": "3.2.37",
- "@vue/compiler-ssr": "3.2.37",
- "@vue/reactivity-transform": "3.2.37",
- "@vue/shared": "3.2.37",
+ "@vue/compiler-core": "3.2.45",
+ "@vue/compiler-dom": "3.2.45",
+ "@vue/compiler-ssr": "3.2.45",
+ "@vue/reactivity-transform": "3.2.45",
+ "@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7",
"postcss": "^8.1.10",
@@ -15452,12 +15453,12 @@
}
},
"@vue/compiler-ssr": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz",
- "integrity": "sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz",
+ "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==",
"requires": {
- "@vue/compiler-dom": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-dom": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"@vue/component-compiler-utils": {
@@ -15518,9 +15519,9 @@
}
},
"@vue/devtools-api": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.2.0.tgz",
- "integrity": "sha512-pF1G4wky+hkifDiZSWn8xfuLOJI1ZXtuambpBEYaf7Xaf6zC/pM29rvAGpd3qaGXnr4BAXU1Pxz/VfvBGwexGA=="
+ "version": "6.4.5",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.4.5.tgz",
+ "integrity": "sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ=="
},
"@vue/eslint-config-standard": {
"version": "7.0.0",
@@ -15545,57 +15546,57 @@
}
},
"@vue/reactivity": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.37.tgz",
- "integrity": "sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz",
+ "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==",
"requires": {
- "@vue/shared": "3.2.37"
+ "@vue/shared": "3.2.45"
}
},
"@vue/reactivity-transform": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz",
- "integrity": "sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz",
+ "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==",
"requires": {
"@babel/parser": "^7.16.4",
- "@vue/compiler-core": "3.2.37",
- "@vue/shared": "3.2.37",
+ "@vue/compiler-core": "3.2.45",
+ "@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7"
}
},
"@vue/runtime-core": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.37.tgz",
- "integrity": "sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz",
+ "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==",
"requires": {
- "@vue/reactivity": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/reactivity": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"@vue/runtime-dom": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz",
- "integrity": "sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz",
+ "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==",
"requires": {
- "@vue/runtime-core": "3.2.37",
- "@vue/shared": "3.2.37",
+ "@vue/runtime-core": "3.2.45",
+ "@vue/shared": "3.2.45",
"csstype": "^2.6.8"
}
},
"@vue/server-renderer": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.37.tgz",
- "integrity": "sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz",
+ "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==",
"requires": {
- "@vue/compiler-ssr": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-ssr": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"@vue/shared": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.37.tgz",
- "integrity": "sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw=="
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz",
+ "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg=="
},
"@vue/vue-loader-v15": {
"version": "npm:vue-loader@15.10.0",
@@ -16949,9 +16950,9 @@
}
},
"csstype": {
- "version": "2.6.20",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz",
- "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
+ "version": "2.6.21",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
+ "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
},
"date-fns": {
"version": "2.28.0",
@@ -22029,15 +22030,15 @@
"dev": true
},
"vue": {
- "version": "3.2.37",
- "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.37.tgz",
- "integrity": "sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==",
+ "version": "3.2.45",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz",
+ "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==",
"requires": {
- "@vue/compiler-dom": "3.2.37",
- "@vue/compiler-sfc": "3.2.37",
- "@vue/runtime-dom": "3.2.37",
- "@vue/server-renderer": "3.2.37",
- "@vue/shared": "3.2.37"
+ "@vue/compiler-dom": "3.2.45",
+ "@vue/compiler-sfc": "3.2.45",
+ "@vue/runtime-dom": "3.2.45",
+ "@vue/server-renderer": "3.2.45",
+ "@vue/shared": "3.2.45"
}
},
"vue-demi": {
@@ -22157,11 +22158,11 @@
}
},
"vue-router": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.2.tgz",
- "integrity": "sha512-5BP1qXFncVRwgV/XnqzsKApdMjQPqWIpoUBdL1ynz8HyLxIX/UDAx7Ql2BjmA5CXT/p61JfZvkpiFWFpaqcfag==",
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",
+ "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==",
"requires": {
- "@vue/devtools-api": "^6.1.4"
+ "@vue/devtools-api": "^6.4.5"
}
},
"vue-style-loader": {
@@ -22189,9 +22190,9 @@
"dev": true
},
"vuex": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
- "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz",
+ "integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==",
"requires": {
"@vue/devtools-api": "^6.0.0-beta.11"
}
diff --git a/src/JobsJobsJobs/App/package.json b/src/JobsJobsJobs/App/package.json
index bf84a29..93866e7 100644
--- a/src/JobsJobsJobs/App/package.json
+++ b/src/JobsJobsJobs/App/package.json
@@ -18,9 +18,9 @@
"date-fns-tz": "^1.1.6",
"dompurify": "^2.3.1",
"marked": "^4.0.18",
- "vue": "^3.2.6",
- "vue-router": "^4.0.11",
- "vuex": "^4.0.0-0"
+ "vue": "^3.2.45",
+ "vue-router": "^4.1.6",
+ "vuex": "^4.1.0"
},
"devDependencies": {
"@types/bootstrap": "^5.1.2",
diff --git a/src/JobsJobsJobs/Directory.Build.props b/src/JobsJobsJobs/Directory.Build.props
index 2629784..48a6885 100644
--- a/src/JobsJobsJobs/Directory.Build.props
+++ b/src/JobsJobsJobs/Directory.Build.props
@@ -3,7 +3,7 @@
net6.0
enable
embedded
- 2.2.2.0
- 2.2.2.0
+ 3.0.0.0
+ 3.0.0.0
diff --git a/src/JobsJobsJobs/Server/.gitignore b/src/JobsJobsJobs/Server/.gitignore
deleted file mode 100644
index 701678b..0000000
--- a/src/JobsJobsJobs/Server/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-wwwroot
diff --git a/src/JobsJobsJobs/Server/Handlers.fs b/src/JobsJobsJobs/Server/Handlers.fs
index d74f646..6d88e6c 100644
--- a/src/JobsJobsJobs/Server/Handlers.fs
+++ b/src/JobsJobsJobs/Server/Handlers.fs
@@ -467,11 +467,21 @@ module Success =
| None -> return! Error.notFound next ctx
}
+[]
+module Home =
+ open JobsJobsJobs.Views
+ open JobsJobsJobs.Views.Layout
+
+ let home : HttpHandler = fun next ctx -> task {
+ let render = { IsLoggedOn = false; PageTitle = "Welcome"; CurrentUrl = "/"; Content = Home.home }
+ return! htmlView (view render) next ctx
+ }
open Giraffe.EndpointRouting
/// All available endpoints for the application
let allEndpoints = [
+ route "/" Home.home
subRoute "/api" [
subRoute "/citizen" [
GET_HEAD [ routef "/%O" Citizen.get ]
diff --git a/src/JobsJobsJobs/Server/JobsJobsJobs.Server.fsproj b/src/JobsJobsJobs/Server/JobsJobsJobs.Server.fsproj
index 2c4a48a..813f28e 100644
--- a/src/JobsJobsJobs/Server/JobsJobsJobs.Server.fsproj
+++ b/src/JobsJobsJobs/Server/JobsJobsJobs.Server.fsproj
@@ -10,6 +10,9 @@
+
+
+
@@ -25,6 +28,9 @@
+
+
+
diff --git a/src/JobsJobsJobs/Server/Views/Common.fs b/src/JobsJobsJobs/Server/Views/Common.fs
new file mode 100644
index 0000000..066a78c
--- /dev/null
+++ b/src/JobsJobsJobs/Server/Views/Common.fs
@@ -0,0 +1,10 @@
+[]
+module JobsJobsJobs.Views.Common
+
+open Giraffe.ViewEngine
+
+/// Create an audio clip with the specified text node
+let audioClip clip text =
+ span [ _class "jjj-audio-clip"; _onclick "jjj.playFile(this)" ] [
+ text; audio [ _id clip ] [ source [ _src $"/audio/{clip}.mp3" ] ]
+ ]
diff --git a/src/JobsJobsJobs/Server/Views/Home.fs b/src/JobsJobsJobs/Server/Views/Home.fs
new file mode 100644
index 0000000..86df136
--- /dev/null
+++ b/src/JobsJobsJobs/Server/Views/Home.fs
@@ -0,0 +1,72 @@
+module JobsJobsJobs.Views.Home
+
+open Giraffe.ViewEngine
+
+/// The home page
+let home =
+ article [] [
+ p [] [ rawText " " ]
+ p [] [
+ rawText "Welcome to Jobs, Jobs, Jobs (AKA No Agenda Careers), where citizens of Gitmo Nation can assist "
+ rawText "one another in finding employment. This will enable them to continue providing value-for-value to "
+ rawText "Adam and John, as they continue their work deconstructing the misinformation that passes for news "
+ rawText "on a day-to-day basis."
+ ]
+ p [] [
+ rawText "Do you not understand the terms in the paragraph above? No worries; just head over to "
+ a [ _href "https://noagendashow.net"; _target "_blank"; _rel "noopener" ] [
+ rawText "The Best Podcast in the Universe"
+ ]
+ rawText " "; em [] [ audioClip "thats-true" (rawText "(that’s true!)") ]
+ rawText " and find out what you’re missing."
+ ]
+ ]
+
+/// The page for terms of service
+let termsOfService =
+ article [] [
+ h3 [] [ rawText "Terms of Service" ]
+ p [ _class "fst-italic" ] [ rawText "(as of August 30th, 2022)" ]
+ h4 [] [ rawText "Acceptance of Terms" ]
+ p [] [
+ rawText "By accessing this web site, you are agreeing to be bound by these Terms and Conditions, and that "
+ rawText "you are responsible to ensure that your use of this site complies with all applicable laws. Your "
+ rawText "continued use of this site implies your acceptance of these terms."
+ ]
+ h4 [] [ rawText "Description of Service and Registration" ]
+ p [] [
+ rawText "Jobs, Jobs, Jobs is a service that allows individuals to enter and amend employment profiles and "
+ rawText "job listings, restricting access to the details of these to other users of this site, unless the "
+ rawText "individual specifies that this information should be visible publicly. See our "
+ a [ _href "/privacy-policy" ] [ str "privacy policy" ]
+ rawText " for details on the personal (user) information we maintain."
+ ]
+ h4 [] [ rawText "Liability" ]
+ p [] [
+ rawText "This service is provided “as is”, and no warranty (express or implied) exists. The "
+ rawText "service and its developers may not be held liable for any damages that may arise through the use "
+ rawText "of this service."
+ ]
+ h4 [] [ rawText "Updates to Terms" ]
+ p [] [
+ rawText "These terms and conditions may be updated at any time. When these terms are updated, users will "
+ rawText "be notified via a notice on the dashboard page. Additionally, the date at the top of this page "
+ rawText "will be updated, and any substantive updates will also be accompanied by a summary of those "
+ rawText "changes."
+ ]
+ hr []
+ p [] [
+ rawText "You may also wish to review our "
+ a [ _href "/privacy-policy" ] [ rawText "privacy policy" ]
+ rawText " to learn how we handle your data."
+ ]
+ hr []
+ p [ _class "fst-italic" ] [
+ rawText "Change on August 30th, 2022 – added references to job listings, removed "
+ rawText "references to Mastodon instances."
+ ]
+ p [ _class "fst-italic" ] [
+ rawText "Change on September 6th, 2021 – replaced “No Agenda Social” with a "
+ rawText "list of all No Agenda-affiliated Mastodon instances."
+ ]
+ ]
diff --git a/src/JobsJobsJobs/Server/Views/Layout.fs b/src/JobsJobsJobs/Server/Views/Layout.fs
new file mode 100644
index 0000000..d33c147
--- /dev/null
+++ b/src/JobsJobsJobs/Server/Views/Layout.fs
@@ -0,0 +1,148 @@
+module JobsJobsJobs.Views.Layout
+
+open Giraffe.ViewEngine
+open Giraffe.ViewEngine.Accessibility
+open Giraffe.ViewEngine.Htmx
+
+/// Data items needed to render a view
+type PageRenderContext =
+ { /// Whether a user is logged on
+ IsLoggedOn : bool
+
+ /// The current URL
+ CurrentUrl : string
+
+ /// The title of this page
+ PageTitle : string
+
+ /// The page content
+ Content : XmlNode
+ }
+
+/// Generate the HTML head tag
+let private htmlHead ctx =
+ let pageTitle =
+ seq {
+ if ctx.PageTitle <> "" then
+ ctx.PageTitle; " | "
+ "Jobs, Jobs, Jobs"
+ } |> Seq.reduce (+)
+ head [] [
+ meta [ _name "viewport"; _content "width=device-width, initial-scale=1" ]
+ title [] [ str pageTitle ]
+ link [ _href "https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css"
+ _rel "stylesheet"
+ _integrity "sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx"
+ _crossorigin "anonymous" ]
+ link [ _href "https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
+ _rel "stylesheet" ]
+ link [ _href "/style.css"; _rel "stylesheet" ]
+ ]
+
+/// Display the links available to the current user
+let private links ctx =
+ let navLink url icon text =
+ a [ _href url
+ _onclick "jjj.hideMenu()"
+ if url = ctx.CurrentUrl then _class "jjj-current-page"
+ ] [ i [ _class $"mdi mdi-{icon}"; _ariaHidden "true" ] []; rawText text ]
+ nav [ _class "jjj-nav" ] [
+ if ctx.IsLoggedOn then
+ navLink "/citizen/dashboard" "view-dashboard-variant" "Dashboard"
+ navLink "/help-wanted" "newspaper-variant-multiple-outline" "Help Wanted!"
+ navLink "/profile/search" "view-list-outline" "Employment Profiles"
+ navLink "/success-story/list" "thumb-up" "Success Stories"
+ div [ _class "separator" ] []
+ navLink "/citizen/account" "mdiAccountEdit" "My Account"
+ navLink "/listings/mine" "mdiSignText" "My Job Listings"
+ navLink "/profile/edit" "mdiPencil" "My Employment Profile"
+ div [ _class "separator" ] []
+ navLink "/citizen/log-off" "mdiLogoutVariant" "Log Off"
+ else
+ navLink "/" "home" "Home"
+ navLink "/profile/seeking" "view-list-outline" "Job Seekers"
+ navLink "/citizen/log-on" "login-variant" "Log On"
+ navLink "/how-it-works" "help-circle-outline" "How It Works"
+ ]
+
+/// Generate mobile and desktop side navigation areas
+let private sideNavs ctx = [
+ div [ _id "mobileMenu"
+ _class "jjj-mobile-menu offcanvas offcanvas-end"
+ _tabindex "-1"
+ _ariaLabelledBy "mobileMenuLabel" ] [
+ div [ _class "offcanvas-header" ] [
+ h5 [ _id "mobileMenuLabel" ] [ rawText "Menu" ]
+ button [
+ _class "btn-close text-reset"; _type "button"; _data "bs-dismiss" "offcanvas"; _ariaLabel "Close"
+ ] []
+ ]
+ div [ _class "offcanvas-body" ] [ links ctx ]
+ ]
+ aside [ _class "jjj-full-menu d-none d-md-block p-3" ] [
+ p [ _class "home-link pb-3" ] [ a [ _href "/" ] [ rawText "Jobs, Jobs, Jobs" ] ]
+ p [] [ rawText " " ]
+ links ctx
+ ]
+]
+
+/// Title bars for mobile and desktop
+let private titleBars = [
+ nav [ _class "d-flex d-md-none navbar navbar-dark" ] [
+ span [ _class "navbar-text" ] [ a [ _href "/" ] [ rawText "Jobs, Jobs, Jobs" ] ]
+ button [ _class "btn"
+ _data "bs-toggle" "offcanvas"
+ _data "bs-target" "#mobileMenu"
+ _ariaControls "mobileMenu" ] [ i [ _class "mdi mdi-menu" ] [] ]
+ ]
+ nav [ _class "d-none d-md-flex navbar navbar-light bg-light"] [
+ span [] [ rawText " " ]
+ span [ _class "navbar-text" ] [
+ rawText "(…and Jobs – "
+ audioClip "pelosi-jobs" (rawText "Let’s Vote for Jobs!")
+ rawText ")"
+ ]
+ ]
+]
+
+/// The HTML footer for the page
+let private htmlFoot =
+ let v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
+ let version =
+ seq {
+ string v.Major
+ if v.Minor > 0 then
+ "."; string v.Minor
+ if v.Build > 0 then
+ "."; string v.Build
+ } |> Seq.reduce (+)
+ footer [] [
+ p [ _class "text-muted" ] [
+ str "Jobs, Jobs, Jobs v"; str version; rawText " • "
+ a [ _href "/privacy-policy" ] [ str "Privacy Policy" ]; rawText " • "
+ a [ _href "/terms-of-service" ] [ str "Terms of Service" ]
+ ]
+ ]
+
+/// Create a full view
+let view ctx =
+ html [ _lang "en" ] [
+ htmlHead ctx
+ body [] [
+ div [ _class "jjj-app" ] [
+ yield! sideNavs ctx
+ //otherSideNav ctx
+ div [ _class "jjj-main" ] [
+ yield! titleBars
+ main [ _class "jjj-content container-fluid" ] [ ctx.Content ]
+ htmlFoot
+ ]
+ ]
+ Script.minified
+ script [ _async
+ _src "https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
+ _integrity "sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
+ _crossorigin "anonymous" ] []
+ script [ _src "/script.js" ] []
+ ]
+ ]
diff --git a/src/JobsJobsJobs/Server/wwwroot/audio/pelosi-jobs.mp3 b/src/JobsJobsJobs/Server/wwwroot/audio/pelosi-jobs.mp3
new file mode 100644
index 0000000..fda27a3
Binary files /dev/null and b/src/JobsJobsJobs/Server/wwwroot/audio/pelosi-jobs.mp3 differ
diff --git a/src/JobsJobsJobs/Server/wwwroot/audio/thats-true.mp3 b/src/JobsJobsJobs/Server/wwwroot/audio/thats-true.mp3
new file mode 100644
index 0000000..1523b4a
Binary files /dev/null and b/src/JobsJobsJobs/Server/wwwroot/audio/thats-true.mp3 differ
diff --git a/src/JobsJobsJobs/Server/wwwroot/script.js b/src/JobsJobsJobs/Server/wwwroot/script.js
new file mode 100644
index 0000000..3c6df25
--- /dev/null
+++ b/src/JobsJobsJobs/Server/wwwroot/script.js
@@ -0,0 +1,19 @@
+/** Script for Jobs, Jobs, Jobs */
+this.jjj = {
+ /**
+ * Play an audio file
+ * @param {HTMLElement} elt The element which was clicked
+ */
+ playFile(elt) {
+ elt.querySelector("audio").play()
+ },
+
+ /**
+ * Hide the offcanvas menu if it displayed
+ */
+ hideMenu() {
+ /** @type {HTMLElement} */
+ const menu = document.querySelector(".jjj-mobile-menu")
+ if (menu.style.display !== "none") bootstrap.Offcanvas.getOrCreateInstance(menu).hide()
+ }
+}
diff --git a/src/JobsJobsJobs/Server/wwwroot/style.css b/src/JobsJobsJobs/Server/wwwroot/style.css
new file mode 100644
index 0000000..28679a0
--- /dev/null
+++ b/src/JobsJobsJobs/Server/wwwroot/style.css
@@ -0,0 +1,212 @@
+/* Overall styling */
+html {
+ scroll-behavior: smooth;
+}
+a:link,
+a:visited {
+ text-decoration: none;
+}
+a:not(.btn):hover {
+ text-decoration: underline;
+}
+label.jjj-required::after {
+ color: red;
+ content: ' *';
+}
+.jjj-heading-label {
+ display: inline-block;
+ font-size: 1rem;
+ text-transform: uppercase;
+}
+.material-icons {
+ vertical-align: bottom;
+}
+/* Material Design Icon / Bootstrap styling */
+.mdi::before {
+ font-size: 24px;
+ line-height: 14px;
+}
+.btn .mdi::before {
+ position: relative;
+ top: 4px;
+}
+.btn-xs .mdi::before {
+ font-size: 18px;
+ top: 3px;
+}
+.btn-sm .mdi::before {
+ font-size: 18px;
+ top: 3px;
+}
+.dropdown-menu .mdi {
+ width: 18px;
+}
+.dropdown-menu .mdi::before {
+ position: relative;
+ top: 4px;
+ left: -8px;
+}
+.nav .mdi::before {
+ position: relative;
+ top: 4px;
+}
+.navbar .navbar-toggle .mdi::before {
+ position: relative;
+ top: 4px;
+ color: #FFF;
+}
+.breadcrumb .mdi::before {
+ position: relative;
+ top: 4px;
+}
+.breadcrumb a:hover {
+ text-decoration: none;
+}
+.breadcrumb a:hover span {
+ text-decoration: underline;
+}
+.alert .mdi::before {
+ position: relative;
+ top: 4px;
+ margin-right: 2px;
+}
+.input-group-addon .mdi::before {
+ position: relative;
+ top: 3px;
+}
+.navbar-brand .mdi::before {
+ position: relative;
+ top: 2px;
+ margin-right: 2px;
+}
+.list-group-item .mdi::before {
+ position: relative;
+ top: 3px;
+ left: -3px
+}
+/* Layout styling */
+.jjj-app {
+ display: flex;
+ flex-direction: row;
+}
+.jjj-main {
+ flex-grow: 1;
+ display: flex;
+ flex-flow: column;
+ min-height: 100vh;
+}
+.jjj-content {
+ flex-grow: 2;
+}
+/* Menu styling */
+.jjj-full-menu,
+.jjj-mobile-menu {
+ background-image: linear-gradient(180deg, darkgreen 0%, green 70%);
+ color: white;
+ font-size: 1.2rem;
+}
+.jjj-full-menu {
+ min-height: 100vh;
+ width: 250px;
+ min-width: 250px;
+ position: sticky;
+ top: 0;
+ display: none;
+}
+.jjj-full-menu .home-link {
+ font-size: 1.2rem;
+ text-align: center;
+ background-color: rgba(0, 0, 0, .4);
+ margin: -1rem;
+ padding: 1rem;
+}
+.jjj-full-menu a:link,
+.jjj-full-menu a:visited {
+ text-decoration: none;
+ color: white;
+}
+#jjjMenu {
+ flex-direction: column;
+ flex-grow: 1;
+}
+@media (min-width: 768px) {
+ .jjj-full-menu {
+ display: unset;
+ }
+ .jjj-mobile-menu {
+ display: none;
+ }
+ .navbar-expand-md .navbar-nav {
+ flex-direction: column;
+ }
+}
+.jjj-nav a:link,
+.jjj-nav a:visited {
+ text-decoration: none;
+ color: white;
+}
+nav.jjj-nav > a {
+ display: block;
+ width: 100%;
+ border-radius: .25rem;
+ padding: .5rem;
+ margin: .5rem 0;
+ font-size: 1rem;
+}
+nav.jjj-nav > a > i {
+ vertical-align: top;
+ margin-right: 1rem;
+}
+nav.jjj-nav > a > i.mdi::before {
+ line-height: 24px;
+}
+nav.jjj-nav > a.jjj-current-page {
+ background-color: rgba(255, 255, 255, .2);
+}
+nav.jjj-nav > a:hover {
+ background-color: rgba(255, 255, 255, .5);
+ color: black;
+ text-decoration: none;
+}
+nav.jjj-nav > div.separator {
+ border-bottom: solid 1px rgba(255, 255, 255, .75);
+ height: 1px;
+}
+/* Title bar styling */
+.jjj-main .navbar-dark {
+ background-image: linear-gradient(0deg, green 0%, darkgreen 70%);
+ padding-left: 1rem;
+ padding-right: 1rem;
+}
+.jjj-main .navbar-dark button {
+ padding: 0;
+}
+.jjj-main .navbar-dark .navbar-text {
+ font-weight: bold;
+ color: white;
+}
+.jjj-main .navbar-light .navbar-text {
+ font-style: italic;
+ padding: 0 1rem 0 0;
+}
+/* Audio Clip styling */
+.jjj-audio-clip audio {
+ display: none;
+}
+span.jjj-audio-clip {
+ border-bottom: dotted 1px lightgray;
+}
+span.jjj-audio-clip:hover {
+ cursor: pointer;
+}
+/* Footer styling */
+footer {
+ display: flex;
+ flex-direction: row-reverse;
+}
+footer p {
+ padding-top: 2rem;
+ padding-right: .5rem;
+ font-style: italic;
+ font-size: .8rem;
+}