More styling
This commit is contained in:
@@ -77,13 +77,13 @@
|
||||
|
||||
<button
|
||||
onclick={handleDisconnect}
|
||||
class="text-sm text-red-600 hover:text-red-800 flex items-center gap-1 whitespace-nowrap mt-1 sm:mt-0"
|
||||
class="flex items-center gap-2 rounded-full bg-red-100 px-3 py-1 border border-red-300 hover:bg-red-200 transition-colors whitespace-nowrap"
|
||||
aria-label="Disconnect from Google"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0 text-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
Disconnect
|
||||
<span class="text-sm font-medium text-red-800">Disconnect</span>
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
@@ -180,47 +180,58 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Bottom actions -->
|
||||
<div class="fixed bottom-6 left-1/2 -translate-x-1/2 z-50 flex items-center gap-4">
|
||||
<!-- Search bar -->
|
||||
<div class="relative mr-4">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={searchTerm}
|
||||
oninput={handleSearchInput}
|
||||
placeholder="Search events..."
|
||||
class="w-64 pl-10 pr-4 py-3 rounded-full border border-gray-300 bg-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
<div class="absolute left-3 top-1/2 -translate-y-1/2">
|
||||
{#if isSearching}
|
||||
<svg class="animate-spin h-4 w-4 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg class="h-4 w-4 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
<!-- Bottom actions - Mobile optimized -->
|
||||
<div class="fixed bottom-0 left-0 right-0 z-50 bg-white border-t border-gray-300 shadow-lg pb-safe">
|
||||
<!-- Search bar and New Event button layout -->
|
||||
<div class="max-w-2xl mx-auto px-4 py-3 flex flex-col sm:flex-row gap-3 sm:items-center">
|
||||
<!-- Search bar - Full width on mobile, adaptive on desktop -->
|
||||
<div class="relative flex-grow">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={searchTerm}
|
||||
oninput={handleSearchInput}
|
||||
placeholder="Search events..."
|
||||
class="w-full pl-10 pr-10 py-2.5 rounded-lg border border-gray-300 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
<div class="absolute left-3 top-1/2 -translate-y-1/2">
|
||||
{#if isSearching}
|
||||
<svg class="animate-spin h-4 w-4 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg class="h-4 w-4 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
{/if}
|
||||
</div>
|
||||
{#if searchTerm}
|
||||
<button
|
||||
onclick={clearSearch}
|
||||
class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||
aria-label="Clear search"
|
||||
>
|
||||
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{#if searchTerm}
|
||||
<button
|
||||
onclick={clearSearch}
|
||||
class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||
aria-label="Clear search"
|
||||
>
|
||||
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- New Event button -->
|
||||
<a
|
||||
href="/private/events/event/new"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-full border border-gray-300 transition whitespace-nowrap"
|
||||
>
|
||||
New Event
|
||||
</a>
|
||||
</div>
|
||||
<!-- New Event button - Adaptive width -->
|
||||
<a
|
||||
href="/private/events/event/new"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2.5 px-6 rounded-lg transition text-center whitespace-nowrap sm:flex-shrink-0"
|
||||
>
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
New Event
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add padding to bottom of content to prevent overlap with fixed bottom bar -->
|
||||
<div class="h-24"></div>
|
||||
@@ -417,7 +417,19 @@
|
||||
<!-- Step Content -->
|
||||
<div class="rounded-lg border border-gray-300 bg-white p-6 mb-4">
|
||||
{#if currentStep === 0}
|
||||
<GoogleAuthStep bind:authData bind:errors {connectToGoogle} {cancelGoogleAuth} {disconnectGoogle} />
|
||||
<GoogleAuthStep
|
||||
bind:errors
|
||||
onSuccess={(token) => {
|
||||
authData.error = null;
|
||||
authData.token = token;
|
||||
authData.isConnected = true;
|
||||
setTimeout(checkGoogleAuth, 100);
|
||||
}}
|
||||
onError={(error) => {
|
||||
authData.error = error;
|
||||
authData.isConnected = false;
|
||||
}}
|
||||
/>
|
||||
{:else if currentStep === 1}
|
||||
<EventDetailsStep bind:eventData bind:errors />
|
||||
{:else if currentStep === 2}
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
<script lang="ts">
|
||||
import GoogleAuthButton from '$lib/components/GoogleAuthButton.svelte';
|
||||
|
||||
// Props
|
||||
let { authData, errors, connectToGoogle, cancelGoogleAuth, disconnectGoogle } = $props<{
|
||||
authData: {
|
||||
isConnected: boolean;
|
||||
checking: boolean;
|
||||
connecting: boolean;
|
||||
showCancelOption: boolean;
|
||||
token: string | null;
|
||||
error: string | null;
|
||||
userEmail: string | null;
|
||||
};
|
||||
let { errors, onSuccess, onError } = $props<{
|
||||
errors: Record<string, string>;
|
||||
connectToGoogle: () => Promise<void>;
|
||||
cancelGoogleAuth: () => void;
|
||||
disconnectGoogle: () => Promise<void>;
|
||||
onSuccess?: (token: string) => void;
|
||||
onError?: (error: string) => void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
@@ -24,121 +16,17 @@
|
||||
To create events and import participants from Google Sheets, you need to connect your Google account.
|
||||
</p>
|
||||
|
||||
{#if authData.checking}
|
||||
<div class="flex justify-center items-center space-x-2">
|
||||
<div class="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-600"></div>
|
||||
<span class="text-gray-600">Checking connection...</span>
|
||||
</div>
|
||||
{:else if authData.isConnected}
|
||||
<div class="rounded-lg bg-green-50 border border-green-200 p-4 mb-4">
|
||||
<div class="flex items-center justify-start">
|
||||
<div class="justify-start flex flex-col items-start">
|
||||
<p class="text-sm font-medium text-green-800">
|
||||
Google account connected successfully!
|
||||
</p>
|
||||
{#if authData.userEmail}
|
||||
<div class="flex items-center mt-2 bg-white rounded-full px-3 py-1 border border-green-300">
|
||||
<p class="text-sm font-medium text-gray-700">
|
||||
{authData.userEmail}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
<p class="text-sm text-green-700 mt-2">
|
||||
You can now access Google Sheets and Gmail features.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button
|
||||
onclick={disconnectGoogle}
|
||||
class="text-sm text-red-600 hover:text-red-800 flex items-center"
|
||||
aria-label="Disconnect Google account"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
Disconnect
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="rounded-lg bg-yellow-50 border border-yellow-200 p-4 mb-4">
|
||||
<div class="flex items-center justify-start">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3 justify-start flex flex-col items-start">
|
||||
<p class="text-sm font-medium text-yellow-800">
|
||||
Google account not connected
|
||||
</p>
|
||||
<p class="text-sm text-yellow-700 mt-1">
|
||||
Please connect your Google account to continue with event creation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<GoogleAuthButton
|
||||
size="large"
|
||||
variant="primary"
|
||||
onSuccess={onSuccess}
|
||||
onError={onError}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<button
|
||||
onclick={connectToGoogle}
|
||||
disabled={authData.connecting}
|
||||
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
aria-label="Connect to Google account"
|
||||
>
|
||||
{#if authData.connecting}
|
||||
<div class="w-5 h-5 mr-2 animate-spin rounded-full border-2 border-white border-t-transparent"></div>
|
||||
Connecting...
|
||||
{:else}
|
||||
<svg class="w-5 h-5 mr-2" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
||||
<path fill="currentColor" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
||||
<path fill="currentColor" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
||||
<path fill="currentColor" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
||||
</svg>
|
||||
Connect to Google
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
{#if authData.connecting && authData.showCancelOption}
|
||||
<button
|
||||
onclick={cancelGoogleAuth}
|
||||
class="text-sm text-gray-600 hover:text-gray-900"
|
||||
aria-label="Cancel Google authentication"
|
||||
>
|
||||
Cancel connection
|
||||
</button>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
Taking too long? You can cancel and try again.
|
||||
</p>
|
||||
{/if}
|
||||
{#if errors.google}
|
||||
<div class="mt-4 text-sm text-red-600">
|
||||
{errors.google}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if authData.error}
|
||||
<div class="mt-4 rounded-lg bg-red-50 border border-red-200 p-4">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-red-800">
|
||||
Connection Error
|
||||
</p>
|
||||
<p class="text-sm text-red-700 mt-1">
|
||||
{authData.error}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if errors.auth}
|
||||
<p class="mt-2 text-sm text-red-600">{errors.auth}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import GoogleAuthButton from './components/GoogleAuthButton.svelte';
|
||||
import GoogleAuthButton from '$lib/components/GoogleAuthButton.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user