Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function RootLayout({
/>
<meta name="theme-color" content="#0C5A4B" />
</head>
<body className={`${inter.className} min-w-full min-h-screen`}>
<body className={`${inter.className} h-screen w-screen overflow-hidden`}>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added to ensure the full screen was used, otherwise prayer table wasn't utilising the space

{children}
</body>
</html>
Expand Down
71 changes: 2 additions & 69 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
import Blackout from "@/components/Blackout/Blackout"
import Clock from "@/components/Clock/Clock"
import Date from "@/components/Date/Date"
import MosqueMetadata from "@/components/MosqueMetadata/MosqueMetadata"
import Notice from "@/components/Notice/Notice"
import SunriseJummahTiles from "@/components/SunriseJummahTiles/SunriseJummahTiles"
import PrayerTimes from "@/components/PrayerTimes/PrayerTimes"
import ServiceWorker from "@/components/ServiceWorker/ServiceWorker"
import SlidingBanner from "@/components/SlidingBanner/SlidingBanner"
import {
getJummahTimes,
getMetaData,
getPrayerTimesForUpcomingDays,
getPrayerTimesForToday,
getPrayerTimesForTomorrow,
getConfiguration,
} from "@/services/MosqueDataService"
import type {
DailyPrayerTime,
UpcomingPrayerTimes,
} from "@/types/DailyPrayerTimeType"
import type { JummahTimes } from "@/types/JummahTimesType"
import type { MosqueMetadataType } from "@/types/MosqueDataType"
import type { Metadata } from "next"
import UpcomingPrayerDayTiles from "@/components/UpcomingPrayerDayTiles/UpcomingPrayerDayTiles"
import "./prayer-times.css"
import Announcement from "@/components/Announcement/Announcement"
import { ConfigurationJson } from "@/types/ConfigurationType"
import { ConfigurationProvider } from "@/providers/ConfigurationProvider"
import ScreenFactory from "@/components/Screens/ScreenFactory"

export async function generateMetadata(): Promise<Metadata> {
const mosqueMetadata: MosqueMetadataType = await getMetaData()
Expand All @@ -38,59 +19,11 @@ export async function generateMetadata(): Promise<Metadata> {
}

export default async function Home() {
const today: DailyPrayerTime = await getPrayerTimesForToday()
const tomorrow: DailyPrayerTime = await getPrayerTimesForTomorrow()
const jummahTimes: JummahTimes = await getJummahTimes()
const mosqueMetadata: MosqueMetadataType = await getMetaData()
const config: ConfigurationJson = await getConfiguration()
const upcomingPrayerDays: UpcomingPrayerTimes[] =
await getPrayerTimesForUpcomingDays()

let slides = [
<SunriseJummahTiles
sunrise={today.sunrise_start}
jummahTimes={jummahTimes}
key={"sunrise_jummah_times"}
/>,
]

upcomingPrayerDays.forEach((times) => {
slides.push(
<UpcomingPrayerDayTiles times={times} key={times.display_date} />,
)
})

return (
<ConfigurationProvider config={config}>
<div className="bg-mosqueBrand min-h-screen min-w-full">
<main className="md:p-5">
<div className="md:grid md:grid-cols-8">
<div className="md:col-span-3">
<div className="p-4 md:p-6">
<Clock />
</div>
<div className="p-4 md:p-6">
<Date />
</div>
<div className="p-4 md:p-6">
<MosqueMetadata metadata={mosqueMetadata} />
</div>
<div className="hidden md:p-6 md:block">
<Notice />
</div>
</div>
<div className="p-4 md:p-6 md:col-span-5">
<PrayerTimes today={today} tomorrow={tomorrow} />
</div>
</div>
<div className="p-4 md:p-6">
<SlidingBanner slides={slides} />
</div>
<ServiceWorker />
</main>
{config.feature.announcement.enabled && <Announcement />}
<Blackout prayerTimeToday={today} />
</div>
<ScreenFactory config={config} />
</ConfigurationProvider>
)
}
4 changes: 2 additions & 2 deletions components/Clock/Clock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export default function Clock({ darkMode = false }: { darkMode?: boolean }) {
<div
className={`${
!darkMode ? "bg-mosqueBrand-onPrimary" : ""
} p-7 text-center md:text-left md:w-fit`}
} p-7 2k:px-[1.5vw] 2k:py-[1.5vh] text-center md:text-left md:w-fit`}
>
<time
className={`text-5xl md:text-8xl font-bold ${
className={`text-5xl md:text-8xl 2k:text-10xl 4k:text-12xl font-bold ${
!darkMode ? "text-mosqueBrand" : "text-gray-500"
}`}
>
Expand Down
8 changes: 6 additions & 2 deletions components/Date/Date.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ export default function Date() {

return (
<div className="text-mosqueBrand-onPrimary text-center md:text-left">
<p className="font-bold text-2xl md:text-5xl">{englishDate}</p>
<p className="mt-3 md:mt-5 text-2xl md:text-4xl">{hijriDate}</p>
<p className="font-bold text-2xl md:text-5xl 2k:text-6xl 4k:text-8xl">
{englishDate}
</p>
<p className="mt-3 md:mt-5 2k:mt-[2vh] text-2xl md:text-4xl 2k:text-5xl 4k:text-7xl">
{hijriDate}
</p>
</div>
)
}
16 changes: 16 additions & 0 deletions components/MosqueMetadata/MosqueLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MosqueMetadataType } from "@/types/MosqueDataType"

export default function MosqueLogo({
metadata,
}: {
metadata: MosqueMetadataType
}) {
return (
// eslint-disable-next-line @next/next/no-img-element
<img
className="m-2 max-w-full lg:max-w-lg max-h-16 mx-auto"
src={metadata.logo_url}
alt=""
/>
)
}
16 changes: 10 additions & 6 deletions components/MosqueMetadata/MosqueMetadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,24 @@ export default function MosqueMetadata({
}) {
return (
<div className="md:flex text-mosqueBrand-onPrimary text-center md:text-left">
<div className="mr-4 flex-shrink-0 self-center">
<div className="mr-4 2k:mr-[1vw] flex-shrink-0 self-center">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
className="m-2 max-w-full lg:max-w-lg max-h-16 mx-auto"
className="m-2 max-w-full lg:max-w-lg max-h-[10vh] mx-auto"
src={metadata.logo_url}
alt=""
/>
</div>
<div>
<h2 className="mt-3 md:mt-5 font-bold text-2xl md:text-3xl">
<div className={"flex flex-col gap-[0.7vh] "}>
<h2 className="mt-[1.2vh] font-bold text-2xl md:text-3xl 2k:text-4xl 4k:text-6xl">
{metadata.name}
</h2>
<p className="mt-3 text-xl mx-5 md:mx-0">{metadata.address}</p>
<p className="text-xl">{metadata.website}</p>
<p className="mt-[1.2vh] text-xl leading-[2vh] 2k:text-[1.8rem] 4k:text-[2.8rem] mx-5 md:mx-0">
{metadata.address}
</p>
<p className="text-xl leading-[2vh] 2k:text-[1.8rem] 4k:text-[2.8rem]">
{metadata.website}
</p>
Comment on lines +22 to +27
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

leading-[2vh] will clip/overlap text at the targeted 2k/4k resolutions.

Viewport-relative line-height is smaller than the font-size at the breakpoints this PR is adding:

Resolution 2vh line-height Applied font-size Result
4K (2160px tall) 43.2px text-[2.8rem] = 44.8px line-height < font-size → overlapping lines
2K (1440px tall) 28.8px text-[1.8rem] = 28.8px line-height == font-size → no leading at all
1080p (1080px tall) 21.6px text-xl = 20px barely above font-size

Since address/website can wrap to multiple lines, this will produce overlapping/cropped text precisely on the displays this PR targets. Prefer a relative unit-less leading-* value (or scale leading alongside the breakpoint like the font size).

🛠 Proposed fix
-        <p className="mt-[1.2vh] text-xl leading-[2vh] 2k:text-[1.8rem] 4k:text-[2.8rem] mx-5 md:mx-0">
+        <p className="mt-[1.2vh] text-xl leading-snug 2k:text-[1.8rem] 4k:text-[2.8rem] mx-5 md:mx-0">
           {metadata.address}
         </p>
-        <p className="text-xl leading-[2vh] 2k:text-[1.8rem] 4k:text-[2.8rem]">
+        <p className="text-xl leading-snug 2k:text-[1.8rem] 4k:text-[2.8rem]">
           {metadata.website}
         </p>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<p className="mt-[1.2vh] text-xl leading-[2vh] 2k:text-[1.8rem] 4k:text-[2.8rem] mx-5 md:mx-0">
{metadata.address}
</p>
<p className="text-xl leading-[2vh] 2k:text-[1.8rem] 4k:text-[2.8rem]">
{metadata.website}
</p>
<p className="mt-[1.2vh] text-xl leading-snug 2k:text-[1.8rem] 4k:text-[2.8rem] mx-5 md:mx-0">
{metadata.address}
</p>
<p className="text-xl leading-snug 2k:text-[1.8rem] 4k:text-[2.8rem]">
{metadata.website}
</p>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/MosqueMetadata/MosqueMetadata.tsx` around lines 22 - 27, The
current hard-coded viewport-based line-height in MosqueMetadata.tsx (className
on the <p> elements rendering metadata.address and metadata.website) uses
leading-[2vh], which causes overlapping at 2k/4k breakpoints; replace the
viewport-relative leading with unitless or responsive leading classes (e.g.,
leading-normal/leading-6 or breakpoint-specific unitless values like
2k:leading-[1.05] and 4k:leading-[1.1]) in the className for the <p> elements
that render metadata.address and metadata.website so line-height scales properly
with font-size and prevents text overlap.

</div>
</div>
)
Expand Down
8 changes: 4 additions & 4 deletions components/Notice/Notice.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export default function Notice() {
return (
<div className="flex text-mosqueBrand-onPrimary text-center md:text-left">
<div className="mr-4 flex-shrink-0 self-center">
<div className="flex text-mosqueBrand-onPrimary text-center md:text-left ">
<div className="mr-[1.2vw] flex-shrink-0 self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
className="h-20 w-auto"
className="h-20 2k:h-[8vh] w-auto"
>
<path
fill="none"
Expand All @@ -20,7 +20,7 @@ export default function Notice() {
</svg>
</div>
<div>
<p className="italic text-xl md:text-2xl md:max-w-lg hidden md:block">
<p className="italic text-xl md:text-2xl 2k:text-4xl 4k:text-5xl 4k:leading-[1.3] md:max-w-[25vw] hidden md:block">
Please ensure your mobile phone is silent in the prayer hall.
</p>
</div>
Expand Down
27 changes: 17 additions & 10 deletions components/PrayerTimes/PrayerTimes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getNextPrayer } from "@/services/PrayerTimeService"
import { DailyPrayerTime } from "@/types/DailyPrayerTimeType"
import { useConfiguration } from "@/hooks/useConfiguration"
import { dtFormatTimeTo12h } from "@/lib/datetimeUtils"
import { cn } from "@/lib/utils"

export default function PrayerTimes({
today,
Expand Down Expand Up @@ -44,6 +45,8 @@ export default function PrayerTimes({
const config = useConfiguration()
const [nextPrayerTime, setNextPrayerTime] = useState(getNextPrayer(today))
const isTomorrowEnabled = config.feature.prayer_time_tomorrow.enabled
const tableColumnTitleClassNames = "md:text-5xl 2k:text-6xl 4k:text-8xl"
const tableDataClassNames = "text-xl md:text-6xl 2k:text-[5rem] 4k:text-9xl"

useEffect(() => {
const interval = setInterval(() => {
Expand All @@ -54,17 +57,19 @@ export default function PrayerTimes({
}, [today])

return (
<table className="text-mosqueBrand-onPrimary mx-auto table-auto border-collapse border-none w-full">
<table className="text-mosqueBrand-onPrimary mx-auto table-auto border-collapse border-none w-full h-full">
<thead>
<tr
className="text-center [&>*]:p-2 md:[&>*]:p-8
md:[&>*]:border [&>*]:border-mosqueBrand-primaryAlt
[&>th]:border-t-0 [&>th:last-of-type]:border-r-0"
>
<th className="sr-only">Prayer time</th>
<th className="md:text-5xl">Begins</th>
<th className="md:text-5xl">Jama&apos;ah</th>
{isTomorrowEnabled && <th className={"md:text-5xl"}>Tomorrow</th>}
<th className={cn(tableColumnTitleClassNames)}>Begins</th>
<th className={cn(tableColumnTitleClassNames)}>Jama&apos;ah</th>
{isTomorrowEnabled && (
<th className={cn(tableColumnTitleClassNames)}>Tomorrow</th>
)}
</tr>
</thead>
<tbody>
Expand All @@ -83,36 +88,38 @@ export default function PrayerTimes({
border border-mosqueBrand-primaryAlt border-l-0 border-r-0
last-of-type:border-b-0"
>
<th className="text-left text-xl md:text-5xl md:text-right">
<th
className={cn("text-left md:text-right", tableDataClassNames)}
>
{prayer.label}
</th>
<td className="text-xl md:text-6xl">
<td className={cn(tableDataClassNames)}>
{dtFormatTimeTo12h(prayer.data.start)}
{prayer.data?.start_secondary ? (
<div className="block mt-1 md:mt-2">
{dtFormatTimeTo12h(prayer.data.start_secondary)}
</div>
) : null}
</td>
<td className={`font-bold text-xl md:text-6xl`}>
<td className={cn(`font-bold`, tableDataClassNames)}>
<span
className={
nextPrayerTime.today === true &&
nextPrayerTime.prayerIndex === index
? "underline decoration-mosqueBrand-highlight underline-offset-8"
? "underline decoration-mosqueBrand-highlight underline-offset-[1.5vh]"
: ""
}
>
{dtFormatTimeTo12h(prayer.data.congregation_start)}
</span>
</td>
{isTomorrowEnabled && (
<td className={`text-xl md:text-6xl`}>
<td className={cn(tableDataClassNames)}>
<span
className={
nextPrayerTime.today === false &&
nextPrayerTime.prayerIndex === index
? "underline decoration-mosqueBrand-highlight underline-offset-8"
? "underline decoration-mosqueBrand-highlight underline-offset-[1.5vh]"
: ""
}
>
Expand Down
87 changes: 87 additions & 0 deletions components/Screens/DefaultScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type {
DailyPrayerTime,
UpcomingPrayerTimes,
} from "@/types/DailyPrayerTimeType"
import {
getConfiguration,
getJummahTimes,
getMetaData,
getPrayerTimesForToday,
getPrayerTimesForTomorrow,
getPrayerTimesForUpcomingDays,
} from "@/services/MosqueDataService"
import type { JummahTimes } from "@/types/JummahTimesType"
import type { MosqueMetadataType } from "@/types/MosqueDataType"
import { ConfigurationJson } from "@/types/ConfigurationType"
import SunriseJummahTiles from "@/components/SunriseJummahTiles/SunriseJummahTiles"
import UpcomingPrayerDayTiles from "@/components/UpcomingPrayerDayTiles/UpcomingPrayerDayTiles"
import { ConfigurationProvider } from "@/providers/ConfigurationProvider"
import Clock from "@/components/Clock/Clock"
import Date from "@/components/Date/Date"
import MosqueMetadata from "@/components/MosqueMetadata/MosqueMetadata"
import Notice from "@/components/Notice/Notice"
import PrayerTimes from "@/components/PrayerTimes/PrayerTimes"
import SlidingBanner from "@/components/SlidingBanner/SlidingBanner"
import ServiceWorker from "@/components/ServiceWorker/ServiceWorker"
import Announcement from "@/components/Announcement/Announcement"
import Blackout from "@/components/Blackout/Blackout"


interface DefaultScreenProps {
config: ConfigurationJson
}

export default async function DefaultScreen({ config }: DefaultScreenProps) {
const today: DailyPrayerTime = await getPrayerTimesForToday()
const tomorrow: DailyPrayerTime = await getPrayerTimesForTomorrow()
const jummahTimes: JummahTimes = await getJummahTimes()
const mosqueMetadata: MosqueMetadataType = await getMetaData()
const upcomingPrayerDays: UpcomingPrayerTimes[] =
await getPrayerTimesForUpcomingDays()

let slides = [
<SunriseJummahTiles
sunrise={today.sunrise_start}
jummahTimes={jummahTimes}
key={"sunrise_jummah_times"}
/>,
]

upcomingPrayerDays.forEach((times) => {
slides.push(
<UpcomingPrayerDayTiles times={times} key={times.display_date} />,
)
})

return (
<div className="bg-mosqueBrand h-full w-full">
<main className="flex h-full w-full flex-col p-4 md:p-5 2k:p-[1.5vw]">
<div className="min-h-0 flex-1 md:grid md:grid-cols-8">
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added to ensure the full screen was used, otherwise prayer table wasn't utilising the space

<div className="md:col-span-3 flex flex-col gap-4 2k:gap-[2vh]">
<div className="p-4 md:p-6 2k:p-[1.5vh]">
<Clock />
</div>
<div className="p-4 md:p-6 2k:p-[1.5vh]">
<Date />
</div>
<div className="p-4 md:p-6 2k:p-[1.5vh]">
<MosqueMetadata metadata={mosqueMetadata} />
</div>
<div className="hidden md:p-6 md:block 2k:p-[1.5vh]">
<Notice />
</div>
</div>
<div className="p-4 md:p-6 md:col-span-5">
<PrayerTimes today={today} tomorrow={tomorrow} />
</div>
</div>
<div className="shrink-0 p-4 md:p-6">
<SlidingBanner slides={slides} />
</div>
<ServiceWorker />
</main>
{config.feature.announcement.enabled && <Announcement />}
<Blackout prayerTimeToday={today} />
</div>
)
}
Loading