File manager - Edit - /home/cipherteam/htdocs/cipherteam.in/API/IPO/V3/IPOCalendar/IPOCalandar.php
Back
<?php //IPOCalendar.php if(isset($_GET['c'])) $color = '#'.$_GET['c']; else $color = "#F16334"; function tintColor($hex, $percent) { $hex = ltrim($hex, '#'); if (strlen($hex) === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; $r = hexdec(substr($hex, 0, 2)); $g = hexdec(substr($hex, 2, 2)); $b = hexdec(substr($hex, 4, 2)); $r = (int)($r + (255 - $r) * $percent); $g = (int)($g + (255 - $g) * $percent); $b = (int)($b + (255 - $b) * $percent); return sprintf("#%02x%02x%02x", $r, $g, $b); } function shadeColor($hex, $percent) { $hex = ltrim($hex, '#'); if (strlen($hex) === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; $r = hexdec(substr($hex, 0, 2)); $g = hexdec(substr($hex, 2, 2)); $b = hexdec(substr($hex, 4, 2)); $r = (int)($r * (1 - $percent)); $g = (int)($g * (1 - $percent)); $b = (int)($b * (1 - $percent)); return sprintf("#%02x%02x%02x", $r, $g, $b); } $colorPageBg = tintColor($color, 0.93); $colorSurface = tintColor($color, 0.97); $colorSoft = tintColor($color, 0.86); $colorSofter = tintColor($color, 0.92); $colorLight = tintColor($color, 0.62); $colorHair = tintColor($color, 0.82); $colorDark = shadeColor($color, 0.45); $colorDeep = shadeColor($color, 0.65); // ------- Data fetch (DB) ------- $rows = []; $dbErr = ''; if (file_exists('Connection.php')) { require_once("Connection.php"); if (isset($con) && !$con->connect_error) { $sql = "SELECT `c_name` AS NAME, `TYPE` AS TYPE, `ipo_open` AS OPENN, `ipo_close` AS CLOSEE, `ipo_allotment` AS ALLOTMENT, `ipo_refund` AS REFUND, `ipo_credit` AS CREDIT, `ipo_listing` AS LISTING FROM `ipo_post`"; $res = $con->query($sql); if ($res) { $rows = $res->fetch_all(MYSQLI_ASSOC); $res->free(); } mysqli_close($con); } else { $dbErr = 'Database unavailable'; } } else { $dbErr = 'Connection.php missing'; } date_default_timezone_set("Asia/Kolkata"); $todayStr = date("d-m-Y"); $todayDt = new DateTime($todayStr); // ------- Build event index: for each day in next 30 days, list events ------- // Event meta — order matters for sorting events within a day $eventOrder = ['OPENN' => 1, 'CLOSEE' => 2, 'ALLOTMENT' => 3, 'REFUND' => 4, 'CREDIT' => 5, 'LISTING' => 6]; $eventLabel = ['OPENN' => 'Open', 'CLOSEE' => 'Close', 'ALLOTMENT' => 'Allotment', 'REFUND' => 'Refund', 'CREDIT' => 'Credit', 'LISTING' => 'Listing']; $eventClass = ['OPENN' => 'open', 'CLOSEE' => 'close', 'ALLOTMENT' => 'allot', 'REFUND' => 'refund', 'CREDIT' => 'credit', 'LISTING' => 'listing']; $days = []; // dayKey 'd-m-Y' => ['date' => DateTime, 'ipos' => [name => ['type' => 'M|S', 'events' => [{key,label,class}]]]] $totalEvents = 0; $totalIpos = 0; $ipoTypeMap = []; // company name => 'M' or 'S' $cur = clone $todayDt; for ($i = 0; $i < 30; $i++) { $dayKey = $cur->format("d-m-Y"); $days[$dayKey] = ['dt' => clone $cur, 'ipos' => []]; $cur->modify('+1 day'); } foreach ($rows as $row) { $name = trim((string)($row['NAME'] ?? '')); if ($name === '') continue; $type = strtoupper(trim((string)($row['TYPE'] ?? ''))); $type = ($type === 'S') ? 'S' : 'M'; $ipoTypeMap[$name] = $type; foreach ($eventOrder as $key => $_) { $d = trim((string)($row[$key] ?? '')); if ($d === '') continue; if (!isset($days[$d])) continue; // outside the 30-day window if (!isset($days[$d]['ipos'][$name])) { $days[$d]['ipos'][$name] = ['type' => $type, 'events' => []]; $totalIpos++; } $days[$d]['ipos'][$name]['events'][] = [ 'key' => $key, 'label' => $eventLabel[$key], 'class' => $eventClass[$key], ]; $totalEvents++; } } // Sort events inside each IPO by canonical lifecycle order foreach ($days as $k => $day) { foreach ($day['ipos'] as $name => $ipo) { usort($days[$k]['ipos'][$name]['events'], function($a, $b) use ($eventOrder) { return $eventOrder[$a['key']] - $eventOrder[$b['key']]; }); } } // Today's events (separate panel) $todayKey = $todayDt->format("d-m-Y"); $todayIpos = isset($days[$todayKey]) ? $days[$todayKey]['ipos'] : []; // Pre-compute per-event-type counts for filter chips $evtCounts = ['all' => 0, 'open' => 0, 'close' => 0, 'allot' => 0, 'refund' => 0, 'credit' => 0, 'listing' => 0]; foreach ($days as $day) { foreach ($day['ipos'] as $ipo) { foreach ($ipo['events'] as $e) { $evtCounts['all']++; $evtCounts[$e['class']]++; } } } $hasAnyData = $totalEvents > 0; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>IPO Calendar</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,ital,wght@9..144,0,400;9..144,0,500;9..144,0,600;9..144,0,700;9..144,1,400;9..144,1,500&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@500;600;700&display=swap" rel="stylesheet"> <style> :root { --accent: <?php echo $color; ?>; --accent-deep: <?php echo $colorDeep; ?>; --accent-dark: <?php echo $colorDark; ?>; --accent-light: <?php echo $colorLight; ?>; --accent-hair: <?php echo $colorHair; ?>; --accent-soft: <?php echo $colorSoft; ?>; --accent-softer: <?php echo $colorSofter; ?>; --page: <?php echo $colorPageBg; ?>; --surface: #ffffff; --surface-tint: <?php echo $colorSurface; ?>; --ink: #1a1512; --ink-2: #4a4340; --ink-3: #7a746f; /* Event semantics — fixed across themes */ --evt-open: #0f6b3f; /* green — bidding starts */ --evt-open-bg: #def0e5; --evt-close: #a81d25; /* red — last day */ --evt-close-bg: #fadee0; --evt-allot: #b06000; /* amber — assignment */ --evt-allot-bg: #fcefd6; --evt-refund: #2c6e6e; /* teal — money back */ --evt-refund-bg: #d8efed; --evt-credit: #1e4a8c; /* blue — shares delivered */ --evt-credit-bg: #dbe7f7; --evt-listing: #6b21a8; /* purple — the big day */ --evt-listing-bg:#ece2f5; --radius: 16px; --radius-sm: 10px; --radius-pill: 999px; } * { box-sizing: border-box; } html, body { background: var(--page); background-image: radial-gradient(circle at 10% 0%, var(--accent-softer) 0%, transparent 40%), radial-gradient(circle at 100% 100%, var(--accent-soft) 0%, transparent 45%); background-attachment: fixed; } body { padding: 16px 12px 24px; min-height: 100vh; font-family: 'DM Sans', system-ui, sans-serif; font-size: 14px; line-height: 1.4; color: var(--ink); -webkit-font-smoothing: antialiased; } a { text-decoration: none; color: var(--accent); } /* ---------- Header ---------- */ .header { background: linear-gradient(135deg, var(--accent) 0%, var(--accent-deep) 100%); color: #fff; border-radius: var(--radius); padding: 18px 20px; margin-bottom: 12px; position: relative; overflow: hidden; box-shadow: 0 10px 30px -12px <?php echo $color; ?>66; } .header::before { position: absolute; content: ""; right: -20px; top: -20px; width: 70px; height: 70px; border-radius: 50%; border: 1.5px solid rgba(255,255,255,0.18); } .header::after { position: absolute; content: ""; right: -45px; top: -45px; width: 120px; height: 120px; border-radius: 50%; border: 1.5px solid rgba(255,255,255,0.10); } .header__title { font-family: 'Fraunces', serif; font-weight: 500; font-size: 26px; letter-spacing: -0.025em; color: #fff; display: flex; align-items: baseline; gap: 8px; position: relative; z-index: 1; flex-wrap: wrap; } .header__title em { font-style: italic; font-weight: 400; color: rgba(255,255,255,0.85); } .header__pulse { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #fff; margin-left: 2px; animation: pulse 1.8s ease-in-out infinite; } .header__sub { font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 500; letter-spacing: 0.10em; text-transform: uppercase; color: rgba(255,255,255,0.78); margin-top: 6px; position: relative; z-index: 1; } .header__stats { display: flex; gap: 18px; margin-top: 14px; padding-top: 12px; border-top: 1px solid rgba(255,255,255,0.18); position: relative; z-index: 1; } .header__stat-num { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 18px; color: #fff; line-height: 1; } .header__stat-lbl { font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(255,255,255,0.72); margin-top: 4px; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255,255,255,0.7); } 70% { box-shadow: 0 0 0 8px rgba(255,255,255,0); } 100% { box-shadow: 0 0 0 0 rgba(255,255,255,0); } } /* ---------- Today panel (the hero) ---------- */ .today { background: var(--surface); border: 2px solid var(--accent); border-radius: var(--radius); padding: 14px 16px 16px; margin-bottom: 14px; position: relative; overflow: hidden; box-shadow: 0 8px 24px -10px <?php echo $color; ?>aa; animation: slideUp .4s ease backwards; } .today::after { content: ""; position: absolute; right: -40px; top: -40px; width: 120px; height: 120px; border-radius: 50%; background: var(--accent-softer); opacity: 0.6; pointer-events: none; } .today__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 12px; position: relative; z-index: 1; } .today__label { font-family: 'DM Sans', sans-serif; font-size: 9.5px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); display: flex; align-items: center; gap: 6px; } .today__label::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: pulse 1.8s ease-in-out infinite; } .today__date { font-family: 'Fraunces', serif; font-style: italic; font-size: 13px; color: var(--accent-dark); } .today__heading { font-family: 'Fraunces', serif; font-weight: 500; font-size: 22px; letter-spacing: -0.02em; color: var(--accent-deep); line-height: 1.15; margin-bottom: 14px; position: relative; z-index: 1; } .today__empty { font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--ink-3); padding: 8px 0 4px; position: relative; z-index: 1; } /* ---------- Filter card ---------- */ .filters { background: var(--surface); border: 1px solid var(--accent-hair); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 12px; box-shadow: 0 2px 0 <?php echo $color; ?>0d; } .search-field { position: relative; display: flex; align-items: center; margin-bottom: 11px; } .search-field__icon { position: absolute; left: 12px; width: 14px; height: 14px; color: var(--accent); opacity: 0.85; pointer-events: none; } .search-field__input { font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--ink); background: var(--surface-tint); border: 1px solid var(--accent-hair); border-radius: var(--radius-sm); padding: 9px 36px 9px 34px; width: 100%; transition: border-color .15s ease, box-shadow .15s ease, background .15s ease; } .search-field__input::placeholder { color: var(--ink-3); } .search-field__input:focus { outline: none; background: var(--surface); border-color: var(--accent-light); box-shadow: 0 0 0 3px <?php echo $color; ?>22; } .search-field__clear { position: absolute; right: 8px; width: 22px; height: 22px; border-radius: 50%; background: var(--accent-soft); color: var(--accent-deep); border: none; cursor: pointer; display: none; align-items: center; justify-content: center; font-size: 14px; line-height: 1; padding: 0; transition: background .15s ease, color .15s ease; } .search-field__clear:hover { background: var(--accent); color: #fff; } .search-field.is-active .search-field__clear { display: inline-flex; } /* Filter chip rows */ .chip-row { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 9px; } .chip-row:last-child { margin-bottom: 0; } .chip-row__label { font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-dark); opacity: 0.7; align-self: center; margin-right: 4px; } .chip { display: inline-flex; align-items: center; gap: 5px; padding: 5px 11px 5px 10px; border-radius: var(--radius-pill); background: var(--accent-softer); color: var(--accent-dark); border: 1px solid transparent; font-family: 'DM Sans', sans-serif; font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; cursor: pointer; user-select: none; transition: background .15s ease, color .15s ease, border-color .15s ease, box-shadow .15s ease; } .chip__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex-shrink: 0; } .chip__count { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 9.5px; padding: 1px 5px; border-radius: var(--radius-pill); background: rgba(0,0,0,0.06); color: inherit; } .chip:hover { color: var(--accent); } .chip.is-active { background: var(--accent); color: #fff; box-shadow: 0 3px 8px -2px <?php echo $color; ?>66; } .chip.is-active .chip__dot { background: #fff; } .chip.is-active .chip__count { background: rgba(255,255,255,0.22); } /* Event-specific dots */ .chip[data-evt="open"] .chip__dot { background: var(--evt-open); } .chip[data-evt="close"] .chip__dot { background: var(--evt-close); } .chip[data-evt="allot"] .chip__dot { background: var(--evt-allot); } .chip[data-evt="refund"] .chip__dot { background: var(--evt-refund); } .chip[data-evt="credit"] .chip__dot { background: var(--evt-credit); } .chip[data-evt="listing"].chip__dot, .chip[data-evt="listing"] .chip__dot { background: var(--evt-listing); } .chip.is-active .chip__dot { background: #fff; } /* ---------- Day card ---------- */ .day { background: var(--surface); border: 1px solid var(--accent-hair); border-radius: var(--radius); margin-bottom: 12px; overflow: hidden; position: relative; box-shadow: 0 2px 0 <?php echo $color; ?>0d; animation: slideUp .35s ease backwards; } @keyframes slideUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .day__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding: 12px 16px 10px; border-bottom: 1px dashed var(--accent-hair); background: var(--surface-tint); } .day__date-strip { display: flex; align-items: baseline; gap: 10px; min-width: 0; } .day__day-num { font-family: 'Fraunces', serif; font-weight: 600; font-size: 22px; color: var(--accent-deep); line-height: 1; letter-spacing: -0.02em; } .day__month { font-family: 'DM Sans', sans-serif; font-size: 10px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); } .day__weekday { font-family: 'Fraunces', serif; font-style: italic; font-size: 13px; color: var(--ink-2); } .day__count { font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700; color: var(--accent); background: var(--accent-softer); padding: 3px 9px; border-radius: var(--radius-pill); flex-shrink: 0; } .day--tomorrow .day__day-num { color: var(--accent); } .day__body { padding: 4px 0 4px; } /* ---------- IPO line in a day ---------- */ .ipo-line { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; padding: 10px 16px; align-items: flex-start; border-bottom: 1px solid var(--accent-hair); transition: background .15s ease; } .ipo-line:last-child { border-bottom: none; } .ipo-line:hover { background: var(--accent-softer); } .ipo-line__name-wrap { display: flex; align-items: baseline; gap: 8px; min-width: 0; flex-wrap: wrap; } .ipo-line__name { font-family: 'Fraunces', serif; font-weight: 500; font-size: 14px; line-height: 1.25; letter-spacing: -0.01em; color: var(--accent-deep); min-width: 0; overflow: hidden; text-overflow: ellipsis; } .ipo-line__type { font-family: 'DM Sans', sans-serif; font-size: 8.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-dark); background: var(--accent-softer); padding: 2px 7px 3px; border-radius: var(--radius-pill); flex-shrink: 0; } .ipo-line__type--sme { color: var(--accent); background: var(--accent-soft); } .ipo-line__events { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; align-items: flex-start; } /* Event chip — colored by lifecycle stage */ .evt { display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px 4px; border-radius: var(--radius-pill); font-family: 'DM Sans', sans-serif; font-size: 9.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap; } .evt::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex-shrink: 0; } .evt--open { color: var(--evt-open); background: var(--evt-open-bg); } .evt--close { color: var(--evt-close); background: var(--evt-close-bg); } .evt--allot { color: var(--evt-allot); background: var(--evt-allot-bg); } .evt--refund { color: var(--evt-refund); background: var(--evt-refund-bg); } .evt--credit { color: var(--evt-credit); background: var(--evt-credit-bg); } .evt--listing { color: var(--evt-listing); background: var(--evt-listing-bg); } /* Today panel uses larger event chips */ .today .ipo-line { padding: 9px 0; border-color: var(--accent-hair); } .today .ipo-line:first-child { padding-top: 0; } .today .ipo-line:last-child { border-bottom: none; padding-bottom: 0; } .today .ipo-line__name { font-size: 15px; } .today .evt { font-size: 10px; padding: 4px 11px 5px; } /* Filtered out — collapsed */ [data-filtered="out"] { display: none !important; } /* ---------- Skeleton ---------- */ .skel { display: block; background-color: var(--accent-softer); background-image: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.65) 50%, transparent 100%); background-size: 200% 100%; background-repeat: no-repeat; background-position: 200% 0; border-radius: 4px; animation: shimmer 1.4s infinite linear; } .skel--circle { border-radius: 50%; } .skel--pill { border-radius: 999px; } @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } @media (prefers-reduced-motion: reduce) { .skel { animation: none; } } /* ---------- Empty state ---------- */ .empty { background: var(--surface); border: 1px dashed var(--accent-light); border-radius: var(--radius); padding: 36px 22px; text-align: center; margin-bottom: 12px; animation: slideUp .5s ease backwards; } .empty__icon { width: 48px; height: 48px; margin: 0 auto 12px; border-radius: 50%; background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center; font-family: 'Fraunces', serif; font-size: 24px; font-style: italic; box-shadow: 0 6px 14px -4px <?php echo $color; ?>66; } .empty__text { font-family: 'Fraunces', serif; font-size: 17px; color: var(--accent-deep); font-weight: 500; } .empty__sub { margin-top: 6px; font-size: 12px; color: var(--accent-dark); opacity: 0.8; line-height: 1.5; } /* ---------- Disclaimer ---------- */ .disclaimer { background: var(--surface); border: 1px solid var(--accent-hair); border-left: 3px solid var(--accent); border-radius: var(--radius-sm); padding: 10px 14px 11px; margin-bottom: 4px; box-shadow: 0 1px 0 <?php echo $color; ?>0d; } .disclaimer__label { font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); margin-bottom: 4px; } .disclaimer__text { font-size: 11.5px; line-height: 1.5; color: var(--ink-2); } </style> </head> <body> <div class="header"> <div class="header__title">IPO <em>Calendar</em><span class="header__pulse"></span></div> <div class="header__sub">Next 30 days · Open · Close · Allotment · Listing</div> <?php if ($hasAnyData): ?> <div class="header__stats"> <div> <div class="header__stat-num"><?php echo (int)$totalEvents; ?></div> <div class="header__stat-lbl">Events</div> </div> <div> <div class="header__stat-num"><?php echo count(array_filter($days, function($d) { return !empty($d['ipos']); })); ?></div> <div class="header__stat-lbl">Active Days</div> </div> </div> <?php endif; ?> </div> <?php if (!$hasAnyData): ?> <div class="empty"> <div class="empty__icon">i</div> <div class="empty__text">No upcoming IPO events</div> <div class="empty__sub">There are no scheduled events in the next 30 days. Check back later.</div> </div> <?php else: ?> <!-- TODAY PANEL --> <?php $todayWeekday = $todayDt->format('l'); $todayPretty = $todayDt->format('j M Y'); ?> <div class="today" id="todayPanel"> <div class="today__head"> <div class="today__label">Today</div> <div class="today__date"><?php echo htmlspecialchars($todayWeekday . ', ' . $todayPretty); ?></div> </div> <?php if (count($todayIpos) === 0): ?> <div class="today__heading">No events today</div> <div class="today__empty">Quiet day — scroll down for the next 30 days.</div> <?php else: ?> <div class="today__heading"><?php echo count($todayIpos); ?> <?php echo count($todayIpos) === 1 ? 'IPO event' : 'IPO events'; ?> happening today</div> <?php foreach ($todayIpos as $name => $ipo): $searchKey = htmlspecialchars(mb_strtolower($name)); $typeText = $ipo['type'] === 'S' ? 'SME' : 'Mainline'; $typeCls = $ipo['type'] === 'S' ? 'ipo-line__type--sme' : ''; $eventCls = implode(' ', array_map(function($e) { return 'has-' . $e['class']; }, $ipo['events'])); ?> <div class="ipo-line" data-name="<?php echo $searchKey; ?>" data-type="<?php echo $ipo['type']; ?>" data-events="<?php echo htmlspecialchars(implode(' ', array_map(function($e) { return $e['class']; }, $ipo['events']))); ?>"> <div class="ipo-line__name-wrap"> <span class="ipo-line__name"><?php echo htmlspecialchars($name); ?></span> <span class="ipo-line__type <?php echo $typeCls; ?>"><?php echo $typeText; ?></span> </div> <div class="ipo-line__events"> <?php foreach ($ipo['events'] as $e): ?> <span class="evt evt--<?php echo $e['class']; ?>"><?php echo htmlspecialchars($e['label']); ?></span> <?php endforeach; ?> </div> </div> <?php endforeach; ?> <?php endif; ?> </div> <!-- FILTER CARD --> <div class="filters"> <div class="search-field" id="searchField"> <svg class="search-field__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"> <circle cx="11" cy="11" r="7"/> <path d="m20 20-3.5-3.5"/> </svg> <input type="text" id="search" class="search-field__input" placeholder="Search company name…" autocomplete="off"> <button type="button" class="search-field__clear" id="searchClear" aria-label="Clear">×</button> </div> <div class="chip-row" role="tablist" aria-label="Filter by IPO type"> <span class="chip-row__label">Type</span> <button type="button" class="chip is-active" data-type-filter="all"> <span class="chip__dot"></span>All </button> <button type="button" class="chip" data-type-filter="M"> <span class="chip__dot"></span>Mainline </button> <button type="button" class="chip" data-type-filter="S"> <span class="chip__dot"></span>SME </button> </div> <div class="chip-row" role="tablist" aria-label="Filter by event"> <span class="chip-row__label">Event</span> <button type="button" class="chip is-active" data-evt-filter="all"> <span class="chip__dot"></span>All <span class="chip__count"><?php echo $evtCounts['all']; ?></span> </button> <?php $evtChips = [ 'open' => 'Open', 'close' => 'Close', 'allot' => 'Allotment', 'refund' => 'Refund', 'credit' => 'Credit', 'listing' => 'Listing', ]; foreach ($evtChips as $cls => $label): if ($evtCounts[$cls] === 0) continue; // skip event types with zero events ?> <button type="button" class="chip" data-evt-filter="<?php echo $cls; ?>" data-evt="<?php echo $cls; ?>"> <span class="chip__dot"></span><?php echo $label; ?> <span class="chip__count"><?php echo $evtCounts[$cls]; ?></span> </button> <?php endforeach; ?> </div> </div> <!-- DAY CARDS (skip empty days, skip today since it's already shown above) --> <?php $cardIdx = 0; foreach ($days as $dayKey => $day): if ($dayKey === $todayKey) continue; // already in TODAY panel if (empty($day['ipos'])) continue; // skip quiet days $dt = $day['dt']; $dayNum = $dt->format('j'); $monthShort = strtoupper($dt->format('M')); $weekday = $dt->format('l'); $tomorrowDt = clone $todayDt; $tomorrowDt->modify('+1 day'); $isTomorrow = $dt->format('d-m-Y') === $tomorrowDt->format('d-m-Y'); $dayMod = $isTomorrow ? 'day--tomorrow' : ''; $ipoCount = count($day['ipos']); $delay = number_format(min($cardIdx, 14) * 0.04, 2); $cardIdx++; ?> <div class="day <?php echo $dayMod; ?>" style="animation-delay:<?php echo $delay; ?>s"> <div class="day__head"> <div class="day__date-strip"> <span class="day__day-num"><?php echo $dayNum; ?></span> <span class="day__month"><?php echo htmlspecialchars($monthShort); ?></span> <span class="day__weekday"><?php echo $isTomorrow ? 'Tomorrow' : htmlspecialchars($weekday); ?></span> </div> <span class="day__count"><?php echo $ipoCount; ?> <?php echo $ipoCount === 1 ? 'IPO' : 'IPOs'; ?></span> </div> <div class="day__body"> <?php foreach ($day['ipos'] as $name => $ipo): $searchKey = htmlspecialchars(mb_strtolower($name)); $typeText = $ipo['type'] === 'S' ? 'SME' : 'Mainline'; $typeCls = $ipo['type'] === 'S' ? 'ipo-line__type--sme' : ''; ?> <div class="ipo-line" data-name="<?php echo $searchKey; ?>" data-type="<?php echo $ipo['type']; ?>" data-events="<?php echo htmlspecialchars(implode(' ', array_map(function($e) { return $e['class']; }, $ipo['events']))); ?>"> <div class="ipo-line__name-wrap"> <span class="ipo-line__name"><?php echo htmlspecialchars($name); ?></span> <span class="ipo-line__type <?php echo $typeCls; ?>"><?php echo $typeText; ?></span> </div> <div class="ipo-line__events"> <?php foreach ($ipo['events'] as $e): ?> <span class="evt evt--<?php echo $e['class']; ?>"><?php echo htmlspecialchars($e['label']); ?></span> <?php endforeach; ?> </div> </div> <?php endforeach; ?> </div> </div> <?php endforeach; ?> <div class="empty" id="searchEmpty" style="display:none"> <div class="empty__icon">i</div> <div class="empty__text">No matches</div> <div class="empty__sub" id="searchEmptySub">Try a different name or change the filters.</div> </div> <?php endif; ?> <div class="disclaimer"> <div class="disclaimer__label">Disclaimer</div> <div class="disclaimer__text"> Calendar dates are based on issuer announcements and may shift. Information only — not investment advice. Always verify with the registrar before acting. </div> </div> <script> (function() { var $input = document.getElementById('search'); var $field = document.getElementById('searchField'); var $clear = document.getElementById('searchClear'); var $lines = document.querySelectorAll('.ipo-line'); var $days = document.querySelectorAll('.day'); var $typeChips = document.querySelectorAll('[data-type-filter]'); var $evtChips = document.querySelectorAll('[data-evt-filter]'); var $searchEmpty = document.getElementById('searchEmpty'); var $searchEmptySub = document.getElementById('searchEmptySub'); if (!$lines.length) return; var state = { q: '', type: 'all', evt: 'all' }; function applyFilters() { var q = state.q.toLowerCase().trim(); var matchedLines = 0; if (q === '') $field && $field.classList.remove('is-active'); else $field && $field.classList.add('is-active'); // Apply line-level filters for (var i = 0; i < $lines.length; i++) { var line = $lines[i]; var name = line.getAttribute('data-name') || ''; var type = line.getAttribute('data-type') || ''; var evts = line.getAttribute('data-events') || ''; var typeOK = state.type === 'all' || state.type === type; var evtOK = state.evt === 'all' || evts.split(' ').indexOf(state.evt) !== -1; var qOK = q === '' || name.indexOf(q) !== -1; if (typeOK && evtOK && qOK) { line.removeAttribute('data-filtered'); matchedLines++; } else { line.setAttribute('data-filtered', 'out'); } } // Hide day cards that have no visible lines after filtering for (var j = 0; j < $days.length; j++) { var day = $days[j]; var visibleLines = day.querySelectorAll('.ipo-line:not([data-filtered="out"])').length; if (visibleLines === 0) day.setAttribute('data-filtered', 'out'); else day.removeAttribute('data-filtered'); } // Show "no matches" panel only when filtering is active and nothing matches var isFiltering = q !== '' || state.type !== 'all' || state.evt !== 'all'; if ($searchEmpty) { if (isFiltering && matchedLines === 0) { if ($searchEmptySub) { var hints = []; if (q !== '') hints.push('"' + state.q.trim() + '"'); if (state.type !== 'all') hints.push(state.type === 'M' ? 'Mainline' : 'SME'); if (state.evt !== 'all') hints.push(state.evt.charAt(0).toUpperCase() + state.evt.slice(1) + ' events'); $searchEmptySub.textContent = 'No matches for ' + hints.join(' · ') + '. Try clearing some filters.'; } $searchEmpty.style.display = 'block'; } else { $searchEmpty.style.display = 'none'; } } } if ($input) { $input.addEventListener('input', function() { state.q = $input.value; applyFilters(); }); } if ($clear) { $clear.addEventListener('click', function() { $input.value = ''; state.q = ''; applyFilters(); $input.focus(); }); } for (var k = 0; k < $typeChips.length; k++) { $typeChips[k].addEventListener('click', function() { if (this.classList.contains('is-active')) return; for (var m = 0; m < $typeChips.length; m++) $typeChips[m].classList.remove('is-active'); this.classList.add('is-active'); state.type = this.getAttribute('data-type-filter'); applyFilters(); }); } for (var n = 0; n < $evtChips.length; n++) { $evtChips[n].addEventListener('click', function() { if (this.classList.contains('is-active')) return; for (var p = 0; p < $evtChips.length; p++) $evtChips[p].classList.remove('is-active'); this.classList.add('is-active'); state.evt = this.getAttribute('data-evt-filter'); applyFilters(); }); } })(); </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 8.2.9 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings