Switch entire UI to dark mode by default

Update all 26 Vue files (3 layouts, 4 components, 19 pages) and the
Blade root template to use a dark color scheme: gray-950 backgrounds,
gray-900 cards, gray-800 borders, light text, and adjusted status
badges/flash messages for dark backgrounds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Dev
2026-02-09 07:24:23 -05:00
parent b1e080d70c
commit 67ea1ef22a
26 changed files with 284 additions and 289 deletions

View File

@@ -19,7 +19,7 @@ defineProps({
:class="[
'px-4 py-2 text-sm font-medium rounded-md disabled:opacity-50',
variant === 'primary' && 'bg-blue-600 text-white hover:bg-blue-700',
variant === 'secondary' && 'bg-white text-gray-700 border border-gray-300 hover:bg-gray-50',
variant === 'secondary' && 'bg-gray-800 text-gray-300 border border-gray-700 hover:bg-gray-700',
variant === 'danger' && 'bg-red-600 text-white hover:bg-red-700',
]"
>

View File

@@ -5,8 +5,8 @@ defineProps({
</script>
<template>
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h3 v-if="title" class="text-sm font-medium text-gray-500 mb-2">{{ title }}</h3>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h3 v-if="title" class="text-sm font-medium text-gray-400 mb-2">{{ title }}</h3>
<slot />
</div>
</template>

View File

@@ -7,10 +7,10 @@ const flash = computed(() => page.props.flash || {});
</script>
<template>
<div v-if="flash.success" class="mb-4 rounded-md bg-green-50 p-4">
<p class="text-sm font-medium text-green-800">{{ flash.success }}</p>
<div v-if="flash.success" class="mb-4 rounded-md bg-green-900/50 border border-green-800 p-4">
<p class="text-sm font-medium text-green-300">{{ flash.success }}</p>
</div>
<div v-if="flash.error" class="mb-4 rounded-md bg-red-50 p-4">
<p class="text-sm font-medium text-red-800">{{ flash.error }}</p>
<div v-if="flash.error" class="mb-4 rounded-md bg-red-900/50 border border-red-800 p-4">
<p class="text-sm font-medium text-red-300">{{ flash.error }}</p>
</div>
</template>

View File

@@ -13,8 +13,8 @@ defineProps({
:class="[
'px-3 py-2 rounded-md text-sm font-medium',
active
? 'bg-gray-100 text-gray-900'
: 'text-gray-700 hover:text-gray-900 hover:bg-gray-100',
? 'bg-gray-800 text-white'
: 'text-gray-300 hover:text-white hover:bg-gray-800',
]"
>
<slot />

View File

@@ -9,55 +9,55 @@ const domains = computed(() => page.props.domains);
</script>
<template>
<div class="min-h-screen bg-gray-50">
<nav class="bg-white border-b border-gray-200">
<div class="min-h-screen bg-gray-950">
<nav class="bg-gray-900 border-b border-gray-800">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<Link href="/dashboard" class="text-xl font-bold text-gray-900">
<Link href="/dashboard" class="text-xl font-bold text-white">
EZSCALE
</Link>
<div class="hidden sm:ml-8 sm:flex sm:space-x-4">
<Link
href="/dashboard"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-800"
>
Dashboard
</Link>
<Link
href="/subscriptions"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-800"
>
Subscriptions
</Link>
<Link
href="/billing"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-800"
>
Billing
</Link>
<Link
href="/plans"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-800"
>
Plans
</Link>
<Link
href="/profile"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
class="px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-800"
>
Profile
</Link>
</div>
</div>
<div class="flex items-center space-x-4">
<span v-if="user" class="text-sm text-gray-600">{{ user.name }}</span>
<span v-if="user" class="text-sm text-gray-400">{{ user.name }}</span>
<Link
v-if="user"
href="/logout"
method="post"
as="button"
class="text-sm text-gray-600 hover:text-gray-900"
class="text-sm text-gray-400 hover:text-white"
>
Log out
</Link>

View File

@@ -8,13 +8,13 @@ const marketingUrl = computed(() => `https://${domains.value?.marketing}`);
</script>
<template>
<div class="min-h-screen flex flex-col items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div class="min-h-screen flex flex-col items-center justify-center bg-gray-950 py-12 px-4 sm:px-6 lg:px-8">
<div class="w-full max-w-md">
<div class="text-center mb-8">
<a :href="marketingUrl" class="text-3xl font-bold text-gray-900">EZSCALE</a>
<p class="mt-2 text-sm text-gray-600">Cloud Hosting Platform</p>
<a :href="marketingUrl" class="text-3xl font-bold text-white">EZSCALE</a>
<p class="mt-2 text-sm text-gray-400">Cloud Hosting Platform</p>
</div>
<div class="bg-white shadow-sm rounded-lg border border-gray-200 p-8">
<div class="bg-gray-900 shadow-sm rounded-lg border border-gray-800 p-8">
<slot />
</div>
</div>

View File

@@ -16,27 +16,27 @@ const submit = () => {
</script>
<template>
<h2 class="text-xl font-semibold text-gray-900 mb-4">Confirm your password</h2>
<p class="text-sm text-gray-600 mb-6">Please confirm your password before continuing.</p>
<h2 class="text-xl font-semibold text-white mb-4">Confirm your password</h2>
<p class="text-sm text-gray-400 mb-6">Please confirm your password before continuing.</p>
<form @submit.prevent="submit" class="space-y-4">
<div>
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
<label for="password" class="block text-sm font-medium text-gray-300">Password</label>
<input
id="password"
v-model="form.password"
type="password"
required
autofocus
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-600">{{ form.errors.password }}</p>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-400">{{ form.errors.password }}</p>
</div>
<button
type="submit"
:disabled="form.processing"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500 disabled:opacity-50"
>
Confirm
</button>

View File

@@ -18,35 +18,35 @@ const submit = () => {
</script>
<template>
<h2 class="text-xl font-semibold text-gray-900 mb-4">Reset your password</h2>
<p class="text-sm text-gray-600 mb-6">Enter your email and we'll send you a reset link.</p>
<h2 class="text-xl font-semibold text-white mb-4">Reset your password</h2>
<p class="text-sm text-gray-400 mb-6">Enter your email and we'll send you a reset link.</p>
<div v-if="status" class="mb-4 text-sm font-medium text-green-600">{{ status }}</div>
<div v-if="status" class="mb-4 text-sm font-medium text-green-400">{{ status }}</div>
<form @submit.prevent="submit" class="space-y-4">
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<label for="email" class="block text-sm font-medium text-gray-300">Email</label>
<input
id="email"
v-model="form.email"
type="email"
required
autofocus
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-600">{{ form.errors.email }}</p>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-400">{{ form.errors.email }}</p>
</div>
<button
type="submit"
:disabled="form.processing"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500 disabled:opacity-50"
>
Send reset link
</button>
<p class="text-center text-sm text-gray-600">
<a href="/login" class="text-blue-600 hover:text-blue-500">Back to login</a>
<p class="text-center text-sm text-gray-400">
<a href="/login" class="text-blue-400 hover:text-blue-300">Back to login</a>
</p>
</form>
</template>

View File

@@ -18,52 +18,52 @@ const submit = () => {
</script>
<template>
<h2 class="text-xl font-semibold text-gray-900 mb-6">Sign in to your account</h2>
<h2 class="text-xl font-semibold text-white mb-6">Sign in to your account</h2>
<form @submit.prevent="submit" class="space-y-4">
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<label for="email" class="block text-sm font-medium text-gray-300">Email</label>
<input
id="email"
v-model="form.email"
type="email"
required
autofocus
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-600">{{ form.errors.email }}</p>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-400">{{ form.errors.email }}</p>
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
<label for="password" class="block text-sm font-medium text-gray-300">Password</label>
<input
id="password"
v-model="form.password"
type="password"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-600">{{ form.errors.password }}</p>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-400">{{ form.errors.password }}</p>
</div>
<div class="flex items-center justify-between">
<label class="flex items-center">
<input v-model="form.remember" type="checkbox" class="rounded border-gray-300 text-blue-600" />
<span class="ml-2 text-sm text-gray-600">Remember me</span>
<input v-model="form.remember" type="checkbox" class="rounded bg-gray-800 border-gray-700 text-blue-600" />
<span class="ml-2 text-sm text-gray-400">Remember me</span>
</label>
<a href="/forgot-password" class="text-sm text-blue-600 hover:text-blue-500">Forgot password?</a>
<a href="/forgot-password" class="text-sm text-blue-400 hover:text-blue-300">Forgot password?</a>
</div>
<button
type="submit"
:disabled="form.processing"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500 disabled:opacity-50"
>
Sign in
</button>
<p class="text-center text-sm text-gray-600">
Don't have an account? <a href="/register" class="text-blue-600 hover:text-blue-500">Sign up</a>
<p class="text-center text-sm text-gray-400">
Don't have an account? <a href="/register" class="text-blue-400 hover:text-blue-300">Sign up</a>
</p>
</form>
</template>

View File

@@ -19,67 +19,67 @@ const submit = () => {
</script>
<template>
<h2 class="text-xl font-semibold text-gray-900 mb-6">Create an account</h2>
<h2 class="text-xl font-semibold text-white mb-6">Create an account</h2>
<form @submit.prevent="submit" class="space-y-4">
<div>
<label for="name" class="block text-sm font-medium text-gray-700">Name</label>
<label for="name" class="block text-sm font-medium text-gray-300">Name</label>
<input
id="name"
v-model="form.name"
type="text"
required
autofocus
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.name" class="mt-1 text-sm text-red-600">{{ form.errors.name }}</p>
<p v-if="form.errors.name" class="mt-1 text-sm text-red-400">{{ form.errors.name }}</p>
</div>
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<label for="email" class="block text-sm font-medium text-gray-300">Email</label>
<input
id="email"
v-model="form.email"
type="email"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-600">{{ form.errors.email }}</p>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-400">{{ form.errors.email }}</p>
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
<label for="password" class="block text-sm font-medium text-gray-300">Password</label>
<input
id="password"
v-model="form.password"
type="password"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-600">{{ form.errors.password }}</p>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-400">{{ form.errors.password }}</p>
</div>
<div>
<label for="password_confirmation" class="block text-sm font-medium text-gray-700">Confirm Password</label>
<label for="password_confirmation" class="block text-sm font-medium text-gray-300">Confirm Password</label>
<input
id="password_confirmation"
v-model="form.password_confirmation"
type="password"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
</div>
<button
type="submit"
:disabled="form.processing"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500 disabled:opacity-50"
>
Create account
</button>
<p class="text-center text-sm text-gray-600">
Already have an account? <a href="/login" class="text-blue-600 hover:text-blue-500">Sign in</a>
<p class="text-center text-sm text-gray-400">
Already have an account? <a href="/login" class="text-blue-400 hover:text-blue-300">Sign in</a>
</p>
</form>
</template>

View File

@@ -24,48 +24,48 @@ const submit = () => {
</script>
<template>
<h2 class="text-xl font-semibold text-gray-900 mb-6">Set new password</h2>
<h2 class="text-xl font-semibold text-white mb-6">Set new password</h2>
<form @submit.prevent="submit" class="space-y-4">
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<label for="email" class="block text-sm font-medium text-gray-300">Email</label>
<input
id="email"
v-model="form.email"
type="email"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-600">{{ form.errors.email }}</p>
<p v-if="form.errors.email" class="mt-1 text-sm text-red-400">{{ form.errors.email }}</p>
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700">New Password</label>
<label for="password" class="block text-sm font-medium text-gray-300">New Password</label>
<input
id="password"
v-model="form.password"
type="password"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-600">{{ form.errors.password }}</p>
<p v-if="form.errors.password" class="mt-1 text-sm text-red-400">{{ form.errors.password }}</p>
</div>
<div>
<label for="password_confirmation" class="block text-sm font-medium text-gray-700">Confirm Password</label>
<label for="password_confirmation" class="block text-sm font-medium text-gray-300">Confirm Password</label>
<input
id="password_confirmation"
v-model="form.password_confirmation"
type="password"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
</div>
<button
type="submit"
:disabled="form.processing"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500 disabled:opacity-50"
>
Reset password
</button>

View File

@@ -25,8 +25,8 @@ const toggleRecovery = () => {
</script>
<template>
<h2 class="text-xl font-semibold text-gray-900 mb-4">Two-Factor Authentication</h2>
<p class="text-sm text-gray-600 mb-6">
<h2 class="text-xl font-semibold text-white mb-4">Two-Factor Authentication</h2>
<p class="text-sm text-gray-400 mb-6">
<template v-if="!useRecovery">
Enter the authentication code from your authenticator app.
</template>
@@ -37,7 +37,7 @@ const toggleRecovery = () => {
<form @submit.prevent="submit" class="space-y-4">
<div v-if="!useRecovery">
<label for="code" class="block text-sm font-medium text-gray-700">Code</label>
<label for="code" class="block text-sm font-medium text-gray-300">Code</label>
<input
id="code"
v-model="form.code"
@@ -45,27 +45,27 @@ const toggleRecovery = () => {
inputmode="numeric"
autofocus
autocomplete="one-time-code"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.code" class="mt-1 text-sm text-red-600">{{ form.errors.code }}</p>
<p v-if="form.errors.code" class="mt-1 text-sm text-red-400">{{ form.errors.code }}</p>
</div>
<div v-else>
<label for="recovery_code" class="block text-sm font-medium text-gray-700">Recovery Code</label>
<label for="recovery_code" class="block text-sm font-medium text-gray-300">Recovery Code</label>
<input
id="recovery_code"
v-model="form.recovery_code"
type="text"
autofocus
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.recovery_code" class="mt-1 text-sm text-red-600">{{ form.errors.recovery_code }}</p>
<p v-if="form.errors.recovery_code" class="mt-1 text-sm text-red-400">{{ form.errors.recovery_code }}</p>
</div>
<button
type="submit"
:disabled="form.processing"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500 disabled:opacity-50"
>
Verify
</button>
@@ -73,7 +73,7 @@ const toggleRecovery = () => {
<button
type="button"
@click="toggleRecovery"
class="w-full text-center text-sm text-gray-600 hover:text-gray-900"
class="w-full text-center text-sm text-gray-400 hover:text-white"
>
{{ useRecovery ? 'Use authentication code' : 'Use a recovery code' }}
</button>

View File

@@ -16,12 +16,12 @@ const submit = () => {
</script>
<template>
<h2 class="text-xl font-semibold text-gray-900 mb-4">Verify your email</h2>
<p class="text-sm text-gray-600 mb-6">
<h2 class="text-xl font-semibold text-white mb-4">Verify your email</h2>
<p class="text-sm text-gray-400 mb-6">
We've sent a verification link to your email. Please check your inbox and click the link to verify.
</p>
<div v-if="status === 'verification-link-sent'" class="mb-4 text-sm font-medium text-green-600">
<div v-if="status === 'verification-link-sent'" class="mb-4 text-sm font-medium text-green-400">
A new verification link has been sent to your email address.
</div>
@@ -29,7 +29,7 @@ const submit = () => {
<button
type="submit"
:disabled="form.processing"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500 disabled:opacity-50"
>
Resend verification email
</button>

View File

@@ -1,5 +1,4 @@
<script setup>
import { ref } from 'vue';
import { useForm, Link } from '@inertiajs/vue3';
import AppLayout from '@/Layouts/AppLayout.vue';
@@ -13,10 +12,6 @@ defineProps({
stripeKey: String,
});
const addForm = useForm({
payment_method_id: '',
});
const defaultForm = useForm({
payment_method_id: '',
});
@@ -35,13 +30,13 @@ const removeMethod = (id) => {
<template>
<div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Billing</h1>
<h1 class="text-2xl font-bold text-white mb-6">Billing</h1>
<div class="space-y-8">
<!-- Payment Methods -->
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-gray-900">Payment Methods</h2>
<h2 class="text-lg font-semibold text-white">Payment Methods</h2>
</div>
<div v-if="paymentMethods.length === 0" class="text-sm text-gray-500">
@@ -53,26 +48,26 @@ const removeMethod = (id) => {
v-for="pm in paymentMethods"
:key="pm.id"
class="flex items-center justify-between p-3 border rounded-md"
:class="pm.is_default ? 'border-blue-300 bg-blue-50' : 'border-gray-200'"
:class="pm.is_default ? 'border-blue-700 bg-blue-900/20' : 'border-gray-700'"
>
<div class="flex items-center gap-3">
<span class="text-sm font-medium capitalize">{{ pm.brand }}</span>
<span class="text-sm font-medium text-gray-200 capitalize">{{ pm.brand }}</span>
<span class="text-sm text-gray-500">&bull;&bull;&bull;&bull; {{ pm.last_four }}</span>
<span class="text-sm text-gray-400">{{ pm.exp_month }}/{{ pm.exp_year }}</span>
<span v-if="pm.is_default" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800">Default</span>
<span class="text-sm text-gray-600">{{ pm.exp_month }}/{{ pm.exp_year }}</span>
<span v-if="pm.is_default" class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-900/50 text-blue-300 border border-blue-800">Default</span>
</div>
<div class="flex items-center gap-2">
<button
v-if="!pm.is_default"
@click="setDefault(pm.id)"
:disabled="defaultForm.processing"
class="text-sm text-blue-600 hover:text-blue-500"
class="text-sm text-blue-400 hover:text-blue-300"
>
Make Default
</button>
<button
@click="removeMethod(pm.id)"
class="text-sm text-red-600 hover:text-red-500"
class="text-sm text-red-400 hover:text-red-300"
>
Remove
</button>
@@ -82,17 +77,17 @@ const removeMethod = (id) => {
</div>
<!-- Recent Invoices -->
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-gray-900">Recent Invoices</h2>
<Link href="/billing/invoices" class="text-sm text-blue-600 hover:text-blue-500">View All</Link>
<h2 class="text-lg font-semibold text-white">Recent Invoices</h2>
<Link href="/billing/invoices" class="text-sm text-blue-400 hover:text-blue-300">View All</Link>
</div>
<div v-if="invoices.length === 0" class="text-sm text-gray-500">No invoices yet.</div>
<table v-else class="w-full text-sm">
<thead>
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-800">
<th class="text-left py-2 text-gray-500 font-medium">Number</th>
<th class="text-left py-2 text-gray-500 font-medium">Date</th>
<th class="text-left py-2 text-gray-500 font-medium">Status</th>
@@ -101,23 +96,23 @@ const removeMethod = (id) => {
</tr>
</thead>
<tbody>
<tr v-for="invoice in invoices" :key="invoice.id" class="border-b border-gray-100">
<td class="py-2 text-gray-900">{{ invoice.number }}</td>
<td class="py-2 text-gray-600">{{ new Date(invoice.created_at).toLocaleDateString() }}</td>
<tr v-for="invoice in invoices" :key="invoice.id" class="border-b border-gray-800/50">
<td class="py-2 text-gray-200">{{ invoice.number }}</td>
<td class="py-2 text-gray-400">{{ new Date(invoice.created_at).toLocaleDateString() }}</td>
<td class="py-2">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium capitalize"
:class="{
'bg-green-100 text-green-800': invoice.status === 'paid',
'bg-yellow-100 text-yellow-800': invoice.status === 'pending',
'bg-red-100 text-red-800': invoice.status === 'overdue',
'bg-green-900/50 text-green-300': invoice.status === 'paid',
'bg-yellow-900/50 text-yellow-300': invoice.status === 'pending',
'bg-red-900/50 text-red-300': invoice.status === 'overdue',
}"
>
{{ invoice.status }}
</span>
</td>
<td class="py-2 text-right text-gray-900">${{ parseFloat(invoice.total).toFixed(2) }}</td>
<td class="py-2 text-right text-gray-200">${{ parseFloat(invoice.total).toFixed(2) }}</td>
<td class="py-2 text-right">
<a :href="`/billing/invoices/${invoice.id}/download`" class="text-blue-600 hover:text-blue-500">Download</a>
<a :href="`/billing/invoices/${invoice.id}/download`" class="text-blue-400 hover:text-blue-300">Download</a>
</td>
</tr>
</tbody>
@@ -125,17 +120,17 @@ const removeMethod = (id) => {
</div>
<!-- Recent Transactions -->
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-gray-900">Recent Transactions</h2>
<Link href="/billing/transactions" class="text-sm text-blue-600 hover:text-blue-500">View All</Link>
<h2 class="text-lg font-semibold text-white">Recent Transactions</h2>
<Link href="/billing/transactions" class="text-sm text-blue-400 hover:text-blue-300">View All</Link>
</div>
<div v-if="transactions.length === 0" class="text-sm text-gray-500">No transactions yet.</div>
<table v-else class="w-full text-sm">
<thead>
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-800">
<th class="text-left py-2 text-gray-500 font-medium">Date</th>
<th class="text-left py-2 text-gray-500 font-medium">Gateway</th>
<th class="text-left py-2 text-gray-500 font-medium">Status</th>
@@ -144,22 +139,22 @@ const removeMethod = (id) => {
</tr>
</thead>
<tbody>
<tr v-for="tx in transactions" :key="tx.id" class="border-b border-gray-100">
<td class="py-2 text-gray-600">{{ new Date(tx.created_at).toLocaleDateString() }}</td>
<td class="py-2 text-gray-600 capitalize">{{ tx.gateway }}</td>
<tr v-for="tx in transactions" :key="tx.id" class="border-b border-gray-800/50">
<td class="py-2 text-gray-400">{{ new Date(tx.created_at).toLocaleDateString() }}</td>
<td class="py-2 text-gray-400 capitalize">{{ tx.gateway }}</td>
<td class="py-2">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium capitalize"
:class="{
'bg-green-100 text-green-800': tx.status === 'succeeded',
'bg-red-100 text-red-800': tx.status === 'failed',
'bg-yellow-100 text-yellow-800': tx.status === 'pending',
'bg-green-900/50 text-green-300': tx.status === 'succeeded',
'bg-red-900/50 text-red-300': tx.status === 'failed',
'bg-yellow-900/50 text-yellow-300': tx.status === 'pending',
}"
>
{{ tx.status }}
</span>
</td>
<td class="py-2 text-gray-600">{{ tx.description }}</td>
<td class="py-2 text-right text-gray-900">${{ parseFloat(tx.amount).toFixed(2) }}</td>
<td class="py-2 text-gray-400">{{ tx.description }}</td>
<td class="py-2 text-right text-gray-200">${{ parseFloat(tx.amount).toFixed(2) }}</td>
</tr>
</tbody>
</table>

View File

@@ -12,18 +12,18 @@ defineProps({
<template>
<div>
<div class="mb-4">
<Link href="/billing" class="text-sm text-blue-600 hover:text-blue-500">&larr; Back to Billing</Link>
<Link href="/billing" class="text-sm text-blue-400 hover:text-blue-300">&larr; Back to Billing</Link>
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Invoices</h1>
<h1 class="text-2xl font-bold text-white mb-6">Invoices</h1>
<div class="bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden">
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm overflow-hidden">
<div v-if="!invoices.data || invoices.data.length === 0" class="p-6 text-sm text-gray-500 text-center">
No invoices found.
</div>
<table v-else class="w-full text-sm">
<thead class="bg-gray-50">
<thead class="bg-gray-800/50">
<tr>
<th class="text-left px-6 py-3 text-gray-500 font-medium">Number</th>
<th class="text-left px-6 py-3 text-gray-500 font-medium">Date</th>
@@ -34,31 +34,31 @@ defineProps({
</tr>
</thead>
<tbody>
<tr v-for="invoice in invoices.data" :key="invoice.id" class="border-t border-gray-100">
<td class="px-6 py-3 text-gray-900">{{ invoice.number }}</td>
<td class="px-6 py-3 text-gray-600">{{ new Date(invoice.created_at).toLocaleDateString() }}</td>
<td class="px-6 py-3 text-gray-600 capitalize">{{ invoice.gateway }}</td>
<tr v-for="invoice in invoices.data" :key="invoice.id" class="border-t border-gray-800">
<td class="px-6 py-3 text-gray-200">{{ invoice.number }}</td>
<td class="px-6 py-3 text-gray-400">{{ new Date(invoice.created_at).toLocaleDateString() }}</td>
<td class="px-6 py-3 text-gray-400 capitalize">{{ invoice.gateway }}</td>
<td class="px-6 py-3">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium capitalize"
:class="{
'bg-green-100 text-green-800': invoice.status === 'paid',
'bg-yellow-100 text-yellow-800': invoice.status === 'pending',
'bg-red-100 text-red-800': invoice.status === 'overdue',
'bg-green-900/50 text-green-300': invoice.status === 'paid',
'bg-yellow-900/50 text-yellow-300': invoice.status === 'pending',
'bg-red-900/50 text-red-300': invoice.status === 'overdue',
}"
>
{{ invoice.status }}
</span>
</td>
<td class="px-6 py-3 text-right text-gray-900">${{ parseFloat(invoice.total).toFixed(2) }}</td>
<td class="px-6 py-3 text-right text-gray-200">${{ parseFloat(invoice.total).toFixed(2) }}</td>
<td class="px-6 py-3 text-right">
<a :href="`/billing/invoices/${invoice.id}/download`" class="text-blue-600 hover:text-blue-500">Download</a>
<a :href="`/billing/invoices/${invoice.id}/download`" class="text-blue-400 hover:text-blue-300">Download</a>
</td>
</tr>
</tbody>
</table>
<!-- Pagination -->
<div v-if="invoices.links && invoices.last_page > 1" class="px-6 py-3 border-t border-gray-200 flex items-center justify-between">
<div v-if="invoices.links && invoices.last_page > 1" class="px-6 py-3 border-t border-gray-800 flex items-center justify-between">
<div class="text-sm text-gray-500">
Showing {{ invoices.from }} to {{ invoices.to }} of {{ invoices.total }}
</div>
@@ -69,7 +69,7 @@ defineProps({
:href="link.url || '#'"
:class="[
'px-3 py-1 text-sm rounded',
link.active ? 'bg-blue-600 text-white' : 'text-gray-600 hover:bg-gray-100',
link.active ? 'bg-blue-600 text-white' : 'text-gray-400 hover:bg-gray-800',
!link.url && 'opacity-50 pointer-events-none',
]"
v-html="link.label"

View File

@@ -12,18 +12,18 @@ defineProps({
<template>
<div>
<div class="mb-4">
<Link href="/billing" class="text-sm text-blue-600 hover:text-blue-500">&larr; Back to Billing</Link>
<Link href="/billing" class="text-sm text-blue-400 hover:text-blue-300">&larr; Back to Billing</Link>
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Transactions</h1>
<h1 class="text-2xl font-bold text-white mb-6">Transactions</h1>
<div class="bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden">
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm overflow-hidden">
<div v-if="!transactions.data || transactions.data.length === 0" class="p-6 text-sm text-gray-500 text-center">
No transactions found.
</div>
<table v-else class="w-full text-sm">
<thead class="bg-gray-50">
<thead class="bg-gray-800/50">
<tr>
<th class="text-left px-6 py-3 text-gray-500 font-medium">Date</th>
<th class="text-left px-6 py-3 text-gray-500 font-medium">Gateway</th>
@@ -34,30 +34,30 @@ defineProps({
</tr>
</thead>
<tbody>
<tr v-for="tx in transactions.data" :key="tx.id" class="border-t border-gray-100">
<td class="px-6 py-3 text-gray-600">{{ new Date(tx.created_at).toLocaleDateString() }}</td>
<td class="px-6 py-3 text-gray-600 capitalize">{{ tx.gateway }}</td>
<td class="px-6 py-3 text-gray-600 capitalize">{{ tx.payment_method }}</td>
<tr v-for="tx in transactions.data" :key="tx.id" class="border-t border-gray-800">
<td class="px-6 py-3 text-gray-400">{{ new Date(tx.created_at).toLocaleDateString() }}</td>
<td class="px-6 py-3 text-gray-400 capitalize">{{ tx.gateway }}</td>
<td class="px-6 py-3 text-gray-400 capitalize">{{ tx.payment_method }}</td>
<td class="px-6 py-3">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium capitalize"
:class="{
'bg-green-100 text-green-800': tx.status === 'succeeded',
'bg-red-100 text-red-800': tx.status === 'failed',
'bg-yellow-100 text-yellow-800': tx.status === 'pending',
'bg-gray-100 text-gray-800': tx.status === 'refunded',
'bg-green-900/50 text-green-300': tx.status === 'succeeded',
'bg-red-900/50 text-red-300': tx.status === 'failed',
'bg-yellow-900/50 text-yellow-300': tx.status === 'pending',
'bg-gray-800 text-gray-400': tx.status === 'refunded',
}"
>
{{ tx.status }}
</span>
</td>
<td class="px-6 py-3 text-gray-600">{{ tx.description }}</td>
<td class="px-6 py-3 text-right text-gray-900">${{ parseFloat(tx.amount).toFixed(2) }}</td>
<td class="px-6 py-3 text-gray-400">{{ tx.description }}</td>
<td class="px-6 py-3 text-right text-gray-200">${{ parseFloat(tx.amount).toFixed(2) }}</td>
</tr>
</tbody>
</table>
<!-- Pagination -->
<div v-if="transactions.links && transactions.last_page > 1" class="px-6 py-3 border-t border-gray-200 flex items-center justify-between">
<div v-if="transactions.links && transactions.last_page > 1" class="px-6 py-3 border-t border-gray-800 flex items-center justify-between">
<div class="text-sm text-gray-500">
Showing {{ transactions.from }} to {{ transactions.to }} of {{ transactions.total }}
</div>
@@ -68,7 +68,7 @@ defineProps({
:href="link.url || '#'"
:class="[
'px-3 py-1 text-sm rounded',
link.active ? 'bg-blue-600 text-white' : 'text-gray-600 hover:bg-gray-100',
link.active ? 'bg-blue-600 text-white' : 'text-gray-400 hover:bg-gray-800',
!link.url && 'opacity-50 pointer-events-none',
]"
v-html="link.label"

View File

@@ -73,32 +73,32 @@ const submit = () => {
<template>
<div>
<div class="mb-4">
<Link href="/plans" class="text-sm text-blue-600 hover:text-blue-500">&larr; Back to Plans</Link>
<Link href="/plans" class="text-sm text-blue-400 hover:text-blue-300">&larr; Back to Plans</Link>
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Checkout</h1>
<h1 class="text-2xl font-bold text-white mb-6">Checkout</h1>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Order Summary -->
<div class="lg:col-span-1 order-2 lg:order-1">
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Order Summary</h2>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h2 class="text-lg font-semibold text-white mb-4">Order Summary</h2>
<div class="space-y-3">
<div class="flex justify-between text-sm">
<span class="text-gray-600">{{ plan.name }}</span>
<span class="text-gray-900">${{ parseFloat(plan.price).toFixed(2) }}</span>
<span class="text-gray-400">{{ plan.name }}</span>
<span class="text-white">${{ parseFloat(plan.price).toFixed(2) }}</span>
</div>
<div class="flex justify-between text-sm text-gray-500">
<span>Billing Cycle</span>
<span class="capitalize">{{ plan.billing_cycle }}</span>
</div>
<div v-if="couponApplied" class="flex justify-between text-sm text-green-600">
<div v-if="couponApplied" class="flex justify-between text-sm text-green-400">
<span>Discount</span>
<span>-${{ couponDiscount.toFixed(2) }}</span>
</div>
<hr class="border-gray-200">
<div class="flex justify-between font-semibold">
<hr class="border-gray-800">
<div class="flex justify-between font-semibold text-white">
<span>Total</span>
<span>${{ total }}/{{ plan.billing_cycle }}</span>
</div>
@@ -110,24 +110,24 @@ const submit = () => {
<div class="lg:col-span-2 order-1 lg:order-2">
<form @submit.prevent="submit" class="space-y-6">
<!-- Payment Gateway -->
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Payment Method</h2>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h2 class="text-lg font-semibold text-white mb-4">Payment Method</h2>
<div class="space-y-3">
<label class="flex items-center p-3 border rounded-md cursor-pointer" :class="selectedGateway === 'stripe' ? 'border-blue-500 bg-blue-50' : 'border-gray-200'">
<label class="flex items-center p-3 border rounded-md cursor-pointer" :class="selectedGateway === 'stripe' ? 'border-blue-500 bg-blue-900/20' : 'border-gray-700'">
<input v-model="selectedGateway" type="radio" value="stripe" class="mr-3">
<span class="text-sm font-medium">Credit / Debit Card (Stripe)</span>
<span class="text-sm font-medium text-gray-200">Credit / Debit Card (Stripe)</span>
</label>
<label class="flex items-center p-3 border rounded-md cursor-pointer" :class="selectedGateway === 'paypal' ? 'border-blue-500 bg-blue-50' : 'border-gray-200'">
<label class="flex items-center p-3 border rounded-md cursor-pointer" :class="selectedGateway === 'paypal' ? 'border-blue-500 bg-blue-900/20' : 'border-gray-700'">
<input v-model="selectedGateway" type="radio" value="paypal" class="mr-3">
<span class="text-sm font-medium">PayPal</span>
<span class="text-sm font-medium text-gray-200">PayPal</span>
</label>
</div>
<!-- Saved Payment Methods (Stripe) -->
<div v-if="selectedGateway === 'stripe' && paymentMethods.length > 0" class="mt-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Select Card</label>
<select v-model="selectedPaymentMethod" class="w-full rounded-md border-gray-300 text-sm">
<label class="block text-sm font-medium text-gray-300 mb-2">Select Card</label>
<select v-model="selectedPaymentMethod" class="w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 text-sm">
<option v-for="pm in paymentMethods" :key="pm.id" :value="pm.id">
{{ pm.brand }} ending in {{ pm.last_four }} ({{ pm.exp_month }}/{{ pm.exp_year }})
<template v-if="pm.is_default"> - Default</template>
@@ -138,39 +138,39 @@ const submit = () => {
<div v-if="selectedGateway === 'stripe' && paymentMethods.length === 0" class="mt-4">
<p class="text-sm text-gray-500">
You have no saved payment methods.
<Link href="/billing" class="text-blue-600 hover:text-blue-500">Add one first</Link>.
<Link href="/billing" class="text-blue-400 hover:text-blue-300">Add one first</Link>.
</p>
</div>
</div>
<!-- Coupon -->
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Coupon Code</h2>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h2 class="text-lg font-semibold text-white mb-4">Coupon Code</h2>
<div class="flex gap-3">
<input
v-model="couponCode"
type="text"
placeholder="Enter coupon code"
class="flex-1 rounded-md border-gray-300 text-sm"
class="flex-1 rounded-md bg-gray-800 border-gray-700 text-gray-100 text-sm placeholder-gray-500"
:disabled="couponApplied"
>
<button
type="button"
@click="applyCoupon"
:disabled="!couponCode || couponApplied"
class="px-4 py-2 bg-gray-100 text-sm font-medium text-gray-700 rounded-md hover:bg-gray-200 disabled:opacity-50"
class="px-4 py-2 bg-gray-800 text-sm font-medium text-gray-300 rounded-md hover:bg-gray-700 border border-gray-700 disabled:opacity-50"
>
{{ couponApplied ? 'Applied' : 'Apply' }}
</button>
</div>
<p v-if="couponError" class="mt-2 text-sm text-red-600">{{ couponError }}</p>
<p v-if="couponApplied" class="mt-2 text-sm text-green-600">Coupon applied successfully!</p>
<p v-if="couponError" class="mt-2 text-sm text-red-400">{{ couponError }}</p>
<p v-if="couponApplied" class="mt-2 text-sm text-green-400">Coupon applied successfully!</p>
</div>
<!-- Errors -->
<div v-if="form.errors && Object.keys(form.errors).length" class="rounded-md bg-red-50 p-4">
<ul class="list-disc list-inside text-sm text-red-600">
<div v-if="form.errors && Object.keys(form.errors).length" class="rounded-md bg-red-900/50 border border-red-800 p-4">
<ul class="list-disc list-inside text-sm text-red-300">
<li v-for="(error, field) in form.errors" :key="field">{{ error }}</li>
</ul>
</div>

View File

@@ -12,26 +12,26 @@ defineProps({
<template>
<div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Dashboard</h1>
<h1 class="text-2xl font-bold text-white mb-6">Dashboard</h1>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h3 class="text-sm font-medium text-gray-500">Total Services</h3>
<p class="mt-2 text-3xl font-bold text-gray-900">{{ servicesCount }}</p>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h3 class="text-sm font-medium text-gray-400">Total Services</h3>
<p class="mt-2 text-3xl font-bold text-white">{{ servicesCount }}</p>
</div>
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h3 class="text-sm font-medium text-gray-500">Active Services</h3>
<p class="mt-2 text-3xl font-bold text-green-600">{{ activeServicesCount }}</p>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h3 class="text-sm font-medium text-gray-400">Active Services</h3>
<p class="mt-2 text-3xl font-bold text-green-400">{{ activeServicesCount }}</p>
</div>
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h3 class="text-sm font-medium text-gray-500">Quick Actions</h3>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h3 class="text-sm font-medium text-gray-400">Quick Actions</h3>
<div class="mt-3 space-y-2">
<Link href="/plans" class="block text-sm text-blue-600 hover:text-blue-500">Browse Plans</Link>
<Link href="/subscriptions" class="block text-sm text-blue-600 hover:text-blue-500">My Subscriptions</Link>
<Link href="/billing" class="block text-sm text-blue-600 hover:text-blue-500">Billing & Payments</Link>
<Link href="/profile" class="block text-sm text-blue-600 hover:text-blue-500">Edit Profile</Link>
<Link href="/plans" class="block text-sm text-blue-400 hover:text-blue-300">Browse Plans</Link>
<Link href="/subscriptions" class="block text-sm text-blue-400 hover:text-blue-300">My Subscriptions</Link>
<Link href="/billing" class="block text-sm text-blue-400 hover:text-blue-300">Billing & Payments</Link>
<Link href="/profile" class="block text-sm text-blue-400 hover:text-blue-300">Edit Profile</Link>
</div>
</div>
</div>

View File

@@ -8,13 +8,13 @@ const accountUrl = computed(() => `https://${domains.value?.account}`);
</script>
<template>
<div class="min-h-screen bg-white">
<nav class="border-b border-gray-200">
<div class="min-h-screen bg-gray-950">
<nav class="border-b border-gray-800">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16 items-center">
<span class="text-xl font-bold text-gray-900">EZSCALE</span>
<span class="text-xl font-bold text-white">EZSCALE</span>
<div class="space-x-4">
<a :href="accountUrl + '/login'" class="text-sm text-gray-600 hover:text-gray-900">Sign in</a>
<a :href="accountUrl + '/login'" class="text-sm text-gray-400 hover:text-white">Sign in</a>
<a :href="accountUrl + '/register'" class="text-sm px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">Get Started</a>
</div>
</div>
@@ -23,11 +23,11 @@ const accountUrl = computed(() => `https://${domains.value?.account}`);
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24">
<div class="text-center">
<h1 class="text-4xl font-bold text-gray-900 sm:text-5xl md:text-6xl">
<h1 class="text-4xl font-bold text-white sm:text-5xl md:text-6xl">
Cloud Hosting
<span class="text-blue-600">Made Simple</span>
<span class="text-blue-400">Made Simple</span>
</h1>
<p class="mt-6 max-w-2xl mx-auto text-xl text-gray-500">
<p class="mt-6 max-w-2xl mx-auto text-xl text-gray-400">
VPS, Dedicated Servers, Web Hosting, and Game Servers. Powered by EZSCALE.
</p>
<div class="mt-10">

View File

@@ -23,10 +23,10 @@ const serviceTypeLabels = {
<template>
<div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Plans & Pricing</h1>
<h1 class="text-2xl font-bold text-white mb-6">Plans & Pricing</h1>
<div v-for="(plans, type) in plansByType" :key="type" class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-4">
<h2 class="text-xl font-semibold text-gray-200 mb-4">
{{ serviceTypeLabels[type] || type }}
</h2>
@@ -34,28 +34,28 @@ const serviceTypeLabels = {
<div
v-for="plan in plans"
:key="plan.id"
class="bg-white rounded-lg border border-gray-200 shadow-sm p-6 flex flex-col"
class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6 flex flex-col"
>
<h3 class="text-lg font-semibold text-gray-900">{{ plan.name }}</h3>
<p v-if="plan.description" class="mt-1 text-sm text-gray-500">{{ plan.description }}</p>
<h3 class="text-lg font-semibold text-white">{{ plan.name }}</h3>
<p v-if="plan.description" class="mt-1 text-sm text-gray-400">{{ plan.description }}</p>
<div class="mt-4">
<span class="text-3xl font-bold text-gray-900">
<span class="text-3xl font-bold text-white">
{{ formatPrice(plan.price, plan.billing_cycle) }}
</span>
</div>
<ul v-if="plan.features" class="mt-4 space-y-2 flex-1">
<li v-for="(value, feature) in plan.features" :key="feature" class="flex items-start text-sm text-gray-600">
<svg class="h-5 w-5 text-green-500 mr-2 shrink-0" fill="currentColor" viewBox="0 0 20 20">
<li v-for="(value, feature) in plan.features" :key="feature" class="flex items-start text-sm text-gray-400">
<svg class="h-5 w-5 text-green-400 mr-2 shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
<span><strong>{{ feature }}:</strong> {{ value }}</span>
<span><strong class="text-gray-300">{{ feature }}:</strong> {{ value }}</span>
</li>
</ul>
<div class="mt-6">
<span v-if="plan.stock_quantity !== null && plan.stock_quantity <= 0" class="block text-center text-sm font-medium text-red-600">
<span v-if="plan.stock_quantity !== null && plan.stock_quantity <= 0" class="block text-center text-sm font-medium text-red-400">
Out of Stock
</span>
<Link

View File

@@ -17,33 +17,33 @@ const formatPrice = (price, cycle) => {
<template>
<div>
<div class="mb-4">
<Link href="/plans" class="text-sm text-blue-600 hover:text-blue-500">&larr; Back to Plans</Link>
<Link href="/plans" class="text-sm text-blue-400 hover:text-blue-300">&larr; Back to Plans</Link>
</div>
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-8 max-w-2xl">
<h1 class="text-2xl font-bold text-gray-900">{{ plan.name }}</h1>
<p v-if="plan.description" class="mt-2 text-gray-500">{{ plan.description }}</p>
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-8 max-w-2xl">
<h1 class="text-2xl font-bold text-white">{{ plan.name }}</h1>
<p v-if="plan.description" class="mt-2 text-gray-400">{{ plan.description }}</p>
<div class="mt-6">
<span class="text-4xl font-bold text-gray-900">
<span class="text-4xl font-bold text-white">
{{ formatPrice(plan.price, plan.billing_cycle) }}
</span>
</div>
<div v-if="plan.features" class="mt-8">
<h2 class="text-lg font-semibold text-gray-900 mb-3">Features</h2>
<h2 class="text-lg font-semibold text-white mb-3">Features</h2>
<ul class="space-y-2">
<li v-for="(value, feature) in plan.features" :key="feature" class="flex items-start text-sm text-gray-600">
<svg class="h-5 w-5 text-green-500 mr-2 shrink-0" fill="currentColor" viewBox="0 0 20 20">
<li v-for="(value, feature) in plan.features" :key="feature" class="flex items-start text-sm text-gray-400">
<svg class="h-5 w-5 text-green-400 mr-2 shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
<span><strong>{{ feature }}:</strong> {{ value }}</span>
<span><strong class="text-gray-300">{{ feature }}:</strong> {{ value }}</span>
</li>
</ul>
</div>
<div class="mt-8">
<span v-if="plan.stock_quantity !== null && plan.stock_quantity <= 0" class="block text-center text-sm font-medium text-red-600">
<span v-if="plan.stock_quantity !== null && plan.stock_quantity <= 0" class="block text-center text-sm font-medium text-red-400">
This plan is currently out of stock.
</span>
<Link

View File

@@ -21,49 +21,49 @@ const submit = () => {
<template>
<div class="max-w-2xl">
<h1 class="text-2xl font-bold text-gray-900 mb-6">Profile Settings</h1>
<h1 class="text-2xl font-bold text-white mb-6">Profile Settings</h1>
<form @submit.prevent="submit" class="bg-white rounded-lg border border-gray-200 shadow-sm p-6 space-y-4">
<form @submit.prevent="submit" class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6 space-y-4">
<div>
<label for="name" class="block text-sm font-medium text-gray-700">Name</label>
<label for="name" class="block text-sm font-medium text-gray-300">Name</label>
<input
id="name"
v-model="form.name"
type="text"
required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="form.errors.name" class="mt-1 text-sm text-red-600">{{ form.errors.name }}</p>
<p v-if="form.errors.name" class="mt-1 text-sm text-red-400">{{ form.errors.name }}</p>
</div>
<div>
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<label for="email" class="block text-sm font-medium text-gray-300">Email</label>
<input
id="email"
:value="user.email"
type="email"
disabled
class="mt-1 block w-full rounded-md border-gray-200 bg-gray-50 shadow-sm px-3 py-2 border text-gray-500"
class="mt-1 block w-full rounded-md bg-gray-800/50 border-gray-700 shadow-sm px-3 py-2 border text-gray-500"
/>
</div>
<div>
<label for="phone" class="block text-sm font-medium text-gray-700">Phone</label>
<label for="phone" class="block text-sm font-medium text-gray-300">Phone</label>
<input
id="phone"
v-model="form.phone"
type="tel"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
</div>
<div>
<label for="company" class="block text-sm font-medium text-gray-700">Company</label>
<label for="company" class="block text-sm font-medium text-gray-300">Company</label>
<input
id="company"
v-model="form.company"
type="text"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
</div>

View File

@@ -69,8 +69,8 @@ const disableTwoFactor = () => {
<template>
<div class="max-w-2xl">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Two-Factor Authentication</h2>
<p class="text-sm text-gray-600 mb-6">
<h2 class="text-lg font-semibold text-white mb-4">Two-Factor Authentication</h2>
<p class="text-sm text-gray-400 mb-6">
Add an extra layer of security to your account using a TOTP authenticator app.
</p>
@@ -85,22 +85,22 @@ const disableTwoFactor = () => {
</div>
<div v-if="confirming" class="mt-6">
<p class="text-sm text-gray-600 mb-4">
<p class="text-sm text-gray-400 mb-4">
Scan this QR code with your authenticator app, then enter the code below to confirm.
</p>
<div v-if="qrCode" v-html="qrCode" class="mb-4"></div>
<div v-if="qrCode" v-html="qrCode" class="mb-4 [&_svg]:fill-white"></div>
<form @submit.prevent="confirmTwoFactor" class="space-y-4 max-w-xs">
<div>
<label for="code" class="block text-sm font-medium text-gray-700">Confirmation Code</label>
<label for="code" class="block text-sm font-medium text-gray-300">Confirmation Code</label>
<input
id="code"
v-model="confirmationForm.code"
type="text"
inputmode="numeric"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
class="mt-1 block w-full rounded-md bg-gray-800 border-gray-700 text-gray-100 shadow-sm focus:border-blue-500 focus:ring-blue-500 px-3 py-2 border"
/>
<p v-if="confirmationForm.errors.code" class="mt-1 text-sm text-red-600">{{ confirmationForm.errors.code }}</p>
<p v-if="confirmationForm.errors.code" class="mt-1 text-sm text-red-400">{{ confirmationForm.errors.code }}</p>
</div>
<button
type="submit"
@@ -113,15 +113,15 @@ const disableTwoFactor = () => {
</div>
<div v-if="recoveryCodes.length > 0 && !confirming" class="mt-6">
<h3 class="text-sm font-semibold text-gray-900 mb-2">Recovery Codes</h3>
<p class="text-sm text-gray-600 mb-3">Store these codes in a safe place. They can be used to access your account if you lose your authenticator device.</p>
<div class="bg-gray-100 rounded-md p-4 font-mono text-sm">
<h3 class="text-sm font-semibold text-white mb-2">Recovery Codes</h3>
<p class="text-sm text-gray-400 mb-3">Store these codes in a safe place. They can be used to access your account if you lose your authenticator device.</p>
<div class="bg-gray-800 rounded-md p-4 font-mono text-sm text-gray-300">
<div v-for="code in recoveryCodes" :key="code">{{ code }}</div>
</div>
</div>
<div v-if="page.props.auth?.user?.two_factor_enabled && !confirming" class="mt-6">
<p class="text-sm text-green-600 mb-4">Two-factor authentication is enabled.</p>
<p class="text-sm text-green-400 mb-4">Two-factor authentication is enabled.</p>
<button
@click="disableTwoFactor"
:disabled="disabling"

View File

@@ -9,37 +9,37 @@ defineProps({
});
const statusColors = {
active: 'bg-green-100 text-green-800',
canceled: 'bg-red-100 text-red-800',
past_due: 'bg-yellow-100 text-yellow-800',
trialing: 'bg-blue-100 text-blue-800',
incomplete: 'bg-gray-100 text-gray-800',
active: 'bg-green-900/50 text-green-300 border border-green-800',
canceled: 'bg-red-900/50 text-red-300 border border-red-800',
past_due: 'bg-yellow-900/50 text-yellow-300 border border-yellow-800',
trialing: 'bg-blue-900/50 text-blue-300 border border-blue-800',
incomplete: 'bg-gray-800 text-gray-400 border border-gray-700',
};
</script>
<template>
<div>
<div class="flex items-center justify-between mb-6">
<h1 class="text-2xl font-bold text-gray-900">Subscriptions</h1>
<h1 class="text-2xl font-bold text-white">Subscriptions</h1>
<Link href="/plans" class="px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-md hover:bg-blue-700">
Browse Plans
</Link>
</div>
<div v-if="subscriptions.length === 0" class="bg-white rounded-lg border border-gray-200 shadow-sm p-12 text-center">
<div v-if="subscriptions.length === 0" class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-12 text-center">
<p class="text-gray-500 mb-4">You don't have any subscriptions yet.</p>
<Link href="/plans" class="text-blue-600 hover:text-blue-500 text-sm font-medium">Browse Available Plans</Link>
<Link href="/plans" class="text-blue-400 hover:text-blue-300 text-sm font-medium">Browse Available Plans</Link>
</div>
<div v-else class="space-y-4">
<div
v-for="subscription in subscriptions"
:key="subscription.id"
class="bg-white rounded-lg border border-gray-200 shadow-sm p-6"
class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6"
>
<div class="flex items-center justify-between">
<div>
<h3 class="text-lg font-semibold text-gray-900">
<h3 class="text-lg font-semibold text-white">
{{ subscription.plan?.name || subscription.type }}
</h3>
<p class="text-sm text-gray-500 mt-1">
@@ -51,25 +51,25 @@ const statusColors = {
</div>
<div class="flex items-center gap-3">
<span
:class="statusColors[subscription.stripe_status] || 'bg-gray-100 text-gray-800'"
:class="statusColors[subscription.stripe_status] || 'bg-gray-800 text-gray-400'"
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium capitalize"
>
{{ subscription.stripe_status }}
</span>
<Link
:href="`/subscriptions/${subscription.id}`"
class="text-sm text-blue-600 hover:text-blue-500 font-medium"
class="text-sm text-blue-400 hover:text-blue-300 font-medium"
>
Manage
</Link>
</div>
</div>
<div v-if="subscription.plan" class="mt-3 text-sm text-gray-600">
<div v-if="subscription.plan" class="mt-3 text-sm text-gray-400">
${{ parseFloat(subscription.plan.price).toFixed(2) }}/{{ subscription.plan.billing_cycle }}
</div>
<div v-if="subscription.ends_at" class="mt-2 text-sm text-red-600">
<div v-if="subscription.ends_at" class="mt-2 text-sm text-red-400">
Cancels on {{ new Date(subscription.ends_at).toLocaleDateString() }}
</div>
</div>

View File

@@ -21,11 +21,11 @@ const swapForm = useForm({
});
const statusColors = {
active: 'bg-green-100 text-green-800',
canceled: 'bg-red-100 text-red-800',
past_due: 'bg-yellow-100 text-yellow-800',
trialing: 'bg-blue-100 text-blue-800',
incomplete: 'bg-gray-100 text-gray-800',
active: 'bg-green-900/50 text-green-300 border border-green-800',
canceled: 'bg-red-900/50 text-red-300 border border-red-800',
past_due: 'bg-yellow-900/50 text-yellow-300 border border-yellow-800',
trialing: 'bg-blue-900/50 text-blue-300 border border-blue-800',
incomplete: 'bg-gray-800 text-gray-400 border border-gray-700',
};
const cancelSubscription = () => {
@@ -45,21 +45,21 @@ const swapPlan = () => {
<template>
<div>
<div class="mb-4">
<Link href="/subscriptions" class="text-sm text-blue-600 hover:text-blue-500">&larr; Back to Subscriptions</Link>
<Link href="/subscriptions" class="text-sm text-blue-400 hover:text-blue-300">&larr; Back to Subscriptions</Link>
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-6">Subscription Details</h1>
<h1 class="text-2xl font-bold text-white mb-6">Subscription Details</h1>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Subscription Info -->
<div class="lg:col-span-2 space-y-6">
<div class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<div class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-gray-900">
<h2 class="text-lg font-semibold text-white">
{{ subscription.plan?.name || subscription.type }}
</h2>
<span
:class="statusColors[subscription.stripe_status] || 'bg-gray-100 text-gray-800'"
:class="statusColors[subscription.stripe_status] || 'bg-gray-800 text-gray-400'"
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium capitalize"
>
{{ subscription.stripe_status }}
@@ -69,46 +69,46 @@ const swapPlan = () => {
<dl class="grid grid-cols-2 gap-4 text-sm">
<div>
<dt class="text-gray-500">Gateway</dt>
<dd class="mt-1 text-gray-900 capitalize">{{ subscription.gateway || 'stripe' }}</dd>
<dd class="mt-1 text-gray-200 capitalize">{{ subscription.gateway || 'stripe' }}</dd>
</div>
<div v-if="subscription.plan">
<dt class="text-gray-500">Price</dt>
<dd class="mt-1 text-gray-900">${{ parseFloat(subscription.plan.price).toFixed(2) }}/{{ subscription.plan.billing_cycle }}</dd>
<dd class="mt-1 text-gray-200">${{ parseFloat(subscription.plan.price).toFixed(2) }}/{{ subscription.plan.billing_cycle }}</dd>
</div>
<div v-if="subscription.current_period_start">
<dt class="text-gray-500">Current Period Start</dt>
<dd class="mt-1 text-gray-900">{{ new Date(subscription.current_period_start).toLocaleDateString() }}</dd>
<dd class="mt-1 text-gray-200">{{ new Date(subscription.current_period_start).toLocaleDateString() }}</dd>
</div>
<div v-if="subscription.current_period_end">
<dt class="text-gray-500">Current Period End</dt>
<dd class="mt-1 text-gray-900">{{ new Date(subscription.current_period_end).toLocaleDateString() }}</dd>
<dd class="mt-1 text-gray-200">{{ new Date(subscription.current_period_end).toLocaleDateString() }}</dd>
</div>
<div v-if="subscription.ends_at">
<dt class="text-gray-500">Cancels On</dt>
<dd class="mt-1 text-red-600">{{ new Date(subscription.ends_at).toLocaleDateString() }}</dd>
<dd class="mt-1 text-red-400">{{ new Date(subscription.ends_at).toLocaleDateString() }}</dd>
</div>
<div>
<dt class="text-gray-500">Created</dt>
<dd class="mt-1 text-gray-900">{{ new Date(subscription.created_at).toLocaleDateString() }}</dd>
<dd class="mt-1 text-gray-200">{{ new Date(subscription.created_at).toLocaleDateString() }}</dd>
</div>
</dl>
</div>
<!-- Change Plan -->
<div v-if="availablePlans.length > 0 && subscription.stripe_status === 'active'" class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Change Plan</h2>
<div v-if="availablePlans.length > 0 && subscription.stripe_status === 'active'" class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h2 class="text-lg font-semibold text-white mb-4">Change Plan</h2>
<form @submit.prevent="swapPlan" class="space-y-4">
<div class="space-y-2">
<label v-for="plan in availablePlans" :key="plan.id"
class="flex items-center justify-between p-3 border rounded-md cursor-pointer"
:class="swapForm.plan_id == plan.id ? 'border-blue-500 bg-blue-50' : 'border-gray-200'"
:class="swapForm.plan_id == plan.id ? 'border-blue-500 bg-blue-900/20' : 'border-gray-700'"
>
<div class="flex items-center">
<input v-model="swapForm.plan_id" type="radio" :value="plan.id" class="mr-3">
<span class="text-sm font-medium">{{ plan.name }}</span>
<span class="text-sm font-medium text-gray-200">{{ plan.name }}</span>
</div>
<span class="text-sm text-gray-600">${{ parseFloat(plan.price).toFixed(2) }}/{{ plan.billing_cycle }}</span>
<span class="text-sm text-gray-400">${{ parseFloat(plan.price).toFixed(2) }}/{{ plan.billing_cycle }}</span>
</label>
</div>
@@ -126,12 +126,12 @@ const swapPlan = () => {
<!-- Actions Sidebar -->
<div class="space-y-6">
<!-- Cancel -->
<div v-if="subscription.stripe_status === 'active' && !subscription.ends_at" class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Cancel Subscription</h2>
<div v-if="subscription.stripe_status === 'active' && !subscription.ends_at" class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h2 class="text-lg font-semibold text-white mb-4">Cancel Subscription</h2>
<div class="space-y-3">
<label class="flex items-center text-sm">
<input v-model="cancelImmediately" type="checkbox" class="mr-2">
<label class="flex items-center text-sm text-gray-300">
<input v-model="cancelImmediately" type="checkbox" class="mr-2 rounded bg-gray-800 border-gray-700">
Cancel immediately (no grace period)
</label>
@@ -146,8 +146,8 @@ const swapPlan = () => {
</div>
<!-- Resume -->
<div v-if="subscription.ends_at && subscription.stripe_status !== 'canceled'" class="bg-white rounded-lg border border-gray-200 shadow-sm p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Resume Subscription</h2>
<div v-if="subscription.ends_at && subscription.stripe_status !== 'canceled'" class="bg-gray-900 rounded-lg border border-gray-800 shadow-sm p-6">
<h2 class="text-lg font-semibold text-white mb-4">Resume Subscription</h2>
<p class="text-sm text-gray-500 mb-3">Your subscription is set to cancel. You can resume it before it expires.</p>
<button

View File

@@ -12,7 +12,7 @@
@vite(['resources/js/app.js'])
@inertiaHead
</head>
<body class="font-sans antialiased">
<body class="font-sans antialiased bg-gray-950 text-gray-100">
@inertia
</body>
</html>