Last active
September 5, 2026 00:32
-
-
Save andreimerlescu/495c66c38f8ad31f042fc95e08ce1d8f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php declare(strict_types=1); | |
| namespace AVC; | |
| class Shabbat | |
| { | |
| public static function enforce(): void { | |
| if (is_falsy(from_server(key: IS_DEV)) && self::is_shabbat()) { | |
| self::send_headers(); | |
| echo self::render_shabbat(); | |
| exit; | |
| } | |
| } | |
| public static function str_date(): string | |
| { | |
| $date = new \DateTime( | |
| datetime: 'now', | |
| timezone: new \DateTimeZone(timezone: 'America/New_York'), | |
| ); | |
| $jd = gregoriantojd( | |
| month: (int)$date->format(format: 'm'), | |
| day: (int)$date->format(format: 'd'), | |
| year: (int)$date->format(format: 'Y'), | |
| ); | |
| $hebrew_date = cal_from_jd( | |
| julian_day: $jd, | |
| calendar: CAL_JEWISH, | |
| ); | |
| $hebrew_months = [ | |
| 1 => 'Tishri', | |
| 2 => 'Heshvan', | |
| 3 => 'Kislev', | |
| 4 => 'Tevet', | |
| 5 => 'Shevat', | |
| 6 => 'Adar', | |
| 7 => 'Adar II', | |
| 8 => 'Nisan', | |
| 9 => 'Iyar', | |
| 10 => 'Sivan', | |
| 11 => 'Tammuz', | |
| 12 => 'Av', | |
| 13 => 'Elul' | |
| ]; | |
| return sprintf("%d %s %d", | |
| $hebrew_date['day'], | |
| $hebrew_months[$hebrew_date['month']], | |
| $hebrew_date['year'] | |
| ); | |
| } | |
| private static function current_time(): \DateTime { | |
| return new \DateTime(); | |
| } | |
| private static function friday_730pm(): \DateTime { | |
| return new \DateTime(datetime: 'Friday this week 19:30') | |
| ->setTimezone(new \DateTimeZone(timezone: 'America/New_York')); | |
| } | |
| private static function saturday_830pm(): \DateTime { | |
| return new \DateTime(datetime: 'Saturday this week 20:30') | |
| ->setTimezone(new \DateTimeZone(timezone: 'America/New_York')); | |
| } | |
| public static function is_shabbat(): bool | |
| { | |
| return ( | |
| self::current_time() >= self::friday_730pm() | |
| && | |
| self::current_time() < self::saturday_830pm() | |
| ); | |
| } | |
| public static function remaining_time(): int { | |
| return self::saturday_830pm()->getTimestamp() - self::current_time()->getTimestamp(); | |
| } | |
| public static function end_time(): string { | |
| return self::saturday_830pm()->format('l, F j, Y'); | |
| } | |
| public static function send_headers(): void { | |
| if (!empty($_SERVER['HTTP_X_SHABBAT_CHECK'])) { | |
| return; // Exit if this header is already set | |
| } | |
| header('X-Shabbat-Check: true'); | |
| header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); | |
| header('Cache-Control: post-check=0, pre-check=0', false); | |
| header('Pragma: no-cache'); | |
| header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); | |
| header('Content-Type: text/html; charset=utf-8'); | |
| } | |
| public static function render_shabbat(): string { | |
| global $configs; | |
| $company = $configs['general']['company'] ?? 'This website'; | |
| $title = i18n::__("Shabbat Shalom!"); | |
| $remaining_time = self::remaining_time(); | |
| $h1 = i18n::__("SHABBAT SHALOM!"); | |
| $p1 = i18n::__("is honoring Yeshua's Sabbath for Shabbat."); | |
| $p2 = i18n::__("Our site will be back online in"); | |
| $p3 = i18n::__("We will reopen at 8:30pm on"); | |
| $p4 = i18n::__("Current Date"); | |
| $end_time = self::end_time(); | |
| $str_date = self::str_date(); | |
| return <<<DOD | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>{$title}</title> | |
| <style> | |
| body { | |
| background-color: #2F4F4F; /* Slate Steel Gray */ | |
| color: #2C2C2C; /* Noir Graphite Dark Gray */ | |
| font-family: Arial, sans-serif; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100vh; | |
| margin: 0; | |
| } | |
| .container { | |
| background-color: rgba(255, 255, 255, 0.9); | |
| padding: 2rem; | |
| border-radius: 10px; | |
| text-align: center; | |
| box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); | |
| max-width: 600px; | |
| width: 90%; | |
| } | |
| .countdown { | |
| font-size: 2rem; | |
| margin: 1rem 0; | |
| font-weight: bold; | |
| } | |
| h1 { | |
| margin-top: 0; | |
| } | |
| </style> | |
| <script> | |
| function startCountdown(seconds) { | |
| const countdownElem = document.getElementById('countdown'); | |
| function updateCountdown() { | |
| const days = Math.floor(seconds / 86400); | |
| const hours = Math.floor((seconds % 86400) / 3600); | |
| const minutes = Math.floor((seconds % 3600) / 60); | |
| const secs = seconds % 60; | |
| countdownElem.textContent = | |
| String(days).padStart(2, '0') + 'd ' + | |
| String(hours).padStart(2, '0') + 'h ' + | |
| String(minutes).padStart(2, '0') + 'm ' + | |
| String(secs).padStart(2, '0') + 's'; | |
| if (seconds > 0) { | |
| seconds--; | |
| setTimeout(updateCountdown, 1000); | |
| } | |
| } | |
| updateCountdown(); | |
| } | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const remainingTime = {$remaining_time}; | |
| startCountdown(remainingTime); | |
| }); | |
| </script> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>{$h1}</h1> | |
| <p>{$company} {$p1}</p> | |
| <p>{$p2}:</p> | |
| <div class="countdown" id="countdown"></div> | |
| <p>{$p3} {$end_time}.</p> | |
| <p>{$p4}: {$str_date}</p> | |
| </div> | |
| </body> | |
| </html> | |
| DOD; | |
| } | |
| } | |
| \class_alias(Shabbat::class, 'Shabbat'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment