├── .eslintrc.cjs
├── .gitignore
├── .prettierrc.json
├── .vscode
└── extensions.json
├── README.md
├── auth.png
├── env.d.ts
├── index.html
├── package.json
├── public
└── favicon.ico
├── src
├── App.vue
├── assets
│ └── scss
│ │ ├── abstract
│ │ └── _variables.scss
│ │ ├── base
│ │ └── _reset.scss
│ │ ├── components
│ │ ├── _anchor.scss
│ │ ├── _button.scss
│ │ ├── _container.scss
│ │ ├── _divider.scss
│ │ ├── _input.scss
│ │ ├── _label.scss
│ │ ├── _loader.scss
│ │ └── _message.scss
│ │ └── main.scss
├── components
│ ├── Auth
│ │ ├── Auth.vue
│ │ └── interfaces
│ │ │ ├── EmailAuth.vue
│ │ │ ├── ForgottenPassword.vue
│ │ │ ├── MagicLink.vue
│ │ │ ├── SocialAuth.vue
│ │ │ └── UpdatePassword.vue
│ ├── UI
│ │ ├── Anchor.vue
│ │ ├── Button.vue
│ │ ├── Container.vue
│ │ ├── Divider.vue
│ │ ├── Input.vue
│ │ ├── Label.vue
│ │ ├── Loader.vue
│ │ └── Message.vue
│ └── icons
│ │ ├── IconApple.vue
│ │ ├── IconAzure.vue
│ │ ├── IconBitBucket.vue
│ │ ├── IconDiscord.vue
│ │ ├── IconFacebook.vue
│ │ ├── IconGithub.vue
│ │ ├── IconGitlab.vue
│ │ ├── IconGoogle.vue
│ │ ├── IconKeycloak.vue
│ │ ├── IconLinkedin.vue
│ │ ├── IconNotion.vue
│ │ ├── IconSlack.vue
│ │ ├── IconSpotify.vue
│ │ ├── IconTwitch.vue
│ │ ├── IconTwitter.vue
│ │ └── IconWorkos.vue
├── index.ts
├── localisation
│ ├── de_formal.json
│ ├── de_informal.json
│ ├── en.json
│ ├── index.ts
│ ├── ja.json
│ └── pt_br.json
├── main.ts
├── shim-vue.d.ts
├── theming
│ ├── defaultThemes.ts
│ ├── index.ts
│ ├── themes.ts
│ └── types.ts
├── types
│ └── index.ts
└── utils.ts
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── yarn.lock
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | require("@rushstack/eslint-patch/modern-module-resolution");
3 |
4 | module.exports = {
5 | root: true,
6 | extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/eslint-config-typescript"],
7 | parserOptions: {
8 | ecmaVersion: "latest",
9 | },
10 | rules: {
11 | "vue/multi-word-component-names": "off",
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | .DS_Store
12 | dist
13 | dist-ssr
14 | coverage
15 | *.local
16 | .env
17 |
18 | /cypress/videos/
19 | /cypress/screenshots/
20 |
21 | # Editor directories and files
22 | .vscode/*
23 | !.vscode/extensions.json
24 | .idea
25 | *.suo
26 | *.ntvs*
27 | *.njsproj
28 | *.sln
29 | *.sw?
30 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "tabWidth": 4,
4 | "endOfLine": "crlf",
5 | "semi": true,
6 | "singleQuote": false,
7 | "printWidth": 180
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
3 | }
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Supabase Auth UI Vue 💚
2 |
3 | Supabase Auth UI is a pre-built Vue component for authenticating users. It supports custom themes and extensible styles to match your brand and aesthetic.
4 |
5 | This was built as my first step towards contributing to open source and is heavily inspired by [Supabase Auth UI React](https://github.com/supabase/auth-ui/tree/main/packages/react)
6 |
7 |
8 |
9 | ## Demo
10 | You can find a link to the hosted demo [here](https://auth-ui-vue-demo-evqn.vercel.app/).
11 |
12 | ## Set up Auth UI 👷🏽♂️
13 |
14 | Import the latest version of [supabase-js](https://supabase.com/docs/reference/javascript) and the Auth UI package
15 |
16 | #### Using npm:
17 |
18 | ```bash
19 | $ npm install @supabase/supabase-js auth-ui-vue
20 | ```
21 |
22 | #### Using yarn:
23 |
24 | ```bash
25 | $ yarn add @supabase/supabase-js auth-ui-vue
26 | ```
27 |
28 | ### Import the Auth component
29 |
30 | Pass `supabaseClient` from `@supabase/supabase-js` as a prop to the component.
31 |
32 | ```vue
33 |
40 |
41 |
42 |
43 |
44 | ```
45 |
46 | This renders the Auth component without any styling. We recommend using one of the predefined themes to style the UI. Import the theme you want to use and pass it to the `appearence.theme` prop.
47 |
48 | ```vue
49 |
60 |
61 |
62 | ```
63 |
64 | ## Social Providers 📲
65 |
66 | The Auth component also supports login with [offical social providers.](https://supabase.com/docs/guides/auth#providers)
67 |
68 | ```vue
69 |
76 |
77 |
78 |
79 |
80 | ```
81 |
82 | ## Props ⚡️
83 |
84 | There are some props that are could be passed to props to the Auth component to determine its output
85 | | Prop | Description | Type | default
86 | | --- | --- | --- | --- |
87 | | supabaseClient | An isomorphic Javascript client for interacting with Postgres. | _`SupabaseClient`_ |
88 | | socialLayout | This determines how the social providers show be displayed | _`horizontal \| vertical`_ | vertical |
89 | | providers | This is an array of social providers that can be used by your users to sign up | _`Provider[]`_ |
90 | | view | This determines what type of auth component is displayed | _`sign_in \| sign_up \| magic_link \| forgotten_password \| update_password`_ | sign_in |
91 | | redirectTo | This determines where supabase should redirect to when users want to sign in with a magic link, sign in with a social provider or update password | _`undefined \| string`_ |
92 | | onlyThirdPartyProviders | This determines whether to show the email and password mode of authentication when the [providers](#social-providers-📲) props is set | _`boolean`_ | false |
93 | | magicLink | This determines whether to show the _'Send Magic Link'_ anchor so users can sign in with magic link | _`boolean`_ | false |
94 | | showLinks | This determines whether to show the links which users can use to change the view to either _`sign_up/sign_in, magic_link,forgotten_password`_ | *`boolean`* | true |
95 | | localization | This determines how the auth component texts like label, placeholders, and anchors can be styled to match your design language| _`Localization`_ | { lang: 'en' } |
96 | | appearance | This determines how the auth component can be styled to match your design | _`Appearance`_ |
97 | | theme | This determines what variant of the theme passed to *`appearance.theme`* | *`default \| string`* | default |
98 |
99 | #### External resources for props:
100 |
101 | - Check [here](https://github.com/supabase/supabase-js) to see how to initialise the `SupabaseClient`.
102 | - Check [here](https://supabase.com/docs/guides/auth/overview#providers) for the list of Providers that can be passed to the `providers` prop.
103 | - Check [here](#custom-labels) to see how the language of the auth component can be overwritten using the `localization` prop.
104 | - Check [here](#customization-✨) to see how the auth component can be styled to match your design using the `appearance` prop.
105 |
106 |
107 | ## Events 🌐
108 | These are some of the events that are emitted by the Auth component when an auth operation is completed which can be listened to on the page/component where the Auth component is being used.
109 |
110 | | Event Name | Description | Emitted Value
111 | | --- | --- | --- |
112 | | set-loading | This event is emitted when an auth operation begins and when it ends | `loading: boolean` |
113 | | signin-completed | This event is emitted when the user signs in into your app successfully | `data: any` |
114 | | signup-completed | This event is emitted when the user signs up on your app successfully | `data:any` |
115 | | magic-link-sent | This event is emitted when the user asks for a magic link to be sent to their email |
116 | | forgotten-password-completed | This event is emitted when the user wants to reset their password and link to do so is sent to their email |
117 | | update-password-completed | This event is emitted when the user successfully change their password to a new one |
118 |
119 | ### Example:
120 |
121 | ```vue
122 |
133 |
134 |
135 |
139 |
140 | ```
141 |
142 | ## Customization ✨
143 |
144 | There are several ways to customize Auth UI:
145 |
146 | - Use one of the [predefined themes](#predefined-themes) that comes with Auth UI
147 | - Extend a theme by [overriding the variable tokens](#override-themes) in a theme
148 | - [Create your own theme](#create-your-own-theme)
149 | - [Use your own CSS classes](#custom-css-classes)
150 | - [Use inline styles](#custom-inline-css)
151 | - [Use your own labels](#custom-labels)
152 |
153 | ### Predefined themes
154 |
155 | Auth UI comes with several themes to customize the appearance. Each predefined theme comes with at least two variations, a `default` variation, and a `dark` variation. You can switch between these themes using the `theme` prop. Import the theme you want to use and pass it to the `appearence.theme` prop.
156 |
157 | ```vue
158 |
169 |
170 |
171 | ```
172 |
173 | > Currently there is only one predefined theme available, but I plan to add more as soon as Supabase does.
174 |
175 | ### Switch theme variations
176 |
177 | Auth UI comes with two theme variations: `default` and `dark`. You can switch between these themes with the `theme` prop.
178 |
179 | ```vue
180 |
187 |
188 |
189 | ```
190 |
191 | If you don't pass a value to `theme` it uses the `"default"` theme. You can pass `"dark"` to the theme prop to switch to the `dark` theme. If your theme has other variations, use the name of the variation in this prop.
192 |
193 | ### Override themes
194 |
195 | Auth UI themes can be overridden using variable tokens. See the [list of variable tokens.](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx)
196 |
197 | ```vue
198 |
205 |
206 |
207 |
221 |
222 | ```
223 |
224 | If you created your own theme, you may not need to override any of the them.
225 |
226 | ### Create your own theme
227 |
228 | You can create your own theme by following the same structure within a `appearance.theme` property. See the list of [tokens within a theme.](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx)
229 |
230 | ```vue
231 |
269 |
270 |
271 | ```
272 |
273 | You can switch between different variations of your theme with the ["theme" prop.](#switch-theme-variations)
274 |
275 | ### Custom CSS Classes
276 |
277 | You can use custom CSS classes for the following elements: `"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
278 |
279 | ```vue
280 |
287 |
288 |
289 |
299 |
300 | ```
301 |
302 | ### Custom inline CSS
303 |
304 | You can use custom CSS inline styles for the following elements: `"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`.
305 |
306 | ```vue
307 |
314 |
315 |
316 |
326 |
327 | ```
328 |
329 | ### Custom labels
330 |
331 | There are currently 5 default localization which can be used with the `localization.lang` prop. They are `en`, `ja`, `de_formal`, `de_informal`, `pt_br`.
332 | You can also use custom labels with `localization.variables`. See the [list of labels](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/lib/Localization/en.json) that can be overwritten.
333 |
334 | ```vue
335 |
342 |
343 |
344 |
346 |
347 | ```
348 |
349 |
--------------------------------------------------------------------------------
/auth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boluwatife2904/auth-ui-vue/2fbd8c09587ea4afaaf52c66463540985d9b3106/auth.png
--------------------------------------------------------------------------------
/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "auth-ui-vue",
3 | "version": "0.1.1",
4 | "author": {
5 | "email": "sanvicola2000@gmail.com",
6 | "name": "Sanusi Victor Olajuwon",
7 | "url": "https://sanusi-victor.netlify.app"
8 | },
9 | "description": "Supabase Auth UI is a pre-built Vue component for authenticating users. It supports custom themes and extensible styles to match your brand and aesthetic.",
10 | "keywords": [
11 | "supabase",
12 | "auth",
13 | "ui",
14 | "vue",
15 | "auth-ui",
16 | "authenticate",
17 | "auth-helper"
18 | ],
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/Boluwatife2904/auth-ui-vue"
22 | },
23 | "license": "MIT",
24 | "publishConfig": {
25 | "access": "public"
26 | },
27 | "files": [
28 | "dist"
29 | ],
30 | "main": "./dist/auth-ui-vue.umd.js",
31 | "module": "./dist/auth-ui-vue.es.js",
32 | "exports": {
33 | ".": {
34 | "import": "./dist/auth-ui-vue.es.js",
35 | "require": "./dist/auth-ui-vue.umd.js"
36 | },
37 | "./dist/style.css": "./dist/style.css"
38 | },
39 | "types": "./dist/index.d.ts",
40 | "scripts": {
41 | "dev": "vite",
42 | "build": "run-p type-check build-only",
43 | "preview": "vite preview",
44 | "build-only": "vite build",
45 | "type-check": "vue-tsc --noEmit",
46 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
47 | },
48 | "dependencies": {
49 | "vue": "^3.2.47"
50 | },
51 | "devDependencies": {
52 | "@rushstack/eslint-patch": "^1.2.0",
53 | "@supabase/supabase-js": "^2.21.0",
54 | "@types/node": "^18.16.0",
55 | "@vitejs/plugin-vue": "^4.1.0",
56 | "@vue/eslint-config-prettier": "^7.1.0",
57 | "@vue/eslint-config-typescript": "^11.0.2",
58 | "@vue/tsconfig": "^0.3.2",
59 | "eslint": "^8.39.0",
60 | "eslint-plugin-vue": "^9.11.0",
61 | "npm-run-all": "^4.1.5",
62 | "prettier": "^2.8.8",
63 | "rollup-plugin-typescript2": "^0.34.1",
64 | "sass": "^1.62.0",
65 | "typescript": "~5.0.4",
66 | "vite": "^4.3.1",
67 | "vite-plugin-vue-type-imports": "^0.2.4",
68 | "vue-tsc": "^1.4.4"
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Boluwatife2904/auth-ui-vue/2fbd8c09587ea4afaaf52c66463540985d9b3106/public/favicon.ico
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/assets/scss/abstract/_variables.scss:
--------------------------------------------------------------------------------
1 | // :root {
2 | // --colors-brand: hsl(153 60% 53%);
3 | // --colors-brandAccent: hsl(154 54.8% 45.1%);
4 | // --colors-brandButtonText: white;
5 | // --colors-defaultButtonBackground: white;
6 | // --colors-defaultButtonBackgroundHover: #eaeaea;
7 | // --colors-defaultButtonBorder: lightgray;
8 | // --colors-defaultButtonText: gray;
9 | // --colors-dividerBackground: #eaeaea;
10 | // --colors-dividerBackground: #787676;
11 | // --colors-inputBackground: transparent;
12 | // --colors-inputBorder: lightgray;
13 | // --colors-inputBorderHover: gray;
14 | // --colors-inputBorderFocus: gray;
15 | // --colors-inputText: black;
16 | // --colors-inputLabelText: gray;
17 | // --colors-inputPlaceholder: darkgray;
18 | // --colors-messageText: gray;
19 | // --colors-messageTextDanger: red;
20 | // --colors-anchorTextColor: gray;
21 | // --colors-anchorTextHoverColor: darkgray;
22 | // --space-spaceSmall: 0.4rem;
23 | // --space-spaceMedium: 0.8rem;
24 | // --space-spaceLarge: 1.6rem;
25 | // --space-labelBottomMargin: 0.8rem;
26 | // --space-anchorBottomMargin: 0.4rem;
27 | // --space-emailInputSpacing: 0.4rem;
28 | // --space-socialAuthSpacing: 0.4rem;
29 | // --space-buttonPadding: 1rem 1.5rem;
30 | // --space-inputPadding: 1rem 1.5rem;
31 | // --fontSizes-baseBodySize: 1.3rem;
32 | // --fontSizes-baseInputSize: 1.4rem;
33 | // --fontSizes-baseLabelSize: 1.4rem;
34 | // --fontSizes-baseButtonSize: 1.4rem;
35 | // --fonts-bodyFontFamily: ui-sans-serif, sans-serif;
36 | // --fonts-buttonFontFamily: ui-sans-serif, sans-serif;
37 | // --fonts-inputFontFamily: ui-sans-serif, sans-serif;
38 | // --fonts-labelFontFamily: ui-sans-serif, sans-serif;
39 | // --borderWidths-buttonBorderWidth: 0.1rem;
40 | // --borderWidths-inputBorderWidth: 0.1rem;
41 | // --radii-buttonBorderRadius: 0.4rem;
42 | // --radii-inputBorderRadius: 0.4rem;
43 | // }
44 |
--------------------------------------------------------------------------------
/src/assets/scss/base/_reset.scss:
--------------------------------------------------------------------------------
1 | *,
2 | *::after,
3 | *::before {
4 | margin: 0;
5 | padding: 0;
6 | box-sizing: inherit;
7 | }
8 |
9 | html {
10 | scroll-behavior: smooth;
11 | font-size: 62.5%;
12 | }
13 |
14 | body {
15 | box-sizing: border-box;
16 | font-size: 1.6rem;
17 | }
--------------------------------------------------------------------------------
/src/assets/scss/components/_anchor.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__anchor {
2 | font-family: var(--fonts-bodyFontFamily);
3 | font-size: var(--fontSizes-baseBodySize);
4 | margin-bottom: var(--space-anchorBottomMargin);
5 | color: var(--colors-anchorTextColor);
6 | display: block;
7 | text-align: center;
8 | text-decoration: underline;
9 |
10 | &:hover {
11 | color: var(--colors-anchorTextHoverColor);
12 | }
13 | }
--------------------------------------------------------------------------------
/src/assets/scss/components/_button.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__button {
2 | font-family: var(--fonts-buttonFontFamily);
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | gap: 0.8rem;
7 | border-radius: var(--radii-buttonBorderRadius);
8 | font-size: var(--fontSizes-baseButtonSize);
9 | padding: var(--space-buttonPadding);
10 | cursor: pointer;
11 | border-width: var(--borderWidths-buttonBorderWidth);
12 | border-style: solid;
13 | width: 100%;
14 |
15 | transition-property: background-color, border;
16 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
17 | transition-duration: 300ms;
18 |
19 | &--default {
20 | background-color: var(--colors-defaultButtonBackground);
21 | color: var(--colors-defaultButtonText);
22 | border-color: var(--colors-defaultButtonBorder);
23 |
24 | &:hover {
25 | background-color: var(--colors-defaultButtonBackgroundHover);
26 | }
27 | }
28 |
29 | &--primary {
30 | background-color: var(--colors-brand);
31 | color: var(--colors-brandButtonText);
32 | border-color: var(--colors-brandAccent);
33 |
34 | &:hover {
35 | background-color: var(--colors-brandAccent);
36 | }
37 | }
38 |
39 | &:disabled {
40 | cursor: not-allowed;
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/assets/scss/components/_container.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__container {
2 | gap: 0.4rem;
3 |
4 | &--vertical {
5 | display: flex;
6 | flex-direction: column;
7 | margin: 0.8rem 0;
8 | }
9 |
10 | &--horizontal {
11 | display: grid;
12 | grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
13 | }
14 |
15 | &--gap-small {
16 | gap: 0.4rem;
17 | }
18 |
19 | &--gap-medium {
20 | gap: 0.8rem;
21 | }
22 |
23 | &--gap-large {
24 | gap: 1.6rem;
25 | }
26 |
27 | &--gap-xlarge {
28 | gap: 2rem;
29 | }
30 |
31 | &--gap-xxlarge {
32 | gap: 2.4rem;
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/src/assets/scss/components/_divider.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__divider {
2 | overflow: hidden;
3 | text-align: center;
4 | margin: 1.6rem 0;
5 | font-family: var(--fonts-bodyFontFamily);
6 | font-size: var(--fontSizes-baseBodySize);
7 |
8 | span {
9 | position: relative;
10 | display: inline-block;
11 | color: var(--colors-dividerBackground);
12 |
13 | &::before,
14 | &::after {
15 | content: "";
16 | position: absolute;
17 | top: 50%;
18 | border-bottom: 1px solid var(--colors-dividerBackground);
19 | width: 100vw;
20 | }
21 |
22 | &::before {
23 | right: 100%;
24 | }
25 |
26 | &::left {
27 | left: 100%;
28 | }
29 |
30 | &.has-spacing {
31 | &::before,
32 | &::after {
33 | margin: 0 1rem;
34 | }
35 | }
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/src/assets/scss/components/_input.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__input {
2 | font-family: var(--fonts-inputFontFamily);
3 | background: var(--colors-inputBackground);
4 | border-radius: var(--radii-inputBorderRadius);
5 | padding: var(--space-inputPadding);
6 | cursor: text;
7 | border-width: var(--borderWidths-inputBorderWidth);
8 | border-color: var(--colors-inputBorder);
9 | border-style: solid;
10 | font-size: var(--fontSizes-baseInputSize);
11 | width: 100%;
12 | color: var(--colors-inputText);
13 | box-sizing: border-box;
14 |
15 | &:hover,
16 | &:focus {
17 | outline: none;
18 | }
19 |
20 | &:hover {
21 | border-color: var(--colors-inputBorderHover);
22 | }
23 |
24 | &:focus {
25 | border-color: var(--colors-inputBorderFocus);
26 | }
27 |
28 | &::placeholder {
29 | color: var(--colors-inputPlaceholder);
30 | }
31 |
32 | transition-property: background-color, border;
33 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
34 | transition-duration: 300ms;
35 |
36 | // &[type="password"] {
37 | // letter-spacing: 0.6rem;
38 | // }
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/src/assets/scss/components/_label.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__label {
2 | display: block;
3 | color: var(--colors-inputLabelText);
4 | font-family: var(--fonts-labelFontFamily);
5 | margin-bottom: var(--space-labelBottomMargin);
6 | font-size: var(--fontSizes-baseLabelSize);
7 | }
--------------------------------------------------------------------------------
/src/assets/scss/components/_loader.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__loader {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | display: flex;
6 | align-items: center;
7 | justify-content: center;
8 | height: 100vh;
9 | width: 100vw;
10 | background-color: rgba(91, 91, 91, 0.6);
11 |
12 | &__spinner {
13 | border-radius: 50%;
14 | width: 10rem;
15 | height: 10rem;
16 | font-size: 1rem;
17 | position: relative;
18 | text-indent: -9999rem;
19 |
20 | border-top: 1.1em solid rgba(255, 255, 255, 0.5);
21 | border-right: 1.1em solid rgba(255, 255, 255, 0.5);
22 | border-bottom: 1.1em solid rgba(255, 255, 255, 0.5);
23 | border-left: 1.1em solid #fff;
24 |
25 | &::after {
26 | border-radius: 50%;
27 | width: 10rem;
28 | height: 10rem;
29 | }
30 |
31 | transform: translateZ(0);
32 | -ms-transform: translateZ(0);
33 | -webkit-transform: translateZ(0);
34 | animation: load8 1.1s infinite linear;
35 | -webkit-animation: load8 1.1s infinite linear;
36 |
37 | @-webkit-keyframes load8 {
38 | 0% {
39 | -webkit-transform: rotate(0deg);
40 | transform: rotate(0deg);
41 | }
42 | 100% {
43 | -webkit-transform: rotate(360deg);
44 | transform: rotate(360deg);
45 | }
46 | }
47 | @keyframes load8 {
48 | 0% {
49 | -webkit-transform: rotate(0deg);
50 | transform: rotate(0deg);
51 | }
52 | 100% {
53 | -webkit-transform: rotate(360deg);
54 | transform: rotate(360deg);
55 | }
56 | }
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/src/assets/scss/components/_message.scss:
--------------------------------------------------------------------------------
1 | .auth-ui__message {
2 | font-family: var(--fonts-bodyFontFamily);
3 | font-size: var(--fontSizes-baseBodySize);
4 | margin-bottom: var(--space-labelBottomMargin);
5 | display: block;
6 | text-align: center;
7 |
8 | &--default {
9 | color: var(--colors-messageText);
10 | }
11 |
12 | &--danger {
13 | color: var(--colors-messageTextDanger);
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/src/assets/scss/main.scss:
--------------------------------------------------------------------------------
1 | // ABSTRACT IMPORTS
2 | @import "abstract/variables";
3 |
4 | // BASE IMPORTS
5 | @import "base/reset";
6 |
7 | // COMPONENTS IMPORT
8 | @import "components/input";
9 | @import "components/label";
10 | @import "components/button";
11 | @import "components/message";
12 | @import "components/container";
13 | @import "components/anchor";
14 | @import "components/divider";
15 | @import "components/loader";
--------------------------------------------------------------------------------
/src/components/Auth/Auth.vue:
--------------------------------------------------------------------------------
1 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/components/Auth/interfaces/EmailAuth.vue:
--------------------------------------------------------------------------------
1 |
72 |
73 |
74 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/components/Auth/interfaces/ForgottenPassword.vue:
--------------------------------------------------------------------------------
1 |
44 |
45 |
46 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/components/Auth/interfaces/MagicLink.vue:
--------------------------------------------------------------------------------
1 |
47 |
48 |
49 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/components/Auth/interfaces/SocialAuth.vue:
--------------------------------------------------------------------------------
1 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | {{ i18n[authView as "sign_in" | "sign_up"]?.social_provider_text }} {{ provider.charAt(0).toUpperCase() + provider.slice(1) }}
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/src/components/Auth/interfaces/UpdatePassword.vue:
--------------------------------------------------------------------------------
1 |
41 |
42 |
43 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/components/UI/Anchor.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/components/UI/Button.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/components/UI/Container.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/components/UI/Divider.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 | {{ text }}
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/UI/Input.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/components/UI/Label.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | {{ label }}
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/components/UI/Loader.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/components/UI/Message.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/components/icons/IconApple.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/components/icons/IconAzure.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/components/icons/IconBitBucket.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Bitbucket-blue
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/components/icons/IconDiscord.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/components/icons/IconFacebook.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/components/icons/IconGithub.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/components/icons/IconGitlab.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/components/icons/IconGoogle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/icons/IconKeycloak.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/icons/IconLinkedin.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/components/icons/IconNotion.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/components/icons/IconSlack.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/components/icons/IconSpotify.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/icons/IconTwitch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/icons/IconTwitter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/components/icons/IconWorkos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import Auth from "@/components/Auth/Auth.vue";
2 | import { ThemeSupa } from "@/theming/defaultThemes";
3 |
4 | import "@/assets/scss/main.scss";
5 |
6 | export { Auth, ThemeSupa };
7 |
8 |
--------------------------------------------------------------------------------
/src/localisation/de_formal.json:
--------------------------------------------------------------------------------
1 | {
2 | "sign_up": {
3 | "email_label": "E-Mail Adresse",
4 | "password_label": "Passwort erstellen",
5 | "email_input_placeholder": "Ihre E-Mail Adresse",
6 | "password_input_placeholder": "Ihr Passwort",
7 | "button_label": "Registrieren",
8 | "social_provider_text": "Anmelden mit",
9 | "link_text": "Haben Sie noch kein Konto? Registrieren"
10 | },
11 | "sign_in": {
12 | "email_label": "E-Mail Adresse",
13 | "password_label": "Passwort erstellen",
14 | "email_input_placeholder": "Ihre E-Mail Adresse",
15 | "password_input_placeholder": "Ihr Passwort",
16 | "button_label": "Anmelden",
17 | "social_provider_text": "Anmelden mit",
18 | "link_text": "Haben Sie bereits ein Konto? Anmelden"
19 | },
20 | "magic_link": {
21 | "email_input_label": "E-Mail Adresse",
22 | "email_input_placeholder": "Ihre E-Mail Adresse",
23 | "button_label": "Magischen Link senden",
24 | "link_text": "Einen magischen Link per E-Mail versenden"
25 | },
26 | "forgotten_password": {
27 | "email_label": "E-Mail Adresse",
28 | "password_label": "Ihr Passwort",
29 | "email_input_placeholder": "Ihre E-Mail Adresse",
30 | "button_label": "Anweisungen zum Zurücksetzen des Passworts senden",
31 | "link_text": "Passwort vergessen?"
32 | },
33 | "update_password": {
34 | "password_label": "Neues Passwort",
35 | "password_input_placeholder": "Ihr neues Passwort",
36 | "button_label": "Passwort aktualisieren"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/localisation/de_informal.json:
--------------------------------------------------------------------------------
1 | {
2 | "sign_up": {
3 | "email_label": "E-Mail Adresse",
4 | "password_label": "Passwort erstellen",
5 | "email_input_placeholder": "Deine E-Mail Adresse",
6 | "password_input_placeholder": "Dein Passwort",
7 | "button_label": "Registrieren",
8 | "social_provider_text": "Anmelden mit",
9 | "link_text": "Hast du noch kein Konto? Registrieren"
10 | },
11 | "sign_in": {
12 | "email_label": "E-Mail Adresse",
13 | "password_label": "Passwort erstellen",
14 | "email_input_placeholder": "Deine E-Mail Adresse",
15 | "password_input_placeholder": "Dein Passwort",
16 | "button_label": "Anmelden",
17 | "social_provider_text": "Anmelden mit",
18 | "link_text": "Hast du bereits ein Konto? Anmelden"
19 | },
20 | "magic_link": {
21 | "email_input_label": "E-Mail Adresse",
22 | "email_input_placeholder": "Deine E-Mail Adresse",
23 | "button_label": "Magischen Link senden",
24 | "link_text": "Einen magischen Link per E-Mail versenden"
25 | },
26 | "forgotten_password": {
27 | "email_label": "E-Mail Adresse",
28 | "password_label": "Dein Passwort",
29 | "email_input_placeholder": "Deine E-Mail Adresse",
30 | "button_label": "Anweisungen zum Zurücksetzen des Passworts senden",
31 | "link_text": "Passwort vergessen?"
32 | },
33 | "update_password": {
34 | "password_label": "Neues Passwort",
35 | "password_input_placeholder": "Dein neues Passwort",
36 | "button_label": "Passwort aktualisieren"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/localisation/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "sign_up": {
3 | "email_label": "Email address",
4 | "password_label": "Create a Password",
5 | "email_input_placeholder": "Your email address",
6 | "password_input_placeholder": "Your password",
7 | "button_label": "Sign up",
8 | "social_provider_text": "Sign in with",
9 | "link_text": "Don't have an account? Sign up"
10 | },
11 | "sign_in": {
12 | "email_label": "Email address",
13 | "password_label": "Your Password",
14 | "email_input_placeholder": "Your email address",
15 | "password_input_placeholder": "Your password",
16 | "button_label": "Sign in",
17 | "social_provider_text": "Sign in with",
18 | "link_text": "Already have an account? Sign in"
19 | },
20 | "magic_link": {
21 | "email_input_label": "Email address",
22 | "email_input_placeholder": "Your email address",
23 | "button_label": "Send Magic Link",
24 | "link_text": "Send a magic link email"
25 | },
26 | "forgotten_password": {
27 | "email_label": "Email address",
28 | "password_label": "Your Password",
29 | "email_input_placeholder": "Your email address",
30 | "button_label": "Send reset password instructions",
31 | "link_text": "Forgot your password?",
32 | "remember_password_link_text": "Remember your password? Login"
33 | },
34 | "update_password": {
35 | "password_label": "New password",
36 | "password_input_placeholder": "Your new password",
37 | "button_label": "Update password"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/localisation/index.ts:
--------------------------------------------------------------------------------
1 | export { default as de_formal } from "./de_formal.json";
2 | export { default as de_informal } from "./de_informal.json";
3 | export { default as en } from "./en.json";
4 | export { default as ja } from "./ja.json";
5 | export { default as pt_br } from "./pt_br.json";
6 |
--------------------------------------------------------------------------------
/src/localisation/ja.json:
--------------------------------------------------------------------------------
1 | {
2 | "sign_up": {
3 | "email_label": "電子メールアドレス",
4 | "password_label": "パスワードを作成",
5 | "email_input_placeholder": "Your email address",
6 | "password_input_placeholder": "Your password",
7 | "button_label": "サインアップ",
8 | "social_provider_text": "に登録する",
9 | "link_text": "アカウントをお持ちではありませんか?サインアップ"
10 | },
11 | "sign_in": {
12 | "email_label": "電子メールアドレス",
13 | "password_label": "あなたのパスワード",
14 | "email_input_placeholder": "Your email address",
15 | "password_input_placeholder": "Your password",
16 | "button_label": "サインイン",
17 | "social_provider_text": "に登録する",
18 | "link_text": "Already have an account? Sign in"
19 | },
20 | "magic_link": {
21 | "email_input_label": "Email address",
22 | "email_input_placeholder": "Your email address",
23 | "button_label": "Send Magic Link",
24 | "link_text": "Send a magic link email"
25 | },
26 | "forgotten_password": {
27 | "email_label": "Email address",
28 | "password_label": "Your Password",
29 | "email_input_placeholder": "Your email address",
30 | "button_label": "Send reset password instructions",
31 | "link_text": "パスワードをお忘れの方"
32 | },
33 | "update_password": {
34 | "password_label": "New password",
35 | "password_input_placeholder": "Your new password",
36 | "button_label": "Update password"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/localisation/pt_br.json:
--------------------------------------------------------------------------------
1 | {
2 | "sign_up": {
3 | "email_label": "Endereço de e-mail",
4 | "password_label": "Crie uma senha",
5 | "email_input_placeholder": "Seu endereço de e-mail",
6 | "password_input_placeholder": "Sua senha",
7 | "button_label": "Cadastre-se",
8 | "social_provider_text": "Entrar com",
9 | "link_text": "Não tem uma conta? Cadastre-se"
10 | },
11 | "sign_in": {
12 | "email_label": "Endereço de e-mail",
13 | "password_label": "Crie uma senha",
14 | "email_input_placeholder": "Seu endereço de e-mail",
15 | "password_input_placeholder": "Sua senha",
16 | "button_label": "Entrar",
17 | "social_provider_text": "Entrar com",
18 | "link_text": "Já tem uma conta? Entre"
19 | },
20 | "magic_link": {
21 | "email_input_label": "Endereço de e-mail",
22 | "email_input_placeholder": "Seu endereço de e-mail",
23 | "button_label": "Enviar e-mail com link mágico",
24 | "link_text": "Enviar e-mail com link mágico"
25 | },
26 | "forgotten_password": {
27 | "email_label": "Endereço de e-mail",
28 | "password_label": "Crie uma senha",
29 | "email_input_placeholder": "Seu endereço de e-mail",
30 | "button_label": "Enviar instruções de redefinição de senha",
31 | "link_text": "Esqueceu sua senha?",
32 | "remember_password_link_text": "Lembrou sua senha? Entre"
33 | },
34 | "update_password": {
35 | "password_label": "Nova senha",
36 | "password_input_placeholder": "Sua nova senha",
37 | "button_label": "Atualizar senha"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable vue/no-reserved-component-names */
2 | import { createApp } from "vue";
3 | import App from "@/App.vue";
4 |
5 | import "./assets/scss/main.scss";
6 |
7 | const app = createApp(App);
8 |
9 | app.mount("#app");
10 |
--------------------------------------------------------------------------------
/src/shim-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.vue" {
2 | import type { DefineComponent } from "vue";
3 | const component: DefineComponent<{}, {}, any>;
4 | export default component;
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/src/theming/defaultThemes.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Create default theme
3 | *
4 | * createStitches()
5 | * https://stitches.dev/docs/api#theme
6 | *
7 | * to add a new theme use createTheme({})
8 | * https://stitches.dev/docs/api#theme
9 | */
10 |
11 | import type { Theme } from "@/types";
12 |
13 | // brand: 'hsl(252 62% 55%)',
14 | // brandAccent: 'hsl(252 62% 45%)',
15 |
16 | export const ThemeSupa: Theme = {
17 | default: {
18 | colors: {
19 | brand: "hsl(153 60.0% 53.0%)",
20 | brandAccent: "hsl(154 54.8% 45.1%)",
21 | brandButtonText: "white",
22 | defaultButtonBackground: "white",
23 | defaultButtonBackgroundHover: "#eaeaea",
24 | defaultButtonBorder: "lightgray",
25 | defaultButtonText: "gray",
26 | dividerBackground: "#eaeaea",
27 | inputBackground: "transparent",
28 | inputBorder: "lightgray",
29 | inputBorderHover: "gray",
30 | inputBorderFocus: "gray",
31 | inputText: "black",
32 | inputLabelText: "gray",
33 | inputPlaceholder: "darkgray",
34 | messageText: "gray",
35 | messageTextDanger: "red",
36 | anchorTextColor: "gray",
37 | anchorTextHoverColor: "darkgray",
38 | },
39 | space: {
40 | spaceSmall: "4px",
41 | spaceMedium: "8px",
42 | spaceLarge: "16px",
43 | labelBottomMargin: "8px",
44 | anchorBottomMargin: "4px",
45 | emailInputSpacing: "4px",
46 | socialAuthSpacing: "4px",
47 | buttonPadding: "10px 15px",
48 | inputPadding: "10px 15px",
49 | },
50 | fontSizes: {
51 | baseBodySize: "13px",
52 | baseInputSize: "14px",
53 | baseLabelSize: "14px",
54 | baseButtonSize: "14px",
55 | },
56 | fonts: {
57 | bodyFontFamily: `ui-sans-serif, sans-serif`,
58 | buttonFontFamily: `ui-sans-serif, sans-serif`,
59 | inputFontFamily: `ui-sans-serif, sans-serif`,
60 | labelFontFamily: `ui-sans-serif, sans-serif`,
61 | },
62 | // fontWeights: {},
63 | // lineHeights: {},
64 | // letterSpacings: {},
65 | // sizes: {},
66 | borderWidths: {
67 | buttonBorderWidth: "1px",
68 | inputBorderWidth: "1px",
69 | },
70 | // borderStyles: {},
71 | radii: {
72 | buttonBorderRadius: "4px",
73 | inputBorderRadius: "4px",
74 | },
75 | // shadows: {},
76 | // zIndices: {},
77 | // transitions: {},
78 | },
79 | dark: {
80 | colors: {
81 | brandButtonText: "white",
82 | defaultButtonBackground: "#2e2e2e",
83 | defaultButtonBackgroundHover: "#3e3e3e",
84 | defaultButtonBorder: "#3e3e3e",
85 | defaultButtonText: "white",
86 | dividerBackground: "#2e2e2e",
87 | inputBackground: "#1e1e1e",
88 | inputBorder: "#3e3e3e",
89 | inputBorderHover: "gray",
90 | inputBorderFocus: "gray",
91 | inputText: "white",
92 | inputPlaceholder: "darkgray",
93 | },
94 | },
95 | };
96 |
97 | export const ThemeMinimal: Theme = {
98 | default: {
99 | colors: {
100 | brand: "black",
101 | brandAccent: "#333333",
102 | brandButtonText: "white",
103 | defaultButtonBackground: "white",
104 | defaultButtonBorder: "lightgray",
105 | defaultButtonText: "gray",
106 | dividerBackground: "#eaeaea",
107 | inputBackground: "transparent",
108 | inputBorder: "lightgray",
109 | inputText: "black",
110 | inputPlaceholder: "darkgray",
111 | },
112 | space: {
113 | spaceSmall: "4px",
114 | spaceMedium: "8px",
115 | spaceLarge: "16px",
116 | },
117 | fontSizes: {
118 | baseInputSize: "14px",
119 | baseLabelSize: "12px",
120 | },
121 | fonts: {
122 | bodyFontFamily: "",
123 | inputFontFamily: "",
124 | buttonFontFamily: "",
125 | labelFontFamily: "",
126 | // linkFontFamily: '',
127 | },
128 | // fontWeights: {},
129 | // lineHeights: {},
130 | // letterSpacings: {},
131 | // sizes: {},
132 | borderWidths: {},
133 | // borderStyles: {},
134 | radii: {},
135 | // shadows: {},
136 | // zIndices: {},
137 | // transitions: {},
138 | },
139 | dark: {
140 | colors: {
141 | brand: "white",
142 | brandAccent: "#afafaf",
143 | brandButtonText: "black",
144 | defaultButtonBackground: "#080808",
145 | defaultButtonBorder: "black",
146 | defaultButtonText: "white",
147 | dividerBackground: "black",
148 | inputBackground: "transparent",
149 | inputBorder: "gray",
150 | inputText: "black",
151 | inputPlaceholder: "darkgray",
152 | },
153 | },
154 | };
155 |
156 |
--------------------------------------------------------------------------------
/src/theming/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./themes";
2 | export * from "./types";
3 |
--------------------------------------------------------------------------------
/src/theming/themes.ts:
--------------------------------------------------------------------------------
1 | import type { ThemeVariables } from "./types";
2 |
3 | // brand: 'hsl(252 62% 55%)',
4 | // brandAccent: 'hsl(252 62% 45%)',
5 |
6 | const supabase: ThemeVariables = {
7 | colors: {
8 | brand: "hsl(153 60.0% 53.0%)",
9 | brandAccent: "hsl(154 54.8% 45.1%)",
10 | brandButtonText: "white",
11 | defaultButtonBackground: "white",
12 | defaultButtonBackgroundHover: "#eaeaea",
13 | defaultButtonBorder: "lightgray",
14 | defaultButtonText: "gray",
15 | dividerBackground: "#eaeaea",
16 | inputBackground: "transparent",
17 | inputBorder: "lightgray",
18 | inputBorderHover: "gray",
19 | inputBorderFocus: "gray",
20 | inputText: "black",
21 | inputLabelText: "gray",
22 | inputPlaceholder: "darkgray",
23 | messageText: "gray",
24 | messageTextDanger: "red",
25 | anchorTextColor: "gray",
26 | anchorTextHoverColor: "darkgray",
27 | },
28 | space: {
29 | spaceSmall: "4px",
30 | spaceMedium: "8px",
31 | spaceLarge: "16px",
32 | labelBottomMargin: "8px",
33 | anchorBottomMargin: "4px",
34 | emailInputSpacing: "4px",
35 | socialAuthSpacing: "4px",
36 | buttonPadding: "10px 15px",
37 | inputPadding: "10px 15px",
38 | },
39 | fontSizes: {
40 | baseBodySize: "13px",
41 | baseInputSize: "14px",
42 | baseLabelSize: "14px",
43 | baseButtonSize: "14px",
44 | },
45 | fonts: {
46 | bodyFontFamily: `ui-sans-serif, sans-serif`,
47 | buttonFontFamily: `ui-sans-serif, sans-serif`,
48 | inputFontFamily: `ui-sans-serif, sans-serif`,
49 | labelFontFamily: `ui-sans-serif, sans-serif`,
50 | },
51 | borderWidths: {
52 | buttonBorderWidth: "1px",
53 | inputBorderWidth: "1px",
54 | },
55 | radii: {
56 | buttonBorderRadius: "4px",
57 | inputBorderRadius: "4px",
58 | },
59 | };
60 |
61 | const defaultDarkTheme: ThemeVariables = {
62 | colors: {
63 | brandButtonText: "white",
64 | defaultButtonBackground: "#2e2e2e",
65 | defaultButtonBackgroundHover: "#3e3e3e",
66 | defaultButtonBorder: "#3e3e3e",
67 | defaultButtonText: "white",
68 | dividerBackground: "#2e2e2e",
69 | inputBackground: "#1e1e1e",
70 | inputBorder: "#3e3e3e",
71 | inputBorderHover: "gray",
72 | inputBorderFocus: "gray",
73 | inputText: "white",
74 | inputPlaceholder: "darkgray",
75 | },
76 | };
77 |
78 | const minimal: ThemeVariables = {
79 | colors: {
80 | brand: "black",
81 | brandAccent: "#333333",
82 | brandButtonText: "white",
83 | defaultButtonBackground: "white",
84 | defaultButtonBorder: "lightgray",
85 | defaultButtonText: "gray",
86 | dividerBackground: "#eaeaea",
87 | inputBackground: "transparent",
88 | inputBorder: "lightgray",
89 | inputText: "black",
90 | inputPlaceholder: "darkgray",
91 | },
92 | space: {
93 | spaceSmall: "4px",
94 | spaceMedium: "8px",
95 | spaceLarge: "16px",
96 | },
97 | fontSizes: {
98 | baseInputSize: "14px",
99 | baseLabelSize: "12px",
100 | },
101 | fonts: {
102 | bodyFontFamily: "",
103 | inputFontFamily: "",
104 | buttonFontFamily: "",
105 | labelFontFamily: "",
106 | // linkFontFamily: '',
107 | },
108 | // fontWeights: {},
109 | // lineHeights: {},
110 | // letterSpacings: {},
111 | // sizes: {},
112 | borderWidths: {},
113 | // borderStyles: {},
114 | radii: {},
115 | // shadows: {},
116 | // zIndices: {},
117 | // transitions: {},
118 | };
119 |
120 | const minimalDark: ThemeVariables = {
121 | colors: {
122 | brand: "white",
123 | brandAccent: "#afafaf",
124 | brandButtonText: "black",
125 | defaultButtonBackground: "#080808",
126 | defaultButtonBorder: "black",
127 | defaultButtonText: "white",
128 | dividerBackground: "black",
129 | inputBackground: "transparent",
130 | inputBorder: "gray",
131 | inputText: "black",
132 | inputPlaceholder: "darkgray",
133 | },
134 | };
135 |
136 | const darkThemes = {
137 | supabase: defaultDarkTheme,
138 | minimal: minimalDark,
139 | };
140 |
141 | export { supabase, minimal, darkThemes };
142 |
143 |
--------------------------------------------------------------------------------
/src/theming/types.ts:
--------------------------------------------------------------------------------
1 | export type ThemeVariables = {
2 | colors?: {
3 | brand?: string;
4 | brandAccent?: string;
5 | brandButtonText?: string;
6 | defaultButtonBackground?: string;
7 | defaultButtonBackgroundHover?: string;
8 | defaultButtonBorder?: string;
9 | defaultButtonText?: string;
10 | dividerBackground?: string;
11 | inputBackground?: string;
12 | inputBorder?: string;
13 | inputBorderFocus?: string;
14 | inputBorderHover?: string;
15 | inputLabelText?: string;
16 | inputPlaceholder?: string;
17 | inputText?: string;
18 | messageText?: string;
19 | messageTextDanger?: string;
20 | anchorTextColor?: string;
21 | anchorTextHoverColor?: string;
22 | };
23 | space?: {
24 | spaceSmall?: string;
25 | spaceMedium?: string;
26 | spaceLarge?: string;
27 | labelBottomMargin?: string;
28 | anchorBottomMargin?: string;
29 | emailInputSpacing?: string;
30 | socialAuthSpacing?: string;
31 | buttonPadding?: string;
32 | inputPadding?: string;
33 | };
34 | fontSizes?: {
35 | baseBodySize?: string;
36 | baseInputSize?: string;
37 | baseLabelSize?: string;
38 | baseButtonSize?: string;
39 | };
40 | fonts?: {
41 | bodyFontFamily?: string;
42 | buttonFontFamily?: string;
43 | inputFontFamily?: string;
44 | labelFontFamily?: string;
45 | };
46 | borderWidths?: {
47 | buttonBorderWidth?: string;
48 | inputBorderWidth?: string;
49 | };
50 | radii?: {
51 | buttonBorderRadius?: string;
52 | inputBorderRadius?: string;
53 | };
54 | };
55 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | import type { Ref } from "vue";
2 | import type { ThemeVariables } from "@/theming";
3 | import type { SupabaseClient, Provider } from "@supabase/supabase-js";
4 |
5 | export type ViewSignIn = "sign_in";
6 | export type ViewSignUp = "sign_up";
7 | export type ViewMagicLink = "magic_link";
8 | export type ViewForgottenPassword = "forgotten_password";
9 | export type ViewUpdatePassword = "update_password";
10 |
11 | export type ViewType = "sign_in" | "sign_up" | "magic_link" | "forgotten_password" | "update_password";
12 |
13 | export type SocialLayout = "vertical" | "horizontal";
14 |
15 | export type AuthProviders = Provider[];
16 |
17 | export type I18nVariables = {
18 | sign_up?: {
19 | email_label?: string;
20 | password_label?: string;
21 | email_input_placeholder?: string;
22 | password_input_placeholder?: string;
23 | button_label?: string;
24 | social_provider_text?: string;
25 | link_text?: string;
26 | };
27 | sign_in?: {
28 | email_label?: string;
29 | password_label?: string;
30 | email_input_placeholder?: string;
31 | password_input_placeholder?: string;
32 | button_label?: string;
33 | social_provider_text?: string;
34 | link_text?: string;
35 | };
36 | magic_link?: {
37 | email_input_label?: string;
38 | email_input_placeholder?: string;
39 | button_label?: string;
40 | link_text?: string;
41 | };
42 | forgotten_password?: {
43 | email_label?: string;
44 | password_label?: string;
45 | email_input_placeholder?: string;
46 | button_label?: string;
47 | link_text?: string;
48 | };
49 | update_password?: {
50 | password_label?: string;
51 | password_input_placeholder?: string;
52 | button_label?: string;
53 | };
54 | };
55 |
56 | export interface Theme {
57 | default: ThemeVariables;
58 | [key: string]: ThemeVariables;
59 | }
60 |
61 | export interface Appearance {
62 | theme?: Theme;
63 | prependedClassName?: string;
64 | variables?: {
65 | default: ThemeVariables;
66 | [key: string]: ThemeVariables;
67 | };
68 | className?: {
69 | anchor?: string;
70 | button?: string;
71 | container?: string;
72 | divider?: string;
73 | input?: string;
74 | label?: string;
75 | loader?: string;
76 | message?: string;
77 | };
78 | style?: {
79 | anchor?: any;
80 | button?: any;
81 | container?: any;
82 | divider?: any;
83 | input?: any;
84 | label?: any;
85 | loader?: any;
86 | message?: any;
87 | };
88 | }
89 |
90 | export interface Localization {
91 | // [key: string]: I18nVariables;
92 | ["en"]: I18nVariables;
93 | ["ja"]: I18nVariables;
94 | ["de_formal"]: I18nVariables;
95 | ["de_informal"]: I18nVariables;
96 | ["pt_br"]: I18nVariables;
97 | }
98 |
99 | export interface AuthProps {
100 | supabaseClient: SupabaseClient; // Supabase Client
101 | socialLayout?: SocialLayout; // This determines how the social providers show be displayed
102 | providers?: AuthProviders; // This is a list of social providers to be used
103 | view?: ViewType; // This determines the type of auth component to be shown
104 | redirectTo?: undefined | string; // This will determine where to redirect the user to after some auth operations
105 | onlyThirdPartyProviders?: boolean; // This will toggle if to show just the social providers without the EmailAuth component
106 | magicLink?: boolean; // This will toggle the 'Send magic link' on the links
107 | showLinks?: boolean; // This will toggle the links on the auth component to change the auth view
108 | /**
109 | * This will toggle on the dark variation of the theme
110 | */
111 | dark?: boolean;
112 | /**
113 | * Override the labels and button text
114 | */
115 | localization?: {
116 | lang?: "en" | "ja" | "de_formal" | "de_informal" | "pt_br";
117 | variables?: I18nVariables;
118 | };
119 | appearance?: Appearance;
120 | theme?: "default" | string;
121 | }
122 |
123 | export interface ViewProps {
124 | authView: Ref;
125 | changeView: (view: ViewType) => void;
126 | }
127 |
128 | export interface LoadingProps {
129 | setIsLoading: (value: boolean) => void;
130 | }
131 |
132 | export interface AuthEmits {
133 | (event: "set-loading", value: boolean): void;
134 | (event: "signin-completed", data: any): void;
135 | (event: "signup-completed", data: any): void;
136 | (event: "magic-link-sent"): void;
137 | (event: "forgotten-password-completed"): void;
138 | (event: "update-password-completed"): void;
139 | }
140 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | function value(src: any, next: any) {
2 | let k;
3 | if (src && next && typeof src === "object" && typeof next === "object") {
4 | if (Array.isArray(next)) {
5 | for (k = 0; k < next.length; k++) {
6 | src[k] = value(src[k], next[k]);
7 | }
8 | } else {
9 | for (k in next) {
10 | src[k] = value(src[k], next[k]);
11 | }
12 | }
13 | return src;
14 | }
15 | return next;
16 | }
17 |
18 | export function merge(target: any, ...args: any) {
19 | const len: number = args.length;
20 | for (let i = 0; i < len; i++) {
21 | target = value(target, args[i]);
22 | }
23 | return target;
24 | }
25 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "baseUrl": "./",
7 | "paths": {
8 | "@/*": ["src/*", "./dist/*"]
9 | },
10 | "moduleResolution": "Node",
11 | "strict": true,
12 | "jsx": "preserve",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "esModuleInterop": true,
16 | "lib": ["ESNext", "DOM"],
17 | "skipLibCheck": true,
18 | "noEmit": true
19 | },
20 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
21 | "references": [{ "path": "./tsconfig.node.json" }]
22 | }
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from "node:url";
2 | import { resolve } from "path";
3 |
4 | import { defineConfig } from "vite";
5 | import vue from "@vitejs/plugin-vue";
6 | import VueTypeImports from "vite-plugin-vue-type-imports";
7 | import typescript2 from "rollup-plugin-typescript2"
8 | // https://vitejs.dev/config/
9 | export default defineConfig({
10 | build: {
11 | lib: {
12 | // Could also be a dictionary or array of multiple entry points
13 | entry: resolve(__dirname, "src/index.ts"),
14 | name: "auth-ui-vue",
15 | // the proper extensions will be added
16 | fileName: (format) => `auth-ui-vue.${format}.js`,
17 | },
18 | rollupOptions: {
19 | // make sure to externalize deps that shouldn't be bundled
20 | // into your library
21 | external: ["vue"],
22 | output: {
23 | // Provide global variables to use in the UMD build
24 | // for externalized deps
25 | globals: {
26 | vue: "Vue",
27 | },
28 | },
29 | },
30 | },
31 | plugins: [vue(), VueTypeImports(), typescript2({
32 | check: false,
33 | include: ["src/components/**/*.vue", 'src/index.ts'],
34 | tsconfigOverride: {
35 | compilerOptions: {
36 | outDir: "dist",
37 | sourceMap: true,
38 | declaration: true,
39 | declarationMap: true,
40 | },
41 | },
42 | exclude: ["vite.config.ts"]
43 | })],
44 | resolve: {
45 | alias: {
46 | "@": fileURLToPath(new URL("./src", import.meta.url)),
47 | },
48 | },
49 | });
50 |
--------------------------------------------------------------------------------