diff --git a/package.json b/package.json index ce543185..c3a3828c 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "terser-webpack-plugin": "^5.3.9", "vue": "^3.3.4", "vue-loader": "^17.2.2", + "vee-validate": "^4.5.8", "vue-material-design-icons": "^5.2.0", "vue3-icon": "^2.1.0", "webpack": "^5.88.2", diff --git a/src/vue/.storybook/main.js b/src/vue/.storybook/main.js index 94a55abb..4ea4cf54 100644 --- a/src/vue/.storybook/main.js +++ b/src/vue/.storybook/main.js @@ -1,7 +1,8 @@ /** @type { import('@storybook/vue3-webpack5').StorybookConfig } */ const webpack = require("webpack"); const path = require("path"); -const config = { + +module.exports = { stories: ["../**/*.stories.@(js|jsx|mjs|ts|tsx)"], addons: [ "storybook-addon-sass-postcss", @@ -18,13 +19,14 @@ const config = { }, staticDirs: [path.resolve(__dirname, "../assets")], webpackFinal: async (config) => { + // Define global constants that can be accessed in your stories config.plugins.push( new webpack.DefinePlugin({ SERVER: JSON.stringify("http://localhost:6006/"), }) ); + return config; }, }; -export default config; diff --git a/src/vue/.storybook/preview-head.html b/src/vue/.storybook/preview-head.html index 34e35130..f9ffcc5d 100644 --- a/src/vue/.storybook/preview-head.html +++ b/src/vue/.storybook/preview-head.html @@ -1,11 +1,12 @@ - - - - - - + + + + - - - + + + + + + diff --git a/src/vue/assets/fonts.css b/src/vue/assets/fonts.css new file mode 100644 index 00000000..2a95ad18 --- /dev/null +++ b/src/vue/assets/fonts.css @@ -0,0 +1,72 @@ +/* Montserrat Font Family */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-stretch: normal; + font-family: 'Montserrat'; + src: url('/fonts/MontserratRegular.woff2') format('woff2'), + url('/fonts/MontserratRegular.woff') format('woff'); + font-weight: 400; +} + +@font-face { + font-family: 'Montserrat'; + src: url('/fonts/MontserratRegular.woff2') format('woff2'), + url('/fonts/MontserratRegular.woff') format('woff'); + font-weight: 400; +} + +@font-face { + font-family: 'Montserrat'; + src: url('/fonts/MontserratMedium.woff2') format('woff2'), + url('/fonts/MontserratMedium.woff') format('woff'); + font-weight: 500; +} + +@font-face { + font-family: 'Montserrat'; + src: url('/fonts/MontserratSemiBold.woff2') format('woff2'), + url('/fonts/MontserratSemiBold.woff') format('woff'); + font-weight: 600; +} + +@font-face { + font-family: 'Montserrat'; + src: url('/fonts/MontserratBold.woff2') format('woff2'), + url('/fonts/MontserratBold.woff') format('woff'); + font-weight: 700; +} + +/* Roboto Font Family */ +@font-face { + font-family: 'Roboto'; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('/fonts/RobotoRegular.woff2') format('woff2'), + url('/fonts/RobotoRegular.woff') format('woff'); + font-weight: normal; +} + +@font-face { + font-family: 'Roboto'; + src: url('/fonts/RobotoMedium.woff2') format('woff2'), + url('/fonts/RobotoMedium.woff') format('woff'); + font-weight: 500; +} + +@font-face { + font-family: 'RobotoBold'; + src: url('/fonts/RobotoBold.woff2') format('woff2'), + url('/fonts/RobotoBold.woff') format('woff'); + font-weight: 700; +} + +/* Body */ +body { + font-family: 'Roboto', sans-serif; +} + + diff --git a/src/vue/components/Button.vue b/src/vue/components/Button.vue index 3dada6cf..ed7dd0a5 100644 --- a/src/vue/components/Button.vue +++ b/src/vue/components/Button.vue @@ -2,7 +2,7 @@ ({ + components: { CheckboxInput }, + setup() { + return { args }; + }, + template: '', +}); + +export const Default = Template.bind({}); +Default.args = { + label: "Checkbox label", + name: "staySignedIn", +}; diff --git a/src/vue/components/checkbox-input/CheckboxInput.vue b/src/vue/components/checkbox-input/CheckboxInput.vue new file mode 100644 index 00000000..cca27c2d --- /dev/null +++ b/src/vue/components/checkbox-input/CheckboxInput.vue @@ -0,0 +1,95 @@ + + + + + {{ label }} + + + + + + + + + diff --git a/src/vue/components/link/Link.stories.js b/src/vue/components/link/Link.stories.js new file mode 100644 index 00000000..a5db9a6f --- /dev/null +++ b/src/vue/components/link/Link.stories.js @@ -0,0 +1,25 @@ +import { defineComponent } from "vue"; + +import Link from "./Link.vue"; // Import your Link component + +export default { + title: "Components/Link", + component: Link, + argTypes: { + url: { control: "text" }, + }, +}; + +const Template = (args) => + defineComponent({ + components: { Link }, + setup() { + return { args }; + }, + template: 'Gå til siden', + }); + +export const Default = Template.bind({}); +Default.args = { + url: "https://example.com", +}; diff --git a/src/vue/components/link/Link.vue b/src/vue/components/link/Link.vue new file mode 100644 index 00000000..27e26688 --- /dev/null +++ b/src/vue/components/link/Link.vue @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/src/vue/components/login-form/LoginForm.stories.js b/src/vue/components/login-form/LoginForm.stories.js new file mode 100644 index 00000000..555c1835 --- /dev/null +++ b/src/vue/components/login-form/LoginForm.stories.js @@ -0,0 +1,24 @@ +import { defineComponent } from "vue"; +import LoginForm from "./LoginForm.vue"; + +export default { + title: "Components/LoginForm", + component: LoginForm, +}; + +const Template = (args) => + defineComponent({ + components: { LoginForm }, + setup() { + return args; + }, + template: + '', + }); + +export const Default = Template.bind({}); +Default.args = { + email: "", + password: "", + stayLoggedIn: false, +}; diff --git a/src/vue/components/login-form/LoginForm.vue b/src/vue/components/login-form/LoginForm.vue new file mode 100644 index 00000000..91543d7a --- /dev/null +++ b/src/vue/components/login-form/LoginForm.vue @@ -0,0 +1,104 @@ + + + Logg inn på kompetanse portalen + + + + + + Logg inn + Glemt passord? + + Opprette ny bruker? + For å opprette bruker i kompetanseportalen, må du være registrert i en + kompetansepakke. Dette gjør du ved å velge en kompetansepakke fra kompetanse.udir.no og registrere deg på denne + ved hjelp av din e-postadresse. + + + + + + + diff --git a/src/vue/components/text-input/TextInput.stories.js b/src/vue/components/text-input/TextInput.stories.js new file mode 100644 index 00000000..c97a0980 --- /dev/null +++ b/src/vue/components/text-input/TextInput.stories.js @@ -0,0 +1,39 @@ +import TextInput from "./TextInput.vue"; + +export default { + title: "Components/TextInput", + component: TextInput, + argTypes: { + label: { control: "text" }, + name: { control: "text" }, + rules: { control: "text" }, + type: { control: "text" }, + modelValue: { control: "text" }, + }, +}; + +const Template = (args) => ({ + components: { TextInput }, + setup() { + return { args }; + }, + template: '', +}); + +export const Email = Template.bind({}); +Email.args = { + label: "E-post", + name: "email", + rules: "required|min:3", + type: "email", + modelValue: "", +}; + +export const Password = Template.bind({}); +Password.args = { + label: "Passord", + name: "password", + rules: "required|min:8", + type: "password", + modelValue: "", +}; diff --git a/src/vue/components/text-input/TextInput.vue b/src/vue/components/text-input/TextInput.vue new file mode 100644 index 00000000..e4ca7a70 --- /dev/null +++ b/src/vue/components/text-input/TextInput.vue @@ -0,0 +1,145 @@ + + + {{ label }} + + + + + + + {{ errors[0] }} + + + + + + diff --git a/src/vue/design/_box-shadow.scss b/src/vue/design/_box-shadow.scss new file mode 100644 index 00000000..d8cdf992 --- /dev/null +++ b/src/vue/design/_box-shadow.scss @@ -0,0 +1,12 @@ +$box-shadow-small: 0 0.1rem 0.2rem rgba(19, 19, 19, 0.15); +$box-shadow-medium: 0 0.2rem 0.3rem rgba(19, 19, 19, 0.35); + +@mixin box-shadow($size: small) { + @if $size == small { + box-shadow: $box-shadow-small; + } @else if $size == medium { + box-shadow: $box-shadow-medium; + } @else { + box-shadow: 0; + } +} diff --git a/src/vue/design/_semantic-colors.scss b/src/vue/design/_semantic-colors.scss new file mode 100644 index 00000000..3b12ad95 --- /dev/null +++ b/src/vue/design/_semantic-colors.scss @@ -0,0 +1,23 @@ +@import "./colors.scss"; + +// Define semantic colors using a more structured format +$semantic-colors: ( + success: ( + background: map-get($color-palette-green, background, 200), + foreground: map-get($color-palette-green, background, 600), + ), + error: ( + background: map-get($color-palette-red, background, 200), + foreground: map-get($color-palette-red, background, 600), + text: map-get($color-palette-red, background, 600), + icon: map-get($color-palette-red, background, 600), + ), + info: ( + background: map-get($color-palette-steel, background, 200), + foreground: map-get($color-palette-steel, background, 700), + ), + warning: map-get($color-palette-orange, background, 600), + hover: $primary-hover-color, + text: $color-grey-900, + focus: $primary-hover-color, +); diff --git a/src/vue/design/_shake-effect.scss b/src/vue/design/_shake-effect.scss new file mode 100644 index 00000000..59b525fb --- /dev/null +++ b/src/vue/design/_shake-effect.scss @@ -0,0 +1,25 @@ +@mixin shake-effect() { + animation: shake 0.25s ease-in-out; + + @keyframes shake { + 0% { + transform: translateX(0); + } + + 25% { + transform: translateX(-0.313rem); + } + + 50% { + transform: translateX(0.313rem); + } + + 75% { + transform: translateX(-0.313rem); + } + + 100% { + transform: translateX(0); + } + } +} diff --git a/yarn.lock b/yarn.lock index 6af393dd..f63b44ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3277,6 +3277,11 @@ "@vue/compiler-dom" "3.3.4" "@vue/shared" "3.3.4" +"@vue/devtools-api@^6.0.0-beta.15": + version "6.5.0" + resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz" + integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q== + "@vue/reactivity-transform@3.3.4": version "3.3.4" resolved "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz" @@ -12700,6 +12705,13 @@ vary@^1, vary@~1.1.2: resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +vee-validate@^4.5.8: + version "4.5.8" + resolved "https://registry.npmjs.org/vee-validate/-/vee-validate-4.5.8.tgz" + integrity sha512-XZx2J93rlET49CdIIoxG9R6wQNoT3RxUUw9ar3QbIhczpzbtlm4BQ+TpCA9DoYHKFlApcXnE28WU7m4quoPsCA== + dependencies: + "@vue/devtools-api" "^6.0.0-beta.15" + void-elements@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz"
For å opprette bruker i kompetanseportalen, må du være registrert i en + kompetansepakke. Dette gjør du ved å velge en kompetansepakke fra kompetanse.udir.no og registrere deg på denne + ved hjelp av din e-postadresse.