From 708af813a80af5e0340ba1f51ed0a3139c50f396 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 19:38:28 +0000 Subject: [PATCH 01/20] ScreenReader: Testing tower name fix --- .../components/layout/TowersDropdown.tsx | 1 + .../tools/actions/fetchSupabaseProfileSA.ts | 82 ++++++++++--------- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/clocktower/components/layout/TowersDropdown.tsx b/clocktower/components/layout/TowersDropdown.tsx index c0f8a7c..1a2ef97 100644 --- a/clocktower/components/layout/TowersDropdown.tsx +++ b/clocktower/components/layout/TowersDropdown.tsx @@ -197,6 +197,7 @@ const TowersDropdown = ({ user }: { user: User | null }) => { {towers.map((tower) => ( { if (currentValue === selectedTowerName) return diff --git a/clocktower/tools/actions/fetchSupabaseProfileSA.ts b/clocktower/tools/actions/fetchSupabaseProfileSA.ts index 86b261e..4de2e2f 100644 --- a/clocktower/tools/actions/fetchSupabaseProfileSA.ts +++ b/clocktower/tools/actions/fetchSupabaseProfileSA.ts @@ -1,50 +1,56 @@ 'use server' -import type { Profile, ServerActionReturn } from "@/types/schemas"; -import { createServerActionClient } from "@supabase/auth-helpers-nextjs"; -import { UUID } from "crypto"; +import type { Profile, ServerActionReturn } from '@/types/schemas' +import { createServerActionClient } from '@supabase/auth-helpers-nextjs' import { cookies } from 'next/headers' -import extractErrorMessage from "../extractErrorMessage"; -import { generateUsername } from "../nameGenerators"; +import extractErrorMessage from '../extractErrorMessage' +import { generateUsername } from '../nameGenerators' -const fetchSupabaseProfileSA = async (userId: string): Promise> => { - const supabase = createServerActionClient( {cookies} ) +const fetchSupabaseProfileSA = async ( + userId: string, +): Promise> => { + const supabase = createServerActionClient({ cookies }) try { + const { data: profileData, error: profileError } = await supabase + .from('profiles') + .select('*') + .eq('id', userId) + + if (profileError) throw profileError + + // If there is no profile data, then create a new profile + if ( + !profileData || + profileData.length === 0 || + profileData[0] === undefined + ) { + createNewProfile(userId) + } - const {data: profileData, error: profileError } = await supabase - .from('profiles') - .select('*') - .eq('id', userId) - - if (profileError) throw profileError - - // If there is no profile data, then create a new profile - if (!profileData || profileData.length === 0 || profileData[0] === undefined) { - createNewProfile(userId) - } - - return { data: profileData[0] as Profile} - } catch(error) { - return { error: extractErrorMessage(error, 'Unknown error from fetchSupabaseProfileSA.') } -} + return { data: profileData[0] as Profile } + } catch (error) { + return { + error: extractErrorMessage( + error, + 'Unknown error from fetchSupabaseProfileSA.', + ), + } + } } const createNewProfile = async (newProfileId: string) => { - const supabase = createServerActionClient( {cookies} ) - - const newProfile = { - id : newProfileId, - username: generateUsername(), - color: '#FFFFFF', - avatar_set: 1, - reduce_motion: false, - } + const supabase = createServerActionClient({ cookies }) + + const newProfile = { + id: newProfileId, + username: generateUsername(), + color: '#FFFFFF', + avatar_set: 1, + reduce_motion: false, + } - const { error } = await supabase - .from('profiles') - .upsert(newProfile) + const { error } = await supabase.from('profiles').upsert(newProfile) - if (error) throw error + if (error) throw error } - -export default fetchSupabaseProfileSA \ No newline at end of file +export default fetchSupabaseProfileSA From 19f1cda3f1c7b7330ed5a90e7f2c00be29c2604b Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 19:42:23 +0000 Subject: [PATCH 02/20] ScreenReader: Seeing if Label works --- clocktower/components/layout/TowersDropdown.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clocktower/components/layout/TowersDropdown.tsx b/clocktower/components/layout/TowersDropdown.tsx index 1a2ef97..ad7479a 100644 --- a/clocktower/components/layout/TowersDropdown.tsx +++ b/clocktower/components/layout/TowersDropdown.tsx @@ -26,6 +26,7 @@ import { GoPlusCircle } from 'react-icons/go' import insertNewTowerSA from '@/tools/actions/insertNewTowerSA' import { Database } from '@/types/supabase' import { capitalizeFirstLetterOfEveryWord } from '@/tools/capitalizeFirstLetterOfEveryWord' +import { Label } from '../ui' const TowersDropdown = ({ user }: { user: User | null }) => { const router = useRouter() @@ -209,7 +210,7 @@ const TowersDropdown = ({ user }: { user: User | null }) => { }} > - {tower.name} + ))} From dde0317531c0fcb83cb8455ac2b02dd8de487c9c Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 19:47:23 +0000 Subject: [PATCH 03/20] trying id change 1 --- clocktower/components/layout/TowersDropdown.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/clocktower/components/layout/TowersDropdown.tsx b/clocktower/components/layout/TowersDropdown.tsx index ad7479a..55d22f2 100644 --- a/clocktower/components/layout/TowersDropdown.tsx +++ b/clocktower/components/layout/TowersDropdown.tsx @@ -209,8 +209,11 @@ const TowersDropdown = ({ user }: { user: User | null }) => { navigateToSelectedTower(tower.id) }} > - - + + ))} From e4884ccf55190651ababcb14394d10448935c902 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 19:53:32 +0000 Subject: [PATCH 04/20] clock dialog settings --- .../[id]/components/ClockSettingsDialog.tsx | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx b/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx index 3ae953f..99dbfc6 100644 --- a/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx +++ b/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx @@ -272,10 +272,11 @@ const ClockSettingsDialog: FC = ({
- + @@ -285,7 +286,11 @@ const ClockSettingsDialog: FC = ({ {configuredPieChart} - @@ -299,6 +304,7 @@ const ClockSettingsDialog: FC = ({ Cancel @@ -310,9 +316,13 @@ const ClockSettingsDialog: FC = ({
- +
= ({
- + = ({ />
- +
- + From 9761563734793b248753b3fd789b39ae9d0c4d18 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 19:56:49 +0000 Subject: [PATCH 05/20] labeled directly --- .../app/tower/[id]/components/ClockSettingsDialog.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx b/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx index 99dbfc6..516424f 100644 --- a/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx +++ b/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx @@ -316,13 +316,10 @@ const ClockSettingsDialog: FC = ({
- +
Date: Sat, 6 Jan 2024 20:01:47 +0000 Subject: [PATCH 06/20] Trying describedby and labeledby --- .../app/tower/[id]/components/ClockSettingsDialog.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx b/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx index 516424f..649bad3 100644 --- a/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx +++ b/clocktower/app/tower/[id]/components/ClockSettingsDialog.tsx @@ -316,10 +316,13 @@ const ClockSettingsDialog: FC = ({
- +
= ({
- + Date: Sat, 6 Jan 2024 20:14:16 +0000 Subject: [PATCH 07/20] attempt at reduced motion clock --- .../tower/[id]/components/RealtimeClock.tsx | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index 1b02052..e453b94 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -281,13 +281,43 @@ const RealtimeClock: React.FC = ({ initialData }) => { /> ) + const reducedMotionChart = ( +
+

{clockData.name}

+

Segments: {clockData.segments}

+

+ Filled: {clockData.filled !== null ? clockData.filled + 1 : 0} of + {clockData.segments} +

+

+ Percentage Filled: + {clockData.filled !== null + ? (clockData.filled + 1) / clockData.segments + : 0} +

+ {/* Add any additional information you want to display */} +
+ ) + + const reduceMotion = true + + let displayedChart: React.JSX.Element + + if (reduceMotion) { + displayedChart = reducedMotionChart + } else if (hasEditAccess) { + displayedChart = configuredPieChart + } else { + displayedChart = readOnlyPieChart + } + return ( <> {!isDeleted && (
- {hasEditAccess ? configuredPieChart : readOnlyPieChart} + {displayedChart}
From 9c994fbfabd85c00423ade14bc886a768e43548b Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 20:36:08 +0000 Subject: [PATCH 08/20] Using Input to be able to update clock --- .../tower/[id]/components/RealtimeClock.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index e453b94..015b7a9 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect, MouseEvent, Suspense } from 'react' import { PieChart } from 'react-minimal-pie-chart' import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' -import { toast } from '@/components/ui' +import { Input, Label, toast } from '@/components/ui' import { lightenHexColor, darkenHexColor } from '@/tools/changeHexColors' import { ClockRowData, ClockSchema, ClockType, UUID } from '@/types/schemas' import ClockSettingsDialog from './ClockSettingsDialog' @@ -283,19 +283,23 @@ const RealtimeClock: React.FC = ({ initialData }) => { const reducedMotionChart = (
-

{clockData.name}

-

Segments: {clockData.segments}

-

- Filled: {clockData.filled !== null ? clockData.filled + 1 : 0} of - {clockData.segments} -

+ + + + + +

Percentage Filled: {clockData.filled !== null - ? (clockData.filled + 1) / clockData.segments + ? Math.floor(((clockData.filled + 1) / clockData.segments) * 100) : 0}

- {/* Add any additional information you want to display */}
) @@ -321,7 +325,7 @@ const RealtimeClock: React.FC = ({ initialData }) => {
- {hasEditAccess && ( + {hasEditAccess && !reduceMotion && ( Date: Sat, 6 Jan 2024 20:38:01 +0000 Subject: [PATCH 09/20] ScreenReader: delete row button label --- clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx b/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx index f9211ce..bcfc4c1 100644 --- a/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx @@ -257,7 +257,10 @@ const RealtimeTowerRow: React.FC = ({ {hasEditAccess && ( - From 502a293fa8a0342d8e4aa40ecaba26c7449a8347 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 20:39:07 +0000 Subject: [PATCH 10/20] bug: screen reader repeating forever --- clocktower/app/tower/[id]/components/RealtimeClock.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index 015b7a9..3349f33 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -283,12 +283,11 @@ const RealtimeClock: React.FC = ({ initialData }) => { const reducedMotionChart = (
- - + + - + Date: Sat, 6 Jan 2024 20:42:53 +0000 Subject: [PATCH 11/20] screenreader: added ids for labels --- .../app/tower/[id]/components/RealtimeClock.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index 3349f33..9f3cfcc 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -15,6 +15,7 @@ import type { } from '@supabase/supabase-js' import extractErrorMessage from '@/tools/extractErrorMessage' import useEditAccess from '@/hooks/useEditAccess' +import generateUUID from '@/tools/generateId' interface RealtimeClockProps { initialData: ClockType @@ -281,13 +282,19 @@ const RealtimeClock: React.FC = ({ initialData }) => { /> ) + const randomId = generateUUID() const reducedMotionChart = (
- - + + - + Date: Sat, 6 Jan 2024 20:48:42 +0000 Subject: [PATCH 12/20] screenreader: Updated clock for reduced motion --- .../tower/[id]/components/RealtimeClock.tsx | 71 ++++++++++++------- clocktower/package-lock.json | 20 ++++++ clocktower/package.json | 2 + clocktower/tools/generateId.ts | 4 +- 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index 9f3cfcc..9ddf49b 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -2,7 +2,16 @@ import React, { useState, useEffect, MouseEvent, Suspense } from 'react' import { PieChart } from 'react-minimal-pie-chart' import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' -import { Input, Label, toast } from '@/components/ui' +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, + Input, + Label, + toast, +} from '@/components/ui' import { lightenHexColor, darkenHexColor } from '@/tools/changeHexColors' import { ClockRowData, ClockSchema, ClockType, UUID } from '@/types/schemas' import ClockSettingsDialog from './ClockSettingsDialog' @@ -284,29 +293,43 @@ const RealtimeClock: React.FC = ({ initialData }) => { const randomId = generateUUID() const reducedMotionChart = ( -
- - - - - - -

- Percentage Filled: - {clockData.filled !== null - ? Math.floor(((clockData.filled + 1) / clockData.segments) * 100) - : 0} -

-
+ + + {`Clock ${clockData.name}`} + + + + + + + + + + + +

+ Percentage Filled: + {clockData.filled !== null + ? Math.floor(((clockData.filled + 1) / clockData.segments) * 100) + : 0} +

+
+
) const reduceMotion = true diff --git a/clocktower/package-lock.json b/clocktower/package-lock.json index b5811f4..55e4f8d 100644 --- a/clocktower/package-lock.json +++ b/clocktower/package-lock.json @@ -58,6 +58,7 @@ "react-minimal-pie-chart": "^8.4.0", "tailwind-merge": "^1.14.0", "tailwindcss-animate": "^1.0.7", + "uuid": "^9.0.1", "zod": "^3.22.4" }, "devDependencies": { @@ -67,6 +68,7 @@ "@types/react": "^18.2.33", "@types/react-color": "^3.0.9", "@types/react-dom": "^18.2.14", + "@types/uuid": "^9.0.7", "eslint": "^8", "eslint-config-next": "^14.0.0", "jest": "^29.7.0", @@ -3194,6 +3196,12 @@ "resolved": "https://registry.npmjs.org/@types/svg-path-parser/-/svg-path-parser-1.1.4.tgz", "integrity": "sha512-i7qKm8qNFGl6rww2SNuU3Bmheia0xZFlu+M3HLU7ol5aVFRxq9rvpBhQEA2V/v0w2Sd12ZMRMrdMjCR8e81ejA==" }, + "node_modules/@types/uuid": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", + "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==", + "dev": true + }, "node_modules/@types/websocket": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.7.tgz", @@ -9574,6 +9582,18 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/clocktower/package.json b/clocktower/package.json index 1a1a4eb..8a2b12d 100644 --- a/clocktower/package.json +++ b/clocktower/package.json @@ -61,6 +61,7 @@ "react-minimal-pie-chart": "^8.4.0", "tailwind-merge": "^1.14.0", "tailwindcss-animate": "^1.0.7", + "uuid": "^9.0.1", "zod": "^3.22.4" }, "devDependencies": { @@ -70,6 +71,7 @@ "@types/react": "^18.2.33", "@types/react-color": "^3.0.9", "@types/react-dom": "^18.2.14", + "@types/uuid": "^9.0.7", "eslint": "^8", "eslint-config-next": "^14.0.0", "jest": "^29.7.0", diff --git a/clocktower/tools/generateId.ts b/clocktower/tools/generateId.ts index 943079a..4ef313b 100644 --- a/clocktower/tools/generateId.ts +++ b/clocktower/tools/generateId.ts @@ -1,6 +1,6 @@ import { UUID } from '@/types/schemas' -import { randomUUID } from 'crypto' +import { v4 as uuv4 } from 'uuid' export default function generateUUID(): UUID { - return randomUUID() + return uuv4() } From 658683ef7e0f72cb29e0847ca63dd01347ca1dba Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 21:23:22 +0000 Subject: [PATCH 13/20] Created Accessibility Provider, fixed minor layout issues. --- clocktower/app/layout.tsx | 2 +- .../tower/[id]/components/RealtimeClock.tsx | 13 +-- .../[id]/components/RealtimeTowerRow.tsx | 3 +- .../layout/AccessiblityOptionsDialog.tsx | 99 +++++++++++++++++++ clocktower/components/layout/Header.tsx | 12 ++- .../providers/AccessibilityProvider.tsx | 40 ++++++++ clocktower/{app => providers}/providers.tsx | 3 +- 7 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 clocktower/components/layout/AccessiblityOptionsDialog.tsx create mode 100644 clocktower/providers/AccessibilityProvider.tsx rename clocktower/{app => providers}/providers.tsx (67%) diff --git a/clocktower/app/layout.tsx b/clocktower/app/layout.tsx index 9bac5bf..1e70635 100644 --- a/clocktower/app/layout.tsx +++ b/clocktower/app/layout.tsx @@ -4,7 +4,7 @@ import Footer from '@/components/layout/Footer' import { Metadata, Viewport } from 'next' import { Toaster } from '@/components/ui/toaster' import { GeistSans } from 'geist/font' -import { Providers } from '@/app/providers' +import { Providers } from '@/providers/providers' import { Suspense } from 'react' const url = process.env.NEXT_PUBLIC_DOMAIN || 'http://localhost:3000' diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index 9ddf49b..0cffd7f 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -25,6 +25,7 @@ import type { import extractErrorMessage from '@/tools/extractErrorMessage' import useEditAccess from '@/hooks/useEditAccess' import generateUUID from '@/tools/generateId' +import { useAccessibility } from '@/providers/AccessibilityProvider' interface RealtimeClockProps { initialData: ClockType @@ -42,6 +43,8 @@ const RealtimeClock: React.FC = ({ initialData }) => { null, ) const [isDeleted, setIsDeleted] = useState(false) + const { screenReaderMode, toggleScreenReaderMode } = useAccessibility() + const hasEditAccess = useEditAccess(towerId) // Init supabase @@ -292,7 +295,7 @@ const RealtimeClock: React.FC = ({ initialData }) => { ) const randomId = generateUUID() - const reducedMotionChart = ( + const screenReaderChart = ( {`Clock ${clockData.name}`} @@ -332,12 +335,10 @@ const RealtimeClock: React.FC = ({ initialData }) => { ) - const reduceMotion = true - let displayedChart: React.JSX.Element - if (reduceMotion) { - displayedChart = reducedMotionChart + if (screenReaderMode) { + displayedChart = screenReaderChart } else if (hasEditAccess) { displayedChart = configuredPieChart } else { @@ -354,7 +355,7 @@ const RealtimeClock: React.FC = ({ initialData }) => {
- {hasEditAccess && !reduceMotion && ( + {hasEditAccess && !screenReaderMode && ( = ({ )} -
+
{children} {addedClocks.map((clock) => ( @@ -297,6 +297,7 @@ const RealtimeTowerRow: React.FC = ({ variant='ghost' className='h-24 w-24' onClick={addClock} + aria-label='Add Clock' > diff --git a/clocktower/components/layout/AccessiblityOptionsDialog.tsx b/clocktower/components/layout/AccessiblityOptionsDialog.tsx new file mode 100644 index 0000000..c289aa4 --- /dev/null +++ b/clocktower/components/layout/AccessiblityOptionsDialog.tsx @@ -0,0 +1,99 @@ +'use client' +import * as React from 'react' +import { useTheme } from 'next-themes' +import { Button } from '@/components/ui/button' +import { RxAccessibility } from 'react-icons/rx' +import { useEffect, useState } from 'react' +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + Label, + ModeToggle, + Switch, + Toggle, +} from '../ui' +import { DialogClose, DialogTrigger } from '@radix-ui/react-dialog' +import { useAccessibility } from '@/providers/AccessibilityProvider' + +export function AccessibilityOptionsDialog({ + className, +}: { + className?: string +}) { + const { + reduceMotion, + toggleReduceMotion, + screenReaderMode, + toggleScreenReaderMode, + } = useAccessibility() + + const [mounted, setMounted] = useState(false) + const { setTheme, resolvedTheme } = useTheme() + + // useEffect only runs on the client, so now we can safely show the UI + useEffect(() => { + setMounted(true) + }, []) + + // Function to toggle theme between light and dark + const toggleTheme = () => { + if (resolvedTheme === 'dark') { + setTheme('light') + } else { + setTheme('dark') + } + } + + if (!mounted) { + return ( + + ) + } + + return ( + + + + + + + Accessibility Settings + + Change the theme and other accessibility options. + + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ ) +} diff --git a/clocktower/components/layout/Header.tsx b/clocktower/components/layout/Header.tsx index 4928eb4..a2c3c22 100644 --- a/clocktower/components/layout/Header.tsx +++ b/clocktower/components/layout/Header.tsx @@ -20,6 +20,8 @@ import { type User, createClientComponentClient, } from '@supabase/auth-helpers-nextjs' +import { Accessibility } from 'lucide-react' +import { AccessibilityOptionsDialog } from './AccessiblityOptionsDialog' // Changing this to a client componenet export default function Header() { @@ -61,11 +63,11 @@ export default function Header() { +
{/* Center of Header */}
- {user ? ( @@ -112,10 +114,10 @@ export default function Header() {
{/* Right side of header */}
-
- {isOnTowerPage && } - -
+
+ {isOnTowerPage && } + +
) diff --git a/clocktower/providers/AccessibilityProvider.tsx b/clocktower/providers/AccessibilityProvider.tsx new file mode 100644 index 0000000..a85c7fc --- /dev/null +++ b/clocktower/providers/AccessibilityProvider.tsx @@ -0,0 +1,40 @@ +import React, { useState, createContext, useContext } from 'react' + +const AccessibilityContext = createContext({ + reduceMotion: false, + toggleReduceMotion: () => {}, + screenReaderMode: false, + toggleScreenReaderMode: () => {}, // Add a toggle function for screen reader mode +}) + +export const useAccessibility = () => useContext(AccessibilityContext) + +export const AccessibilityProvider = ({ + children, +}: { + children: React.ReactNode +}) => { + const [reduceMotion, setReduceMotion] = useState(false) + const [screenReaderMode, setScreenReaderMode] = useState(false) + + const toggleReduceMotion = () => { + setReduceMotion(!reduceMotion) + } + + const toggleScreenReaderMode = () => { + setScreenReaderMode(!screenReaderMode) + } + + return ( + + {children} + + ) +} diff --git a/clocktower/app/providers.tsx b/clocktower/providers/providers.tsx similarity index 67% rename from clocktower/app/providers.tsx rename to clocktower/providers/providers.tsx index fb0293f..15c5179 100644 --- a/clocktower/app/providers.tsx +++ b/clocktower/providers/providers.tsx @@ -1,11 +1,12 @@ // app/providers.jsx 'use client' import { ThemeProvider } from 'next-themes' +import { AccessibilityProvider } from './AccessibilityProvider' export function Providers({ children }: { children: React.ReactNode }) { return ( - {children} + {children} ) } From 33f9cc3773f91ce481e9f2ce614a4df48870e117 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 21:29:25 +0000 Subject: [PATCH 14/20] added reduced motion to stop animations --- clocktower/app/magic/page.tsx | 38 +++++++++++++++++++ .../tower/[id]/components/RealtimeClock.tsx | 2 +- clocktower/app/welcome/page.tsx | 19 ++++++++++ clocktower/components/homepage/SiteTitle.tsx | 10 +++++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/clocktower/app/magic/page.tsx b/clocktower/app/magic/page.tsx index fd9940a..42aa419 100644 --- a/clocktower/app/magic/page.tsx +++ b/clocktower/app/magic/page.tsx @@ -1,8 +1,10 @@ 'use client' import React, { useEffect, useRef } from 'react' import anime from 'animejs' +import { useAccessibility } from '@/providers/AccessibilityProvider' const MagicPage = () => { + const { reduceMotion } = useAccessibility() const headingRef = useRef(null) const wandRef = useRef(null) const mRef = useRef(null) @@ -100,6 +102,42 @@ const MagicPage = () => { }) }, []) + if (reduceMotion) { + return ( +
+
+

+ 🪄 +

+

+ M + a + g + i + c +

+
+ +
+

+ What's going to happen next? +

+
+

+ Hint:{' '} +

+

+ Check your email. +

+
+
+
+ ) + } + return (
diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index 0cffd7f..8342d44 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -43,7 +43,7 @@ const RealtimeClock: React.FC = ({ initialData }) => { null, ) const [isDeleted, setIsDeleted] = useState(false) - const { screenReaderMode, toggleScreenReaderMode } = useAccessibility() + const { screenReaderMode } = useAccessibility() const hasEditAccess = useEditAccess(towerId) diff --git a/clocktower/app/welcome/page.tsx b/clocktower/app/welcome/page.tsx index 5180d81..82284fb 100644 --- a/clocktower/app/welcome/page.tsx +++ b/clocktower/app/welcome/page.tsx @@ -5,10 +5,12 @@ import useWindowSize from '@/hooks/useWindowSize' import { Button } from '@/components/ui' import anime from 'animejs' import { useEffect, useRef } from 'react' +import { useAccessibility } from '@/providers/AccessibilityProvider' const WelcomePage = () => { const { width, height } = useWindowSize() const welcomeRef = useRef(null) + const { reduceMotion } = useAccessibility() useEffect(() => { anime.timeline({ loop: false }).add({ @@ -20,6 +22,23 @@ const WelcomePage = () => { }) }, []) + if (reduceMotion) { + return ( +
+
+

Welcome!

+

+ Now you're ready to get started, just login with your shiny new + account. +

+ +
+
+ ) + } + return (
diff --git a/clocktower/components/homepage/SiteTitle.tsx b/clocktower/components/homepage/SiteTitle.tsx index 108d690..98ee9fa 100644 --- a/clocktower/components/homepage/SiteTitle.tsx +++ b/clocktower/components/homepage/SiteTitle.tsx @@ -2,12 +2,14 @@ 'use client' import React, { useRef, useEffect } from 'react' import anime from 'animejs' +import { useAccessibility } from '@/providers/AccessibilityProvider' const title = 'Clocktower' const animatedLettersIndex = [8, 6, 2, 3] const SiteTitle = () => { const rotationRefs = title.split('').map(() => useRef(null)) + const { reduceMotion } = useAccessibility() useEffect(() => { const timeline = anime.timeline({ @@ -35,6 +37,14 @@ const SiteTitle = () => { }) }, []) + if (reduceMotion) { + return ( +

+ {title} +

+ ) + } + return (

{title.split('').map((letter, index) => ( From 17114a6f4f72ebd14040dd9a1f943cf013bfdd78 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 21:34:26 +0000 Subject: [PATCH 15/20] Turned off vibrating elements when reduced motion is on --- .../profile/components/UpdateAccountForm.tsx | 25 ++++++++--- .../[id]/components/RealtimeTowerRow.tsx | 23 ++++++++--- clocktower/components/layout/Footer.tsx | 41 +++++++++++++------ 3 files changed, 65 insertions(+), 24 deletions(-) diff --git a/clocktower/app/account/profile/components/UpdateAccountForm.tsx b/clocktower/app/account/profile/components/UpdateAccountForm.tsx index b607943..db022fd 100644 --- a/clocktower/app/account/profile/components/UpdateAccountForm.tsx +++ b/clocktower/app/account/profile/components/UpdateAccountForm.tsx @@ -51,6 +51,8 @@ import hash from '@/tools/hash' import updateUserAvatarSetSA from '../actions/updateUserAvatarSet' import { BsTrash3Fill } from 'react-icons/bs' import { DialogClose } from '@radix-ui/react-dialog' +import { useAccessibility } from '@/providers/AccessibilityProvider' + // validation schema for form const formSchema = z .object({ @@ -159,6 +161,7 @@ const UpdateAccountForm = ({ const [currentColor, setCurrentColor] = useState(profile.color) const [avatarSet, setAvatarSet] = useState(profile.avatar_set || 1) const supabase = createClientComponentClient() + const { reduceMotion } = useAccessibility() useEffect(() => { async function getUserFromSession() { @@ -566,12 +569,22 @@ const UpdateAccountForm = ({ 🙅‍♀️ Cancel - - Delete - + {reduceMotion ? ( + // If reduce motion is on, don't vibrate the button + + Delete + + ) : ( + + Delete + + )} diff --git a/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx b/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx index e7c69c4..f4419f5 100644 --- a/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx @@ -33,6 +33,7 @@ import insertNewClockSA from '../actions/insertNewClockSA' import { updateRowNameSA } from '../actions/updateRowNameSA' import { deleteTowerRowSA } from '../actions/deleteTowerRowSA' import useEditAccess from '@/hooks/useEditAccess' +import { useAccessibility } from '@/providers/AccessibilityProvider' type RealtimeTowerRowProps = { initialData: TowerRowRow @@ -51,6 +52,7 @@ const RealtimeTowerRow: React.FC = ({ const [addedClocks, setAddedClocks] = useState>([]) const addedClocksRef = React.useRef(addedClocks.map((c) => c.id)) const hasEditAccess = useEditAccess(towerId) + const { reduceMotion } = useAccessibility() const supabase = createClientComponentClient() // Update self when a server payload is received @@ -275,12 +277,21 @@ const RealtimeTowerRow: React.FC = ({ Cancel - - Delete - + {reduceMotion ? ( + + Delete + + ) : ( + + Delete + + )} diff --git a/clocktower/components/layout/Footer.tsx b/clocktower/components/layout/Footer.tsx index 03a9688..ea20e9d 100644 --- a/clocktower/components/layout/Footer.tsx +++ b/clocktower/components/layout/Footer.tsx @@ -1,5 +1,6 @@ import Link from 'next/link' import ThemeAwareSocialIcon from '@/components/layout/ThemeAwareSocialIcon' +import { useAccessibility } from '@/providers/AccessibilityProvider' const Footer = () => { const emojis = ['❤️', '🐶', '☕️', '❤️‍🩹', '🤖', '👾', '💻'] @@ -8,6 +9,7 @@ const Footer = () => { const copywrite = `© ${currentYear} Turner Monroe` const darkGithub = '/img/github-mark/github-mark.svg' const lightGithub = '/img/github-mark/github-mark-white.svg' + const { reduceMotion } = useAccessibility() return ( <> @@ -24,18 +26,33 @@ const Footer = () => {

)} -
- - - -
+ {reduceMotion ? ( +
+ + + +
+ ) : ( +
+ + + +
+ )}
From 467cb4e1227c0d2ccd3af65ef98757d21eaab662 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 21:36:12 +0000 Subject: [PATCH 16/20] removed animations on screenreader mode --- clocktower/app/magic/page.tsx | 4 ++-- clocktower/app/welcome/page.tsx | 4 ++-- clocktower/components/homepage/SiteTitle.tsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clocktower/app/magic/page.tsx b/clocktower/app/magic/page.tsx index 42aa419..90cf74c 100644 --- a/clocktower/app/magic/page.tsx +++ b/clocktower/app/magic/page.tsx @@ -4,7 +4,7 @@ import anime from 'animejs' import { useAccessibility } from '@/providers/AccessibilityProvider' const MagicPage = () => { - const { reduceMotion } = useAccessibility() + const { reduceMotion, screenReaderMode } = useAccessibility() const headingRef = useRef(null) const wandRef = useRef(null) const mRef = useRef(null) @@ -102,7 +102,7 @@ const MagicPage = () => { }) }, []) - if (reduceMotion) { + if (reduceMotion || screenReaderMode) { return (
diff --git a/clocktower/app/welcome/page.tsx b/clocktower/app/welcome/page.tsx index 82284fb..4893dc5 100644 --- a/clocktower/app/welcome/page.tsx +++ b/clocktower/app/welcome/page.tsx @@ -10,7 +10,7 @@ import { useAccessibility } from '@/providers/AccessibilityProvider' const WelcomePage = () => { const { width, height } = useWindowSize() const welcomeRef = useRef(null) - const { reduceMotion } = useAccessibility() + const { reduceMotion, screenReaderMode } = useAccessibility() useEffect(() => { anime.timeline({ loop: false }).add({ @@ -22,7 +22,7 @@ const WelcomePage = () => { }) }, []) - if (reduceMotion) { + if (reduceMotion || screenReaderMode) { return (
diff --git a/clocktower/components/homepage/SiteTitle.tsx b/clocktower/components/homepage/SiteTitle.tsx index 98ee9fa..6c221cf 100644 --- a/clocktower/components/homepage/SiteTitle.tsx +++ b/clocktower/components/homepage/SiteTitle.tsx @@ -9,7 +9,7 @@ const animatedLettersIndex = [8, 6, 2, 3] const SiteTitle = () => { const rotationRefs = title.split('').map(() => useRef(null)) - const { reduceMotion } = useAccessibility() + const { reduceMotion, screenReaderMode } = useAccessibility() useEffect(() => { const timeline = anime.timeline({ @@ -37,7 +37,7 @@ const SiteTitle = () => { }) }, []) - if (reduceMotion) { + if (reduceMotion || screenReaderMode) { return (

{title} From 473769235ddba7da36d232a90cac917890f3a24d Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 22:04:53 +0000 Subject: [PATCH 17/20] Let screen readers not break the database --- .../tower/[id]/components/RealtimeClock.tsx | 133 +++++++++++++++--- .../[id]/components/RealtimeTowerRow.tsx | 2 +- clocktower/components/homepage/SiteTitle.tsx | 28 ++-- clocktower/components/layout/Footer.tsx | 41 ++---- .../providers/AccessibilityProvider.tsx | 1 + 5 files changed, 138 insertions(+), 67 deletions(-) diff --git a/clocktower/app/tower/[id]/components/RealtimeClock.tsx b/clocktower/app/tower/[id]/components/RealtimeClock.tsx index 8342d44..59b61ca 100644 --- a/clocktower/app/tower/[id]/components/RealtimeClock.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeClock.tsx @@ -154,34 +154,37 @@ const RealtimeClock: React.FC = ({ initialData }) => { } } - // This one actually updates the server - const handleSliceClick = async (event: MouseEvent, dataIndex: number) => { - let newFilledValue: number | null + // Shared function to update the filled state and synchronize with the server + const updateFilledValue = async (inputFilledValue: number | null) => { + // Guard against invalid input + let validFilledValue = inputFilledValue + + if (validFilledValue !== null) { + if (validFilledValue < 0) { + validFilledValue = 0 + } - if ( - clockData.filled === dataIndex || - (clockData.filled !== null && dataIndex < clockData.filled) - ) { - newFilledValue = dataIndex === 0 ? null : dataIndex - 1 - } else { - newFilledValue = dataIndex + if (validFilledValue >= clockData.segments) { + // Correct for too high of a value + validFilledValue = clockData.segments - 1 + } + } + + if (validFilledValue === clockData.filled) { + return // Guard against unnecessary updates } - // Optimistically update local state setClockData((prevState) => ({ ...prevState, - filled: newFilledValue, + filled: validFilledValue, })) - // Prepare data for server update const newClockData = { - filled: newFilledValue, + filled: validFilledValue, } - // Update the server const { error } = await updateClockDataSA({ clockId, newClockData }) - // In case of an error, revert to previous state if (error) { console.error(error) toast({ @@ -196,6 +199,34 @@ const RealtimeClock: React.FC = ({ initialData }) => { } } + // Function to handle slice click + const handleSliceClick = async (event: MouseEvent, dataIndex: number) => { + const newFilledValue = + clockData.filled === dataIndex || + (clockData.filled !== null && dataIndex < clockData.filled) + ? dataIndex === 0 + ? null + : dataIndex - 1 + : dataIndex + + await updateFilledValue(newFilledValue) + } + + // Function to handle input change for screen readers + const handleFilledInputChange = ( + event: React.ChangeEvent, + ) => { + const filledValue = parseInt(event.target.value, 10) - 1 + if ( + isNaN(filledValue) || + filledValue < 0 || + filledValue >= clockData.segments + ) { + return // Guard against invalid input + } + updateFilledValue(filledValue) + } + // Handle mouse over slice const handleMouseOver = (event: MouseEvent, dataIndex: number) => { setHoveredSliceIndex(dataIndex) @@ -294,6 +325,65 @@ const RealtimeClock: React.FC = ({ initialData }) => { /> ) + // Function to handle changes in clock name + const handleNameInputChange = async ( + event: React.ChangeEvent, + ) => { + const newName = event.target.value + const oldName = clockData.name + + // Optimistically update local state + setClockData((prevState) => ({ ...prevState, name: newName })) + + // Update the server + const response = await updateClockDataSA({ + clockId, + newClockData: { name: newName }, + }) + + if (response.error) { + console.error('Failed to update name:', response.error) + toast({ + title: 'Failed to update name', + description: response.error, + variant: 'destructive', + }) + // Revert the local state + setClockData((prevState) => ({ ...prevState, name: oldName })) + } + } + + // Function to handle changes in total segments + const handleTotalSegmentsInputChange = async ( + event: React.ChangeEvent, + ) => { + const newSegments = parseInt(event.target.value, 10) + if (isNaN(newSegments) || newSegments < 1) { + return // Guard against invalid input + } + + const oldSegments = clockData.segments + // Optimistically update local state + setClockData((prevState) => ({ ...prevState, segments: newSegments })) + + // Update the server + const response = await updateClockDataSA({ + clockId, + newClockData: { segments: newSegments }, + }) + + if (response.error) { + console.error('Failed to update segments:', response.error) + toast({ + title: 'Failed to update segments', + description: response.error, + variant: 'destructive', + }) + // Revert the local state + setClockData((prevState) => ({ ...prevState, segments: oldSegments })) + } + } + const randomId = generateUUID() const screenReaderChart = ( @@ -305,23 +395,26 @@ const RealtimeClock: React.FC = ({ initialData }) => { diff --git a/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx b/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx index f4419f5..24dac73 100644 --- a/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx +++ b/clocktower/app/tower/[id]/components/RealtimeTowerRow.tsx @@ -298,7 +298,7 @@ const RealtimeTowerRow: React.FC = ({ )} -
+
{children} {addedClocks.map((clock) => ( diff --git a/clocktower/components/homepage/SiteTitle.tsx b/clocktower/components/homepage/SiteTitle.tsx index 6c221cf..1d67048 100644 --- a/clocktower/components/homepage/SiteTitle.tsx +++ b/clocktower/components/homepage/SiteTitle.tsx @@ -37,25 +37,19 @@ const SiteTitle = () => { }) }, []) - if (reduceMotion || screenReaderMode) { - return ( -

- {title} -

- ) - } - return (

- {title.split('').map((letter, index) => ( -
- {letter} -
- ))} + {reduceMotion || screenReaderMode + ? title + : title.split('').map((letter, index) => ( +
+ {letter} +
+ ))}

) } diff --git a/clocktower/components/layout/Footer.tsx b/clocktower/components/layout/Footer.tsx index ea20e9d..03a9688 100644 --- a/clocktower/components/layout/Footer.tsx +++ b/clocktower/components/layout/Footer.tsx @@ -1,6 +1,5 @@ import Link from 'next/link' import ThemeAwareSocialIcon from '@/components/layout/ThemeAwareSocialIcon' -import { useAccessibility } from '@/providers/AccessibilityProvider' const Footer = () => { const emojis = ['❤️', '🐶', '☕️', '❤️‍🩹', '🤖', '👾', '💻'] @@ -9,7 +8,6 @@ const Footer = () => { const copywrite = `© ${currentYear} Turner Monroe` const darkGithub = '/img/github-mark/github-mark.svg' const lightGithub = '/img/github-mark/github-mark-white.svg' - const { reduceMotion } = useAccessibility() return ( <> @@ -26,33 +24,18 @@ const Footer = () => {
)} - {reduceMotion ? ( -
- - - -
- ) : ( -
- - - -
- )} +
+ + + +

diff --git a/clocktower/providers/AccessibilityProvider.tsx b/clocktower/providers/AccessibilityProvider.tsx index a85c7fc..8d90caa 100644 --- a/clocktower/providers/AccessibilityProvider.tsx +++ b/clocktower/providers/AccessibilityProvider.tsx @@ -1,3 +1,4 @@ +'use client' import React, { useState, createContext, useContext } from 'react' const AccessibilityContext = createContext({ From ce3e3fb9e9c597975525876bb2a645151428e712 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 22:09:58 +0000 Subject: [PATCH 18/20] Rearranged for screen reader ease of use --- .../layout/AccessiblityOptionsDialog.tsx | 26 ++++++++++--------- clocktower/components/layout/Header.tsx | 9 +++++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/clocktower/components/layout/AccessiblityOptionsDialog.tsx b/clocktower/components/layout/AccessiblityOptionsDialog.tsx index c289aa4..6a9378b 100644 --- a/clocktower/components/layout/AccessiblityOptionsDialog.tsx +++ b/clocktower/components/layout/AccessiblityOptionsDialog.tsx @@ -70,26 +70,28 @@ export function AccessibilityOptionsDialog({ Change the theme and other accessibility options. +
+ + +
+
-
- - -
- +
-
- - + +
+ +
diff --git a/clocktower/components/layout/Header.tsx b/clocktower/components/layout/Header.tsx index a2c3c22..61dfba7 100644 --- a/clocktower/components/layout/Header.tsx +++ b/clocktower/components/layout/Header.tsx @@ -58,8 +58,13 @@ export default function Header() {
{/* Left side of header */}
- From 236b65ddcace57aa0c1aa7c39470e58132efe7c5 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 22:11:18 +0000 Subject: [PATCH 19/20] Removed outside styling from mode toggle --- clocktower/components/layout/Header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clocktower/components/layout/Header.tsx b/clocktower/components/layout/Header.tsx index 61dfba7..714674c 100644 --- a/clocktower/components/layout/Header.tsx +++ b/clocktower/components/layout/Header.tsx @@ -69,7 +69,7 @@ export default function Header() { - +
{/* Center of Header */}
From 53a14e2f5f6bb23e856628a90a908f485652eee5 Mon Sep 17 00:00:00 2001 From: Turner Monroe Date: Sat, 6 Jan 2024 22:21:49 +0000 Subject: [PATCH 20/20] Added public front page clock screen reader mode --- clocktower/app/page.tsx | 6 +- .../components/homepage/PublicClock.tsx | 90 ++++++++++++++++++- clocktower/components/layout/Header.tsx | 2 +- 3 files changed, 93 insertions(+), 5 deletions(-) diff --git a/clocktower/app/page.tsx b/clocktower/app/page.tsx index dfe8dda..754cce6 100644 --- a/clocktower/app/page.tsx +++ b/clocktower/app/page.tsx @@ -17,13 +17,13 @@ const Home = async () => { return (
-
+

Shared game clocks for tabletop RPGs

{isLoggedIn ? ( -
+ <>

To make some clocks, select a tower from the dropdown above.

-
+ ) : (