Skip to content

Commit

Permalink
Merge pull request #9 from zernonia/2-component-auth-ui
Browse files Browse the repository at this point in the history
feat: Auth UI component
  • Loading branch information
zernonia authored May 12, 2023
2 parents 89edc77 + 49300b1 commit 4bf3818
Show file tree
Hide file tree
Showing 15 changed files with 352 additions and 0 deletions.
7 changes: 7 additions & 0 deletions components/Lego/Auth/.keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { InjectionKey, Ref } from "vue";
import type { Provider } from "./.types";

export const rootKey = Symbol() as InjectionKey<{
hideProviderLabel?: boolean;
providers?: Provider[];
}>;
12 changes: 12 additions & 0 deletions components/Lego/Auth/.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type Provider =
| "facebook"
| "twitter"
| "google"
| "discord"
| "github"
| "gitlab"
| "apple"
| "slack"
| "azure"
| "bitbucket"
| "tiktok";
23 changes: 23 additions & 0 deletions components/Lego/Auth/Form.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
const emits = defineEmits<{
(e: "submit", payload: { [key: string]: any }): void;
}>();
const handleSignIn = (ev: Event) => {
ev.preventDefault();
const form = ev.target as HTMLFormElement;
if (!form) return;
const formData = new FormData(form);
emits(
"submit",
Object.fromEntries(formData) as { email: string; password?: string }
);
};
</script>

<template>
<form @submit="handleSignIn">
<slot />
</form>
</template>
7 changes: 7 additions & 0 deletions components/Lego/Auth/Form/Button.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script setup lang="ts">
defineProps<{ label?: string }>();
</script>

<template>
<input type="submit" style="cursor: pointer" :value="label ?? 'Sign In'">
</template>
23 changes: 23 additions & 0 deletions components/Lego/Auth/Form/InputText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import type { InputHTMLAttributes } from "vue";
interface Props extends InputHTMLAttributes {
label: string;
name: string;
type: string;
}
defineProps<Props>();
</script>
<script lang="ts">
export default {
inheritAttrs: false,
};
</script>

<template>
<div>
<label :for="name">{{ label }}</label>
<input v-bind="$attrs" :id="name" required :type="type" :name="name">
</div>
</template>
12 changes: 12 additions & 0 deletions components/Lego/Auth/Header.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script setup lang="ts"></script>

<template>
<div>
<slot name="logo" />

<slot>
<h2>Create your account</h2>
<p>to continue to Acme</p>
</slot>
</div>
</template>
38 changes: 38 additions & 0 deletions components/Lego/Auth/SocialProvider.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script setup lang="ts">
import { rootKey } from "./.keys";
import type { Provider } from "./.types";
const rootProps = inject(rootKey);
const props = defineProps<{
provider: Provider;
}>();
const emits = defineEmits<{
(e: "select", payload: Provider): void;
}>();
const providerInfo = {
facebook: { title: "Facebook", icon: "logos:facebook" },
twitter: { title: "Twitter", icon: "logos:twitter" },
google: { title: "Google", icon: "logos:google-icon" },
discord: { title: "Discord", icon: "logos:discord-icon" },
github: { title: "GitHub", icon: "devicon:github" },
gitlab: { title: "gitlab", icon: "devicon:gitlab" },
apple: { title: "apple", icon: "devicon:apple" },
slack: { title: "slack", icon: "devicon:slack" },
azure: { title: "azure", icon: "devicon:azure" },
bitbucket: { title: "bitbucket", icon: "devicon:bitbucket" },
tiktok: { title: "TikTok", icon: "logos-tiktok-icon" },
};
const mappedProvider = computed(() => providerInfo[props.provider]);
</script>

<template>
<button @click="emits('select', provider)">
<Icon :name="mappedProvider.icon" />
<div v-if="!rootProps?.hideProviderLabel">
<slot> Sign in with {{ mappedProvider.title }} </slot>
</div>
</button>
</template>
24 changes: 24 additions & 0 deletions components/Lego/Auth/SocialProviders.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup lang="ts">
import { rootKey } from "./.keys";
import type { Provider } from "./.types";
const rootProps = inject(rootKey);
const emits = defineEmits<{
(e: "select", payload: Provider): void;
}>();
</script>
<script lang="ts">
export default {
inheritAttrs: false,
};
</script>

<template>
<LegoAuthSocialProvider
v-for="provider in rootProps?.providers"
v-bind="$attrs"
:key="provider"
:provider="provider"
@select="emits('select', $event)"
/>
</template>
41 changes: 41 additions & 0 deletions components/Lego/Auth/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script setup lang="ts">
import { rootKey } from "./.keys";
import type { Provider } from "./.types";
const props = defineProps<{
hideProviderLabel?: boolean;
providers?: Provider[];
}>();
provide(rootKey, props);
</script>

<template>
<div>
<slot>
<LegoAuthHeader />

<LegoAuthSocialProvider provider="google" />
<LegoAuthSocialProvider provider="facebook" />
<LegoAuthSocialProvider provider="twitter" />
<LegoAuthSocialProvider provider="github" />
<LegoAuthSocialProvider provider="tiktok" />
<LegoAuthSocialProvider provider="azure" />

<LegoAuthForm>
<LegoAuthFormInputText
name="email"
type="email"
label="Email Address"
/>
<LegoAuthFormInputText
name="password"
type="password"
label="Password"
/>

<LegoAuthFormButton />
</LegoAuthForm>
</slot>
</div>
</template>
60 changes: 60 additions & 0 deletions website/components/AuthUi/Demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script setup lang="ts">
const handleSelectProvider = (provider: string) => {
// return the selected provider
};
const handleSubmit = (payload: { [key: string]: any }) => {
// in this case payload will return { email: string, password: string }
};
</script>

<template>
<LegoAuth
class="max-w-96 w-full bg-white border rounded-2xl px-8 py-10 shadow-sm"
:hide-provider-label="true"
:providers="['twitter', 'google', 'facebook']"
>
<LegoAuthHeader>
<template #logo>
<img src="/logo.svg" alt="NuxtLego" class="w-10">
</template>

<h2 class="mt-4 font-semibold text-xl">Create your account</h2>
<p class="text-gray-400 text-sm mt-1">to continue to NuxtLego</p>
</LegoAuthHeader>

<div class="flex space-x-2 w-full mt-8">
<LegoAuthSocialProviders
class="w-full px-4 py-3 border bg-white hover:bg-gray-50 transition rounded-lg flex justify-center"
@select="handleSelectProvider"
/>
</div>

<LegoAuthForm class="mt-10 text-sm" @submit="handleSubmit">
<LegoAuthFormInputText
name="email"
type="email"
label="Email Address"
class="block border w-full outline-blue-400 px-4 py-2 rounded-lg mt-1 mb-2"
/>
<LegoAuthFormInputText
name="password"
type="password"
label="Password"
class="block border w-full outline-blue-400 px-4 py-2 rounded-lg mt-1 mb-2"
/>

<LegoAuthFormButton
label="Continue"
class="bg-blue-400 hover:bg-blue-500 transition mt-2 px-4 py-2.5 rounded-lg w-full text-sm text-white"
/>
</LegoAuthForm>

<div class="mt-10 text-sm text-gray-400">
Have an account?
<NuxtLink class="text-blue-400 hover:text-blue-500 underline" to="/">
Sign In
</NuxtLink>
</div>
</LegoAuth>
</template>
40 changes: 40 additions & 0 deletions website/components/AuthUi/Showcase.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script setup lang="ts"></script>

<template>
<ShowcaseCard class="group" to="/docs/components/auth-ui">
<template #image>
<div>
<div
class="absolute top-16 group-hover:top-14 right-24 group-hover:right-22 text-4xl text-blue-200 group-hover:text-blue-400 transition-all"
>
<Icon name="ion:logo-facebook" />
</div>
<div
class="absolute top-16 group-hover:top-14 left-24 group-hover:left-22 text-4xl text-blue-200 group-hover:text-blue-400 transition-all"
>
<Icon name="ion:logo-google" />
</div>
<div
class="absolute top-10 group-hover:top-8 left-38 group-hover:left-36 text-4xl text-blue-200 group-hover:text-blue-400 transition-all"
>
<Icon name="ion:logo-github" />
</div>
<div
class="absolute top-10 group-hover:top-8 right-38 group-hover:right-36 text-4xl text-blue-200 group-hover:text-blue-400 transition-all"
>
<Icon name="ion:logo-twitter" />
</div>
<div
class="bg-white relative z-10 bg-white mt-20 w-40 h-12 text-gray-300 group-hover:text-blue-400 transition text-sm border border-gray-200 group-hover:border-blue-400 rounded-xl flex items-center justify-center"
>
Sign Up
</div>
</div>
</template>

<h5 class="font-semibold">Auth UI</h5>
<p class="text-sm mt-1 text-gray-400">
Primitive Auth UI with Social Providers and Native Form.
</p>
</ShowcaseCard>
</template>
1 change: 1 addition & 0 deletions website/components/Showcase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<SocialShareShowcase />
<StaticTweetShowcase />
<WebsiteCardShowcase />
<AuthUiShowcase />
<TocShowcase />
<PageProgressShowcase />
</div>
Expand Down
64 changes: 64 additions & 0 deletions website/content/docs/2.components/4.auth-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: Auth UI
description: Primitive Auth UI with Social Providers and Native Form.
---

::code-example
#preview
:auth-ui-demo
#code
codegen{src="website/components/AuthUi/Demo.vue" lang="vue"}
::

##### Available Providers

- Facebook
- Twitter
- Google
- Discord
- GitHub
- GitLab
- Apple
- Slack
- Azure
- Bitbucket
- Tiktok

## Anatomy

```vue
<template>
<LegoAuth
:hide-provider-label="true"
:providers="['twitter', 'google', 'facebook']"
>
<LegoAuthHeader />
<LegoAuthSocialProviders @select="handleSelectProvider" />
<LegoAuthForm @submit="handleSubmit">
<LegoAuthFormInputText />
<LegoAuthFormButton />
</LegoAuthForm>
</LegoAuth>
</template>
```

## API Reference

### Root

Wrapper that provide the information required for the child component.

| Prop | Default | Types | Description |
| ----------------- | ------- | ------------ | ----------------------------------------- |
| providers | - | `Provider[]` | List the social providers you need |
| hideProviderLabel | - | `boolean` | Hide the label for social provider button |

### Event

| Name | Component | Payload | Description |
| ------- | ----------------------- | ---------------- | ---------------------------------------------- |
| @select | LegoAuthSocialProviders | `Provider` | Event triggered when selecting social provider |
| @submit | LegoAuthForm | `{ [key]: any }` | Event triggered when click on |

1 comment on commit 4bf3818

@vercel
Copy link

@vercel vercel bot commented on 4bf3818 May 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nuxt-lego – ./

nuxt-lego.vercel.app
nuxt-lego-zernonia.vercel.app
nuxt-lego-git-main-zernonia.vercel.app

Please sign in to comment.