Jelajahi Sumber

feat: create initial skeleton and login page

ebagabee 3 minggu lalu
induk
melakukan
b907ee62f5
10 mengubah file dengan 500 tambahan dan 14 penghapusan
  1. 2 0
      .gitignore
  2. 337 0
      package-lock.json
  3. 2 0
      package.json
  4. 4 8
      src/App.vue
  5. 2 0
      src/assets/main.css
  6. 73 0
      src/components/WelcomeSkeleton.vue
  7. 1 0
      src/main.ts
  8. 6 1
      src/router/index.ts
  9. 70 0
      src/views/LoginView.vue
  10. 3 5
      vite.config.ts

+ 2 - 0
.gitignore

@@ -37,3 +37,5 @@ __screenshots__/
 
 # Vite
 *.timestamp-*-*.mjs
+
+.claude

+ 337 - 0
package-lock.json

@@ -8,11 +8,13 @@
       "name": "vue-skeleton-ts",
       "version": "0.0.0",
       "dependencies": {
+        "daisyui": "^5.5.20",
         "pinia": "^3.0.4",
         "vue": "^3.5.32",
         "vue-router": "^5.0.4"
       },
       "devDependencies": {
+        "@tailwindcss/vite": "^4.3.0",
         "@tsconfig/node24": "^24.0.4",
         "@types/node": "^24.12.2",
         "@vitejs/plugin-vue": "^6.0.6",
@@ -1462,6 +1464,290 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@tailwindcss/node": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
+      "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/remapping": "^2.3.5",
+        "enhanced-resolve": "^5.21.0",
+        "jiti": "^2.6.1",
+        "lightningcss": "1.32.0",
+        "magic-string": "^0.30.21",
+        "source-map-js": "^1.2.1",
+        "tailwindcss": "4.3.0"
+      }
+    },
+    "node_modules/@tailwindcss/oxide": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz",
+      "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 20"
+      },
+      "optionalDependencies": {
+        "@tailwindcss/oxide-android-arm64": "4.3.0",
+        "@tailwindcss/oxide-darwin-arm64": "4.3.0",
+        "@tailwindcss/oxide-darwin-x64": "4.3.0",
+        "@tailwindcss/oxide-freebsd-x64": "4.3.0",
+        "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0",
+        "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0",
+        "@tailwindcss/oxide-linux-arm64-musl": "4.3.0",
+        "@tailwindcss/oxide-linux-x64-gnu": "4.3.0",
+        "@tailwindcss/oxide-linux-x64-musl": "4.3.0",
+        "@tailwindcss/oxide-wasm32-wasi": "4.3.0",
+        "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0",
+        "@tailwindcss/oxide-win32-x64-msvc": "4.3.0"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-android-arm64": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz",
+      "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-darwin-arm64": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz",
+      "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-darwin-x64": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz",
+      "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-freebsd-x64": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz",
+      "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz",
+      "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz",
+      "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz",
+      "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "libc": [
+        "musl"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz",
+      "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz",
+      "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "libc": [
+        "musl"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz",
+      "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==",
+      "bundleDependencies": [
+        "@napi-rs/wasm-runtime",
+        "@emnapi/core",
+        "@emnapi/runtime",
+        "@tybys/wasm-util",
+        "@emnapi/wasi-threads",
+        "tslib"
+      ],
+      "cpu": [
+        "wasm32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/core": "^1.10.0",
+        "@emnapi/runtime": "^1.10.0",
+        "@emnapi/wasi-threads": "^1.2.1",
+        "@napi-rs/wasm-runtime": "^1.1.4",
+        "@tybys/wasm-util": "^0.10.1",
+        "tslib": "^2.8.1"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz",
+      "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz",
+      "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/@tailwindcss/vite": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.0.tgz",
+      "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@tailwindcss/node": "4.3.0",
+        "@tailwindcss/oxide": "4.3.0",
+        "tailwindcss": "4.3.0"
+      },
+      "peerDependencies": {
+        "vite": "^5.2.0 || ^6 || ^7 || ^8"
+      }
+    },
     "node_modules/@tsconfig/node24": {
       "version": "24.0.4",
       "resolved": "https://registry.npmjs.org/@tsconfig/node24/-/node24-24.0.4.tgz",
@@ -2448,6 +2734,15 @@
       "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
       "license": "MIT"
     },
+    "node_modules/daisyui": {
+      "version": "5.5.20",
+      "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.20.tgz",
+      "integrity": "sha512-HemJcjl0Gk9rQ8BcgofN6p+EURrqftQG9wK1Hkxs98i49xe68+QxpNvry+PyxwkIUgrbMpNmZ5ZWjmtffAjfhQ==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/saadeghi/daisyui?sponsor=1"
+      }
+    },
     "node_modules/debug": {
       "version": "4.4.3",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -2533,6 +2828,20 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/enhanced-resolve": {
+      "version": "5.21.6",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz",
+      "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.3.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/entities": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
@@ -2992,6 +3301,13 @@
         "node": ">=10.13.0"
       }
     },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true,
+      "license": "ISC"
+    },
     "node_modules/hookable": {
       "version": "5.5.3",
       "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
@@ -4353,6 +4669,27 @@
         "node": ">=16"
       }
     },
+    "node_modules/tailwindcss": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
+      "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tapable": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+      "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
     "node_modules/tinyglobby": {
       "version": "0.2.16",
       "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",

+ 2 - 0
package.json

@@ -15,11 +15,13 @@
     "format": "prettier --write --experimental-cli src/"
   },
   "dependencies": {
+    "daisyui": "^5.5.20",
     "pinia": "^3.0.4",
     "vue": "^3.5.32",
     "vue-router": "^5.0.4"
   },
   "devDependencies": {
+    "@tailwindcss/vite": "^4.3.0",
     "@tsconfig/node24": "^24.0.4",
     "@types/node": "^24.12.2",
     "@vitejs/plugin-vue": "^6.0.6",

+ 4 - 8
src/App.vue

@@ -1,11 +1,7 @@
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { RouterView } from 'vue-router'
+</script>
 
 <template>
-  <h1>You did it!</h1>
-  <p>
-    Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
-    documentation
-  </p>
+  <RouterView />
 </template>
-
-<style scoped></style>

+ 2 - 0
src/assets/main.css

@@ -0,0 +1,2 @@
+@import 'tailwindcss';
+@plugin "daisyui";

+ 73 - 0
src/components/WelcomeSkeleton.vue

@@ -0,0 +1,73 @@
+<script setup lang="ts">
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+
+const stack = [
+  { icon: '💚', name: 'Vue 3' },
+  { icon: '🔷', name: 'TypeScript' },
+  { icon: '🎨', name: 'Tailwind v4' },
+  { icon: '🍍', name: 'Pinia' },
+  { icon: '🔀', name: 'Vue Router' },
+]
+
+const steps = [
+  {
+    icon: '📁',
+    title: 'Explore a estrutura',
+    description: 'src/components, stores e router já estão organizados para você.',
+  },
+  {
+    icon: '🧩',
+    title: 'Crie seus componentes',
+    description: 'Apague o WelcomeSkeleton e comece seus próprios componentes.',
+  },
+  {
+    icon: '🚀',
+    title: 'Faça o deploy',
+    description: 'Rode npm run build e suba para o ambiente de staging.',
+  },
+]
+</script>
+
+<template>
+  <div class="min-h-screen bg-base-100 flex flex-col items-center justify-center px-6 py-16">
+    <div class="badge badge-outline gap-2 mb-10 px-4 py-3 text-base-content/50">
+      <span class="w-2 h-2 rounded-full bg-success animate-pulse" />
+      Skeleton
+    </div>
+
+    <h1
+      class="text-5xl sm:text-6xl font-bold text-center leading-tight tracking-tight mb-4 text-base-content"
+    >
+      Seu projeto está
+      <span class="bg-linear-to-r from-violet-500 to-emerald-500 bg-clip-text text-transparent">
+        pronto.
+      </span>
+    </h1>
+
+    <!-- Subtítulo -->
+    <p class="text-base-content/50 text-lg text-center max-w-md mb-12">
+      Tudo configurado para você começar. Apague esse componente e construa algo incrível.
+    </p>
+
+    <div class="flex flex-wrap justify-center gap-3 mb-14">
+      <div v-for="tech in stack" :key="tech.name" class="badge badge-ghost gap-2 px-4 py-3 text-sm">
+        <span>{{ tech.icon }}</span>
+        {{ tech.name }}
+      </div>
+    </div>
+
+    <div class="grid grid-cols-1 sm:grid-cols-3 gap-4 w-full max-w-2xl mb-14">
+      <div v-for="step in steps" :key="step.title" class="card bg-base-200 shadow-sm">
+        <div class="card-body p-5">
+          <div class="text-2xl mb-1">{{ step.icon }}</div>
+          <h3 class="card-title text-sm">{{ step.title }}</h3>
+          <p class="text-base-content/50 text-xs leading-relaxed">{{ step.description }}</p>
+        </div>
+      </div>
+    </div>
+
+    <button class="btn btn-neutral btn-wide" @click="router.push('/login')">Ir para o Login</button>
+  </div>
+</template>

+ 1 - 0
src/main.ts

@@ -1,6 +1,7 @@
 import { createApp } from 'vue'
 import { createPinia } from 'pinia'
 
+import './assets/main.css'
 import App from './App.vue'
 import router from './router'
 

+ 6 - 1
src/router/index.ts

@@ -1,8 +1,13 @@
 import { createRouter, createWebHistory } from 'vue-router'
+import WelcomeSkeleton from '@/components/WelcomeSkeleton.vue'
+import LoginView from '@/views/LoginView.vue'
 
 const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
-  routes: [],
+  routes: [
+    { path: '/', component: WelcomeSkeleton },
+    { path: '/login', component: LoginView },
+  ],
 })
 
 export default router

+ 70 - 0
src/views/LoginView.vue

@@ -0,0 +1,70 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+const email = ref('')
+const password = ref('')
+const loading = ref(false)
+
+async function handleLogin() {
+  loading.value = true
+  await new Promise((r) => setTimeout(r, 1200))
+  loading.value = false
+}
+</script>
+
+<template>
+  <div class="min-h-screen bg-base-200 flex items-center justify-center px-4">
+    <div class="card bg-base-100 shadow-xl w-full max-w-sm">
+      <div class="card-body gap-6">
+        <div class="text-center space-y-1">
+          <div class="badge badge-outline gap-2 px-4 py-3 mx-auto text-base-content/50 mb-2">
+            <span class="w-2 h-2 rounded-full bg-success animate-pulse" />
+            Skeleton
+          </div>
+          <h2 class="card-title text-2xl justify-center">Bem-vindo de volta</h2>
+          <p class="text-base-content/50 text-sm">Entre com sua conta para continuar</p>
+        </div>
+
+        <div class="flex flex-col gap-4">
+          <label class="form-control w-full">
+            <div class="label">
+              <span class="label-text font-medium">E-mail</span>
+            </div>
+            <input
+              v-model="email"
+              type="email"
+              placeholder="seu@email.com"
+              class="input input-bordered w-full"
+            />
+          </label>
+
+          <label class="form-control w-full">
+            <div class="label">
+              <span class="label-text font-medium">Senha</span>
+            </div>
+            <input
+              v-model="password"
+              type="password"
+              placeholder="••••••••"
+              class="input input-bordered w-full"
+            />
+            <a class="label-text-alt link link-hover text-base-content/50">Esqueceu a senha?</a>
+          </label>
+
+          <button class="btn btn-neutral w-full mt-2" :disabled="loading" @click="handleLogin">
+            <span v-if="loading" class="loading loading-spinner loading-sm" />
+            {{ loading ? 'Entrando...' : 'Entrar' }}
+          </button>
+        </div>
+
+        <div class="divider text-xs text-base-content/30">ou</div>
+
+        <button class="btn btn-ghost btn-sm w-full" @click="router.push('/')">
+          ← Voltar para o início
+        </button>
+      </div>
+    </div>
+  </div>
+</template>

+ 3 - 5
vite.config.ts

@@ -1,4 +1,5 @@
 import { fileURLToPath, URL } from 'node:url'
+import tailwindcss from '@tailwindcss/vite'
 
 import { defineConfig } from 'vite'
 import vue from '@vitejs/plugin-vue'
@@ -6,13 +7,10 @@ import vueDevTools from 'vite-plugin-vue-devtools'
 
 // https://vite.dev/config/
 export default defineConfig({
-  plugins: [
-    vue(),
-    vueDevTools(),
-  ],
+  plugins: [vue(), vueDevTools(), tailwindcss()],
   resolve: {
     alias: {
-      '@': fileURLToPath(new URL('./src', import.meta.url))
+      '@': fileURLToPath(new URL('./src', import.meta.url)),
     },
   },
 })