diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php new file mode 100644 index 0000000..4025158 --- /dev/null +++ b/app/Http/Controllers/Auth/LoginController.php @@ -0,0 +1,30 @@ +authenticate(); + + $request->session()->regenerate(); + + $request->user()?->update(['last_login_at' => now()]); + + return redirect() + ->intended(route('home')) + ->with('success', 'Berhasil masuk. Selamat datang kembali!'); + } +} diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index bdca0a8..e03b7cd 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -41,6 +41,10 @@ public function share(Request $request): array 'auth' => [ 'user' => $request->user(), ], + 'flash' => [ + 'success' => $request->session()->get('success'), + 'error' => $request->session()->get('error'), + ], ]; } } diff --git a/app/Http/Requests/Auth/LoginRequest.php b/app/Http/Requests/Auth/LoginRequest.php new file mode 100644 index 0000000..261496c --- /dev/null +++ b/app/Http/Requests/Auth/LoginRequest.php @@ -0,0 +1,86 @@ +> + */ + public function rules(): array + { + return [ + 'login' => ['required', 'string'], + 'password' => ['required', 'string'], + ]; + } + + /** + * @throws ValidationException + */ + public function authenticate(): void + { + $this->ensureIsNotRateLimited(); + + $login = $this->string('login'); + $field = filter_var($login, FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; + + if (! Auth::attempt([$field => $login, 'password' => $this->string('password')], $this->boolean('remember'))) { + RateLimiter::hit($this->throttleKey()); + + throw ValidationException::withMessages([ + 'login' => 'Email/username atau kata sandi salah.', + ]); + } + + $user = Auth::user(); + + if (! $user?->is_active) { + Auth::logout(); + + throw ValidationException::withMessages([ + 'login' => 'Akun Anda tidak aktif. Hubungi administrator.', + ]); + } + + RateLimiter::clear($this->throttleKey()); + } + + /** + * @throws ValidationException + */ + public function ensureIsNotRateLimited(): void + { + if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) { + return; + } + + event(new Lockout($this)); + + $seconds = RateLimiter::availableIn($this->throttleKey()); + + throw ValidationException::withMessages([ + 'login' => trans('auth.throttle', [ + 'seconds' => $seconds, + 'minutes' => ceil($seconds / 60), + ]), + ]); + } + + public function throttleKey(): string + { + return Str::transliterate(Str::lower($this->string('login')).'|'.$this->ip()); + } +} diff --git a/components.json b/components.json new file mode 100644 index 0000000..91dfb3b --- /dev/null +++ b/components.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://shadcn-vue.com/schema.json", + "style": "new-york", + "font": "inter", + "typescript": true, + "tailwind": { + "config": "", + "css": "resources/css/app.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "pointer": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "composables": "@/composables" + }, + "registries": {} +} diff --git a/package-lock.json b/package-lock.json index 7260568..dfa0ef9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,16 +7,21 @@ "dependencies": { "@inertiajs/vite": "^3.0.0", "@inertiajs/vue3": "^3.0.0", + "@lucide/vue": "^1.17.0", "@tailwindcss/vite": "^4.1.11", "@vitejs/plugin-vue": "^6.0.0", + "@vueuse/core": "^14.3.0", + "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "concurrently": "^9.0.1", "laravel-vite-plugin": "^3.1", - "tailwind-merge": "^3.2.0", + "reka-ui": "^2.9.9", + "tailwind-merge": "^3.6.0", "tailwindcss": "^4.1.1", "typescript": "^5.2.2", "vite": "^8.0.0", - "vue": "^3.5.13" + "vue": "^3.5.13", + "vue-sonner": "^2.0.9" }, "devDependencies": { "@eslint/js": "^9.19.0", @@ -31,6 +36,7 @@ "eslint-plugin-vue": "^9.32.0", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", + "tw-animate-css": "^1.4.0", "typescript-eslint": "^8.23.0", "vue-tsc": "^2.2.4" }, @@ -323,6 +329,68 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@floating-ui/vue": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@floating-ui/vue/-/vue-1.1.11.tgz", + "integrity": "sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "@floating-ui/utils": "^0.2.11", + "vue-demi": ">=0.13.0" + } + }, + "node_modules/@floating-ui/vue/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", @@ -435,6 +503,24 @@ "vue": "^3.0.0" } }, + "node_modules/@internationalized/date": { + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.2.tgz", + "integrity": "sha512-FY1Y+H64NDs+HAF6omlnWxm3mEpfgaCSWtL5l551ZZfImA+kGjPFgrnJrGjH6lfmLL0g8Z/mBu1R3kufeCp6Jw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/number": { + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.7.tgz", + "integrity": "sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -487,6 +573,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@lucide/vue": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@lucide/vue/-/vue-1.17.0.tgz", + "integrity": "sha512-6Q1ZHgr5FbmJzKWe5BxlNdjLj2lbmuH1zwDtVzUJofX0w9UREwKgq4F4jwKqFYyyIS4Rj3FiJvDi2k6djukmmw==", + "license": "ISC", + "peerDependencies": { + "vue": ">=3.0.1" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -841,6 +936,15 @@ "eslint": "^9.0.0 || ^10.0.0" } }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@tailwindcss/node": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", @@ -1098,6 +1202,32 @@ "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.0.tgz", + "integrity": "sha512-gOxY/hFkPh/XQYhnThBHzkbkX3Ed+z/iushyz+R+JAr213aXxUDgQoTgTdrDpBSRsjFM73P/KfUyWmaF9WHMkQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/vue-virtual": { + "version": "3.13.28", + "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.28.tgz", + "integrity": "sha512-A+jWpXtMpWXKhGLKQrXeC9mk1VgYeMWSJ+o0CTCEi+HLYMSQFdVmPG9lJz7d4XJyIkc5xVwZU9QY67QpScqnxA==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.0.0" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", @@ -1139,6 +1269,12 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.61.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.0.tgz", @@ -1935,6 +2071,44 @@ "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", "license": "MIT" }, + "node_modules/@vueuse/core": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.3.0.tgz", + "integrity": "sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.3.0", + "@vueuse/shared": "14.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.3.0.tgz", + "integrity": "sha512-BwxmbAzwAVF50+MW57GXOUEV61nFBGnlBvrTqj49PqWJu3uw7hdu72ztXeZ33RdZtDY6kO+bfCAE1PCn88Tktw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.3.0.tgz", + "integrity": "sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -2013,6 +2187,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", @@ -2292,6 +2478,18 @@ "node": ">=8" } }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2520,6 +2718,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -4931,6 +5135,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -5304,6 +5514,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reka-ui": { + "version": "2.9.9", + "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.9.9.tgz", + "integrity": "sha512-/e+hdF9vP8E2kPrKR4RdgMQQsfpCr8l436Zn8GRWM3jKT9EG1lOO/UFMGBVEnrMLOVoJSjjmIFrej4tMOb+6qQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.13", + "@floating-ui/vue": "^1.1.6", + "@internationalized/date": "^3.5.0", + "@internationalized/number": "^3.5.0", + "@tanstack/vue-virtual": "^3.12.0", + "@vueuse/core": "^14.1.0", + "@vueuse/shared": "^14.1.0", + "aria-hidden": "^1.2.4", + "defu": "^6.1.5", + "ohash": "^2.0.11" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/zernonia" + }, + "peerDependencies": { + "vue": ">= 3.4.0" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5931,6 +6166,16 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tw-animate-css": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", + "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6304,6 +6549,28 @@ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" } }, + "node_modules/vue-sonner": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/vue-sonner/-/vue-sonner-2.0.9.tgz", + "integrity": "sha512-i6BokNlNDL93fpzNxN/LZSn6D6MzlO+i3qXt6iVZne3x1k7R46d5HlFB4P8tYydhgqOrRbIZEsnRd3kG7qGXyw==", + "license": "MIT", + "peerDependencies": { + "@nuxt/kit": "^4.0.3", + "@nuxt/schema": "^4.0.3", + "nuxt": "^4.0.3" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@nuxt/schema": { + "optional": true + }, + "nuxt": { + "optional": true + } + } + }, "node_modules/vue-tsc": { "version": "2.2.12", "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.12.tgz", diff --git a/package.json b/package.json index 9b4251a..c521657 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ }, "devDependencies": { "@eslint/js": "^9.19.0", - "@stylistic/eslint-plugin": "^5.10.0", "@laravel/vite-plugin-wayfinder": "^0.1.3", + "@stylistic/eslint-plugin": "^5.10.0", "@types/node": "^22.13.5", "@vue/eslint-config-typescript": "^14.3.0", "eslint": "^9.17.0", @@ -25,22 +25,28 @@ "eslint-plugin-vue": "^9.32.0", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", + "tw-animate-css": "^1.4.0", "typescript-eslint": "^8.23.0", "vue-tsc": "^2.2.4" }, "dependencies": { "@inertiajs/vite": "^3.0.0", "@inertiajs/vue3": "^3.0.0", + "@lucide/vue": "^1.17.0", "@tailwindcss/vite": "^4.1.11", "@vitejs/plugin-vue": "^6.0.0", + "@vueuse/core": "^14.3.0", + "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "concurrently": "^9.0.1", "laravel-vite-plugin": "^3.1", - "tailwind-merge": "^3.2.0", + "reka-ui": "^2.9.9", + "tailwind-merge": "^3.6.0", "tailwindcss": "^4.1.1", "typescript": "^5.2.2", "vite": "^8.0.0", - "vue": "^3.5.13" + "vue": "^3.5.13", + "vue-sonner": "^2.0.9" }, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "4.9.5", diff --git a/resources/css/app.css b/resources/css/app.css index 9c5a556..bc33953 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,5 +1,11 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); + @import 'tailwindcss'; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; @source '../../storage/framework/views/*.php'; @@ -8,4 +14,247 @@ @theme inline { Instrument Sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --font-heading: + var(--font-sans); + --color-sidebar-ring: + var(--sidebar-ring); + --color-sidebar-border: + var(--sidebar-border); + --color-sidebar-accent-foreground: + var(--sidebar-accent-foreground); + --color-sidebar-accent: + var(--sidebar-accent); + --color-sidebar-primary-foreground: + var(--sidebar-primary-foreground); + --color-sidebar-primary: + var(--sidebar-primary); + --color-sidebar-foreground: + var(--sidebar-foreground); + --color-sidebar: + var(--sidebar); + --color-chart-5: + var(--chart-5); + --color-chart-4: + var(--chart-4); + --color-chart-3: + var(--chart-3); + --color-chart-2: + var(--chart-2); + --color-chart-1: + var(--chart-1); + --color-ring: + var(--ring); + --color-input: + var(--input); + --color-border: + var(--border); + --color-destructive: + var(--destructive); + --color-accent-foreground: + var(--accent-foreground); + --color-accent: + var(--accent); + --color-muted-foreground: + var(--muted-foreground); + --color-muted: + var(--muted); + --color-secondary-foreground: + var(--secondary-foreground); + --color-secondary: + var(--secondary); + --color-primary-foreground: + var(--primary-foreground); + --color-primary: + var(--primary); + --color-popover-foreground: + var(--popover-foreground); + --color-popover: + var(--popover); + --color-card-foreground: + var(--card-foreground); + --color-card: + var(--card); + --color-foreground: + var(--foreground); + --color-background: + var(--background); + --radius-sm: + calc(var(--radius) - 4px); + --radius-md: + calc(var(--radius) - 2px); + --radius-lg: + var(--radius); + --radius-xl: + calc(var(--radius) + 4px); } + +:root { + --radius: + 0.625rem; + --background: + oklch(1 0 0); + --foreground: + oklch(0.141 0.005 285.823); + --card: + oklch(1 0 0); + --card-foreground: + oklch(0.141 0.005 285.823); + --popover: + oklch(1 0 0); + --popover-foreground: + oklch(0.141 0.005 285.823); + --primary: + oklch(0.21 0.006 285.885); + --primary-foreground: + oklch(0.985 0 0); + --secondary: + oklch(0.967 0.001 286.375); + --secondary-foreground: + oklch(0.21 0.006 285.885); + --muted: + oklch(0.967 0.001 286.375); + --muted-foreground: + oklch(0.552 0.016 285.938); + --accent: + oklch(0.967 0.001 286.375); + --accent-foreground: + oklch(0.21 0.006 285.885); + --destructive: + oklch(0.577 0.245 27.325); + --border: + oklch(0.92 0.004 286.32); + --input: + oklch(0.92 0.004 286.32); + --ring: + oklch(0.705 0.015 286.067); + --chart-1: + oklch(0.646 0.222 41.116); + --chart-2: + oklch(0.6 0.118 184.704); + --chart-3: + oklch(0.398 0.07 227.392); + --chart-4: + oklch(0.828 0.189 84.429); + --chart-5: + oklch(0.769 0.188 70.08); + --sidebar: + oklch(0.985 0 0); + --sidebar-foreground: + oklch(0.141 0.005 285.823); + --sidebar-primary: + oklch(0.21 0.006 285.885); + --sidebar-primary-foreground: + oklch(0.985 0 0); + --sidebar-accent: + oklch(0.967 0.001 286.375); + --sidebar-accent-foreground: + oklch(0.21 0.006 285.885); + --sidebar-border: + oklch(0.92 0.004 286.32); + --sidebar-ring: + oklch(0.705 0.015 286.067); +} + +.dark { + --background: + oklch(0.141 0.005 285.823); + --foreground: + oklch(0.985 0 0); + --card: + oklch(0.21 0.006 285.885); + --card-foreground: + oklch(0.985 0 0); + --popover: + oklch(0.21 0.006 285.885); + --popover-foreground: + oklch(0.985 0 0); + --primary: + oklch(0.92 0.004 286.32); + --primary-foreground: + oklch(0.21 0.006 285.885); + --secondary: + oklch(0.274 0.006 286.033); + --secondary-foreground: + oklch(0.985 0 0); + --muted: + oklch(0.274 0.006 286.033); + --muted-foreground: + oklch(0.705 0.015 286.067); + --accent: + oklch(0.274 0.006 286.033); + --accent-foreground: + oklch(0.985 0 0); + --destructive: + oklch(0.704 0.191 22.216); + --border: + oklch(1 0 0 / 10%); + --input: + oklch(1 0 0 / 15%); + --ring: + oklch(0.552 0.016 285.938); + --chart-1: + oklch(0.488 0.243 264.376); + --chart-2: + oklch(0.696 0.17 162.48); + --chart-3: + oklch(0.769 0.188 70.08); + --chart-4: + oklch(0.627 0.265 303.9); + --chart-5: + oklch(0.645 0.246 16.439); + --sidebar: + oklch(0.21 0.006 285.885); + --sidebar-foreground: + oklch(0.985 0 0); + --sidebar-primary: + oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: + oklch(0.985 0 0); + --sidebar-accent: + oklch(0.274 0.006 286.033); + --sidebar-accent-foreground: + oklch(0.985 0 0); + --sidebar-border: + oklch(1 0 0 / 10%); + --sidebar-ring: + oklch(0.552 0.016 285.938); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + + body { + @apply bg-background text-foreground; + } +} + +/* sonner */ +[data-sonner-toast][data-type="success"] { + border-left: 4px solid rgb(34 197 94); + border-top: 0; + border-right: 0; + border-bottom: 0; +} + +[data-sonner-toast][data-type="error"] { + border-left: 4px solid rgb(239 68 68); + border-top: 0; + border-right: 0; + border-bottom: 0; +} + +[data-sonner-toast][data-type="warning"] { + border-left: 4px solid rgb(245 158 11); + border-top: 0; + border-right: 0; + border-bottom: 0; +} + +[data-sonner-toast][data-type="info"] { + border-left: 4px solid rgb(59 130 246); + border-top: 0; + border-right: 0; + border-bottom: 0; +} \ No newline at end of file diff --git a/resources/js/app.ts b/resources/js/app.ts index f4f9fbc..a0bfe51 100644 --- a/resources/js/app.ts +++ b/resources/js/app.ts @@ -1,4 +1,7 @@ import { createInertiaApp } from '@inertiajs/vue3'; +import { createApp, h } from 'vue'; +import { Toaster } from '@/components/ui/sonner'; +import { useFlashToast } from '@/composables/useFlashToast'; const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; @@ -7,4 +10,20 @@ createInertiaApp({ progress: { color: '#4B5563', }, + setup({ el, App, props, plugin }) { + if (!el) { + return; + } + + const app = createApp({ + setup() { + useFlashToast(); + + return () => [h(App, props), h(Toaster)]; + }, + }); + + app.use(plugin); + app.mount(el); + }, }); diff --git a/resources/js/components/LoginForm.vue b/resources/js/components/LoginForm.vue new file mode 100644 index 0000000..5a732ca --- /dev/null +++ b/resources/js/components/LoginForm.vue @@ -0,0 +1,100 @@ + + + diff --git a/resources/js/components/ui/button/Button.vue b/resources/js/components/ui/button/Button.vue new file mode 100644 index 0000000..3763470 --- /dev/null +++ b/resources/js/components/ui/button/Button.vue @@ -0,0 +1,31 @@ + + + diff --git a/resources/js/components/ui/button/index.ts b/resources/js/components/ui/button/index.ts new file mode 100644 index 0000000..3cd94f9 --- /dev/null +++ b/resources/js/components/ui/button/index.ts @@ -0,0 +1,38 @@ +import type { VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" + +export { default as Button } from "./Button.vue" + +export const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + "default": "h-9 px-4 py-2 has-[>svg]:px-3", + "sm": "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + "lg": "h-10 rounded-md px-6 has-[>svg]:px-4", + "icon": "size-9", + "icon-sm": "size-8", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +) +export type ButtonVariants = VariantProps diff --git a/resources/js/components/ui/card/Card.vue b/resources/js/components/ui/card/Card.vue new file mode 100644 index 0000000..f5a0707 --- /dev/null +++ b/resources/js/components/ui/card/Card.vue @@ -0,0 +1,22 @@ + + + diff --git a/resources/js/components/ui/card/CardAction.vue b/resources/js/components/ui/card/CardAction.vue new file mode 100644 index 0000000..c91638b --- /dev/null +++ b/resources/js/components/ui/card/CardAction.vue @@ -0,0 +1,17 @@ + + + diff --git a/resources/js/components/ui/card/CardContent.vue b/resources/js/components/ui/card/CardContent.vue new file mode 100644 index 0000000..dfbc552 --- /dev/null +++ b/resources/js/components/ui/card/CardContent.vue @@ -0,0 +1,17 @@ + + + diff --git a/resources/js/components/ui/card/CardDescription.vue b/resources/js/components/ui/card/CardDescription.vue new file mode 100644 index 0000000..71c1b8d --- /dev/null +++ b/resources/js/components/ui/card/CardDescription.vue @@ -0,0 +1,17 @@ + + + diff --git a/resources/js/components/ui/card/CardFooter.vue b/resources/js/components/ui/card/CardFooter.vue new file mode 100644 index 0000000..9e3739e --- /dev/null +++ b/resources/js/components/ui/card/CardFooter.vue @@ -0,0 +1,17 @@ + + + diff --git a/resources/js/components/ui/card/CardHeader.vue b/resources/js/components/ui/card/CardHeader.vue new file mode 100644 index 0000000..4fe4da4 --- /dev/null +++ b/resources/js/components/ui/card/CardHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/resources/js/components/ui/card/CardTitle.vue b/resources/js/components/ui/card/CardTitle.vue new file mode 100644 index 0000000..5f479e7 --- /dev/null +++ b/resources/js/components/ui/card/CardTitle.vue @@ -0,0 +1,17 @@ + + + diff --git a/resources/js/components/ui/card/index.ts b/resources/js/components/ui/card/index.ts new file mode 100644 index 0000000..1627758 --- /dev/null +++ b/resources/js/components/ui/card/index.ts @@ -0,0 +1,7 @@ +export { default as Card } from "./Card.vue" +export { default as CardAction } from "./CardAction.vue" +export { default as CardContent } from "./CardContent.vue" +export { default as CardDescription } from "./CardDescription.vue" +export { default as CardFooter } from "./CardFooter.vue" +export { default as CardHeader } from "./CardHeader.vue" +export { default as CardTitle } from "./CardTitle.vue" diff --git a/resources/js/components/ui/field/Field.vue b/resources/js/components/ui/field/Field.vue new file mode 100644 index 0000000..5519d37 --- /dev/null +++ b/resources/js/components/ui/field/Field.vue @@ -0,0 +1,25 @@ + + + diff --git a/resources/js/components/ui/field/FieldContent.vue b/resources/js/components/ui/field/FieldContent.vue new file mode 100644 index 0000000..d9a23fd --- /dev/null +++ b/resources/js/components/ui/field/FieldContent.vue @@ -0,0 +1,20 @@ + + + diff --git a/resources/js/components/ui/field/FieldDescription.vue b/resources/js/components/ui/field/FieldDescription.vue new file mode 100644 index 0000000..7240a83 --- /dev/null +++ b/resources/js/components/ui/field/FieldDescription.vue @@ -0,0 +1,22 @@ + + + diff --git a/resources/js/components/ui/field/FieldError.vue b/resources/js/components/ui/field/FieldError.vue new file mode 100644 index 0000000..8a0a63f --- /dev/null +++ b/resources/js/components/ui/field/FieldError.vue @@ -0,0 +1,53 @@ + + + diff --git a/resources/js/components/ui/field/FieldGroup.vue b/resources/js/components/ui/field/FieldGroup.vue new file mode 100644 index 0000000..834d8ce --- /dev/null +++ b/resources/js/components/ui/field/FieldGroup.vue @@ -0,0 +1,20 @@ + + + diff --git a/resources/js/components/ui/field/FieldLabel.vue b/resources/js/components/ui/field/FieldLabel.vue new file mode 100644 index 0000000..b9ce10d --- /dev/null +++ b/resources/js/components/ui/field/FieldLabel.vue @@ -0,0 +1,31 @@ + + + diff --git a/resources/js/components/ui/field/FieldLegend.vue b/resources/js/components/ui/field/FieldLegend.vue new file mode 100644 index 0000000..c620fed --- /dev/null +++ b/resources/js/components/ui/field/FieldLegend.vue @@ -0,0 +1,24 @@ + + + diff --git a/resources/js/components/ui/field/FieldSeparator.vue b/resources/js/components/ui/field/FieldSeparator.vue new file mode 100644 index 0000000..97d0efa --- /dev/null +++ b/resources/js/components/ui/field/FieldSeparator.vue @@ -0,0 +1,29 @@ + + + diff --git a/resources/js/components/ui/field/FieldSet.vue b/resources/js/components/ui/field/FieldSet.vue new file mode 100644 index 0000000..7be4dc9 --- /dev/null +++ b/resources/js/components/ui/field/FieldSet.vue @@ -0,0 +1,21 @@ + + + diff --git a/resources/js/components/ui/field/FieldTitle.vue b/resources/js/components/ui/field/FieldTitle.vue new file mode 100644 index 0000000..f564b8b --- /dev/null +++ b/resources/js/components/ui/field/FieldTitle.vue @@ -0,0 +1,20 @@ + + + diff --git a/resources/js/components/ui/field/index.ts b/resources/js/components/ui/field/index.ts new file mode 100644 index 0000000..162ba14 --- /dev/null +++ b/resources/js/components/ui/field/index.ts @@ -0,0 +1,39 @@ +import type { VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" + +export const fieldVariants = cva( + "group/field flex w-full gap-3 data-[invalid=true]:text-destructive", + { + variants: { + orientation: { + vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"], + horizontal: [ + "flex-row items-center", + "[&>[data-slot=field-label]]:flex-auto", + "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + ], + responsive: [ + "flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto", + "@md/field-group:[&>[data-slot=field-label]]:flex-auto", + "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + ], + }, + }, + defaultVariants: { + orientation: "vertical", + }, + }, +) + +export type FieldVariants = VariantProps + +export { default as Field } from "./Field.vue" +export { default as FieldContent } from "./FieldContent.vue" +export { default as FieldDescription } from "./FieldDescription.vue" +export { default as FieldError } from "./FieldError.vue" +export { default as FieldGroup } from "./FieldGroup.vue" +export { default as FieldLabel } from "./FieldLabel.vue" +export { default as FieldLegend } from "./FieldLegend.vue" +export { default as FieldSeparator } from "./FieldSeparator.vue" +export { default as FieldSet } from "./FieldSet.vue" +export { default as FieldTitle } from "./FieldTitle.vue" diff --git a/resources/js/components/ui/input/Input.vue b/resources/js/components/ui/input/Input.vue new file mode 100644 index 0000000..39c101b --- /dev/null +++ b/resources/js/components/ui/input/Input.vue @@ -0,0 +1,29 @@ + + + diff --git a/resources/js/components/ui/input/index.ts b/resources/js/components/ui/input/index.ts new file mode 100644 index 0000000..9976b86 --- /dev/null +++ b/resources/js/components/ui/input/index.ts @@ -0,0 +1 @@ +export { default as Input } from "./Input.vue" diff --git a/resources/js/components/ui/label/Label.vue b/resources/js/components/ui/label/Label.vue new file mode 100644 index 0000000..ee63970 --- /dev/null +++ b/resources/js/components/ui/label/Label.vue @@ -0,0 +1,26 @@ + + + diff --git a/resources/js/components/ui/label/index.ts b/resources/js/components/ui/label/index.ts new file mode 100644 index 0000000..036e35c --- /dev/null +++ b/resources/js/components/ui/label/index.ts @@ -0,0 +1 @@ +export { default as Label } from "./Label.vue" diff --git a/resources/js/components/ui/separator/Separator.vue b/resources/js/components/ui/separator/Separator.vue new file mode 100644 index 0000000..78d60ec --- /dev/null +++ b/resources/js/components/ui/separator/Separator.vue @@ -0,0 +1,29 @@ + + + diff --git a/resources/js/components/ui/separator/index.ts b/resources/js/components/ui/separator/index.ts new file mode 100644 index 0000000..4407287 --- /dev/null +++ b/resources/js/components/ui/separator/index.ts @@ -0,0 +1 @@ +export { default as Separator } from "./Separator.vue" diff --git a/resources/js/components/ui/sonner/Sonner.vue b/resources/js/components/ui/sonner/Sonner.vue new file mode 100644 index 0000000..36d2951 --- /dev/null +++ b/resources/js/components/ui/sonner/Sonner.vue @@ -0,0 +1,38 @@ + + + diff --git a/resources/js/components/ui/sonner/index.ts b/resources/js/components/ui/sonner/index.ts new file mode 100644 index 0000000..6673112 --- /dev/null +++ b/resources/js/components/ui/sonner/index.ts @@ -0,0 +1 @@ +export { default as Toaster } from "./Sonner.vue" diff --git a/resources/js/composables/useFlashToast.ts b/resources/js/composables/useFlashToast.ts new file mode 100644 index 0000000..3eb90ab --- /dev/null +++ b/resources/js/composables/useFlashToast.ts @@ -0,0 +1,27 @@ +import { router } from '@inertiajs/vue3'; +import { toast } from 'vue-sonner'; + +type Flash = { + success?: string | null; + error?: string | null; +}; + +function showFlash(flash: Flash): void { + if (flash.success) { + toast.success(flash.success); + } + + if (flash.error) { + toast.error(flash.error); + } +} + +export function useFlashToast(): void { + router.on('success', (event) => { + const flash = event.detail.page.props.flash as Flash | undefined; + + if (flash) { + showFlash(flash); + } + }); +} diff --git a/resources/js/lib/new-york-v4/lib/utils.ts b/resources/js/lib/new-york-v4/lib/utils.ts new file mode 100644 index 0000000..c66a9d9 --- /dev/null +++ b/resources/js/lib/new-york-v4/lib/utils.ts @@ -0,0 +1,7 @@ +import type { ClassValue } from "clsx" +import { clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/resources/js/pages/auth/Login.vue b/resources/js/pages/auth/Login.vue new file mode 100644 index 0000000..4ebbb06 --- /dev/null +++ b/resources/js/pages/auth/Login.vue @@ -0,0 +1,14 @@ + + + diff --git a/resources/js/types/auth.ts b/resources/js/types/auth.ts index f9a7fa4..f72009c 100644 --- a/resources/js/types/auth.ts +++ b/resources/js/types/auth.ts @@ -1,9 +1,9 @@ export type User = { id: number; - name: string; email: string; - avatar?: string; - email_verified_at: string | null; + username: string; + is_active: boolean; + last_login_at: string | null; created_at: string; updated_at: string; [key: string]: unknown; diff --git a/resources/js/types/global.d.ts b/resources/js/types/global.d.ts index a53aee2..1bfc830 100644 --- a/resources/js/types/global.d.ts +++ b/resources/js/types/global.d.ts @@ -18,6 +18,10 @@ declare module '@inertiajs/core' { sharedPageProps: { name: string; auth: Auth; + flash: { + success: string | null; + error: string | null; + }; sidebarOpen: boolean; [key: string]: unknown; }; diff --git a/routes/web.php b/routes/web.php index 8c10e0a..6dc73ea 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,5 +1,11 @@ name('home'); + +Route::middleware('guest')->group(function () { + Route::get('/auth/login', [LoginController::class, 'index'])->name('login'); + Route::post('/auth/login', [LoginController::class, 'store']); +}); diff --git a/tsconfig.json b/tsconfig.json index cab1dcd..32ad463 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ @@ -9,7 +8,6 @@ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "useDefineForClassFields": true, @@ -27,14 +25,15 @@ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ "module": "ESNext" /* Specify what module code is generated. */, // "rootDir": "./", /* Specify the root folder within your source files. */ "moduleResolution": "bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "baseUrl": ".", "paths": { - /* Specify a set of entries that re-map imports to additional lookup locations. */ "@/*": ["./resources/js/*"], + "@/*": [ + "resources/js/*" + ] }, // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ @@ -52,12 +51,10 @@ "resolveJsonModule": true /* Enable importing .json files. */, // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ @@ -80,7 +77,6 @@ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - /* Interop Constraints */ "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ @@ -89,7 +85,6 @@ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ @@ -111,7 +106,6 @@ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ @@ -119,7 +113,7 @@ "include": [ "resources/js/**/*.ts", "resources/js/**/*.d.ts", - "resources/js/**/*.tsx", + "resources/js/**/*.tsx", "resources/js/**/*.vue" ] }