Files
nuxt-claude/app/pages/login.vue
NEW_GIL_HOME\hyeon d594bf5a67
Some checks failed
ci / ci (22, ubuntu-latest) (push) Failing after 26m43s
feat: add MCP configuration and update login page design
- Introduced a new `.mcp.json` file for server configurations.
- Updated `package.json` to include the `shadcn` dependency.
- Modified `pnpm-lock.yaml` to reflect the new dependency.
- Adjusted `.claude/settings.local.json` to disable specific MCP servers.
- Enhanced the login page design in `login.vue` with improved layout and user experience elements.
2026-03-08 17:26:33 +09:00

258 lines
8.3 KiB
Vue

<script setup lang="ts">
definePageMeta({ layout: false });
const supabase = useSupabaseClient();
const email = ref("");
const loading = ref(false);
const message = ref("");
const error = ref("");
async function sendMagicLink() {
if (!email.value) return;
loading.value = true;
error.value = "";
message.value = "";
const { error: err } = await supabase.auth.signInWithOtp({
email: email.value,
options: {
emailRedirectTo: `${window.location.origin}/confirm`,
},
});
loading.value = false;
if (err) {
error.value = err.message;
} else {
message.value = `${email.value}로 로그인 링크를 전송했습니다. 이메일을 확인해주세요.`;
}
}
async function signInWithGoogle() {
await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: `${window.location.origin}/confirm`,
},
});
}
</script>
<template>
<UApp>
<div class="min-h-screen flex">
<!-- 좌측 브랜딩 패널 (데스크탑에서만 표시) -->
<div
class="hidden lg:flex lg:w-1/2 relative overflow-hidden bg-gradient-to-br from-green-500 via-emerald-600 to-green-800 flex-col justify-between p-12"
>
<!-- 배경 패턴 -->
<div class="absolute inset-0 opacity-10">
<div
class="absolute top-0 left-0 w-64 h-64 rounded-full bg-white -translate-x-1/2 -translate-y-1/2"
/>
<div
class="absolute bottom-0 right-0 w-96 h-96 rounded-full bg-white translate-x-1/3 translate-y-1/3"
/>
<div
class="absolute top-1/2 left-1/2 w-48 h-48 rounded-full bg-white -translate-x-1/2 -translate-y-1/2"
/>
</div>
<!-- 로고 -->
<div class="relative z-10 flex items-center gap-3">
<div
class="w-10 h-10 rounded-xl bg-white/20 backdrop-blur flex items-center justify-center"
>
<UIcon name="i-lucide-tent" class="text-white text-xl" />
</div>
<span class="text-white text-xl font-bold tracking-tight"
>CampGear</span
>
</div>
<!-- 메인 카피 -->
<div class="relative z-10 space-y-6">
<div class="space-y-3">
<h2 class="text-4xl font-bold text-white leading-tight">
캠핑의 모든 ,<br /> 곳에서 관리하세요
</h2>
<p class="text-green-100 text-lg leading-relaxed">
장비 구매부터 중고 거래까지,<br />스마트한 캠핑 장비 관리를
경험하세요.
</p>
</div>
<!-- 기능 목록 -->
<div class="space-y-3">
<div
v-for="feature in [
{ icon: 'i-lucide-package', text: '장비 구매 내역 관리' },
{ icon: 'i-lucide-repeat', text: '중고 장비 판매 · 추적' },
{ icon: 'i-lucide-bot', text: 'AI 캠핑 어시스턴트' },
]"
:key="feature.text"
class="flex items-center gap-3"
>
<div
class="w-8 h-8 rounded-lg bg-white/20 flex items-center justify-center flex-shrink-0"
>
<UIcon :name="feature.icon" class="text-white text-sm" />
</div>
<span class="text-green-50 text-sm font-medium">{{
feature.text
}}</span>
</div>
</div>
</div>
<!-- 하단 문구 -->
<div class="relative z-10">
<p class="text-green-200 text-sm">
&copy; 2026 CampGear. All rights reserved.
</p>
</div>
</div>
<!-- 우측 로그인 폼 -->
<div
class="flex-1 flex items-center justify-center p-6 sm:p-12 bg-white dark:bg-gray-950"
>
<div class="w-full max-w-sm space-y-8">
<!-- 모바일용 로고 -->
<div class="lg:hidden text-center space-y-2">
<div
class="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-green-500 mb-2"
>
<UIcon name="i-lucide-tent" class="text-white text-2xl" />
</div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
CampGear
</h1>
<p class="text-gray-500 dark:text-gray-400 text-sm">
캠핑 장비 관리 앱
</p>
</div>
<!-- 폼 헤더 -->
<div class="space-y-1">
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">
로그인
</h2>
<p class="text-gray-500 dark:text-gray-400 text-sm">
계속하려면 이메일을 입력하거나 Google 계정으로 로그인하세요.
</p>
</div>
<!-- 로그인 폼 -->
<div class="space-y-4">
<!-- Google 로그인 -->
<UButton
color="neutral"
variant="outline"
class="w-full"
size="lg"
@click="signInWithGoogle"
>
<template #leading>
<UIcon name="i-simple-icons-google" class="text-base" />
</template>
Google로 계속하기
</UButton>
<!-- 구분선 -->
<div class="relative flex items-center gap-3">
<div class="flex-1 h-px bg-gray-200 dark:bg-gray-800" />
<span class="text-xs text-gray-400 dark:text-gray-500 font-medium"
>또는 이메일로</span
>
<div class="flex-1 h-px bg-gray-200 dark:bg-gray-800" />
</div>
<!-- 이메일 입력 -->
<div class="space-y-3">
<UFormField name="email">
<UInput
v-model="email"
type="email"
placeholder="your@email.com"
size="lg"
class="w-full"
:ui="{ base: 'w-full' }"
@keyup.enter="sendMagicLink"
>
<template #leading>
<UIcon name="i-lucide-mail" class="text-gray-400" />
</template>
</UInput>
</UFormField>
<UButton
color="primary"
class="w-full"
size="lg"
:loading="loading"
@click="sendMagicLink"
>
<template #leading>
<UIcon
v-if="!loading"
name="i-lucide-send"
class="text-base"
/>
</template>
매직 링크 전송
</UButton>
</div>
<!-- 피드백 메시지 -->
<Transition
enter-active-class="transition duration-300 ease-out"
enter-from-class="opacity-0 -translate-y-2"
enter-to-class="opacity-100 translate-y-0"
>
<UAlert
v-if="message"
color="success"
icon="i-lucide-check-circle"
:description="message"
class="mt-2"
/>
</Transition>
<Transition
enter-active-class="transition duration-300 ease-out"
enter-from-class="opacity-0 -translate-y-2"
enter-to-class="opacity-100 translate-y-0"
>
<UAlert
v-if="error"
color="error"
icon="i-lucide-alert-circle"
:description="error"
class="mt-2"
/>
</Transition>
</div>
<!-- 안내 문구 -->
<p
class="text-center text-xs text-gray-400 dark:text-gray-500 leading-relaxed"
>
로그인 시 CampGear의
<a
href="#"
class="text-green-600 dark:text-green-400 hover:underline"
>이용약관</a
>
<a
href="#"
class="text-green-600 dark:text-green-400 hover:underline"
>개인정보처리방침</a
> 동의하게 됩니다.
</p>
</div>
</div>
</div>
</UApp>
</template>