Spaces:
Sleeping
Sleeping
| {% extends 'base.html' %} | |
| {% load static %} | |
| {% block title %}Constellation Database — Constellar{% endblock %} | |
| {% block extra_css %} | |
| <style> | |
| /* ── search ── */ | |
| .search-wrap { position: relative; max-width: 480px; margin: 0 auto; } | |
| .search-input { | |
| width: 100%; | |
| background: rgba(255,255,255,.04); | |
| border: 1px solid var(--border); | |
| border-radius: 10px; | |
| padding: .8rem 1rem .8rem 2.75rem; | |
| font-size: .875rem; | |
| font-family: 'Inter', sans-serif; | |
| color: var(--text); | |
| outline: none; | |
| transition: border-color .15s; | |
| } | |
| .search-input:focus { border-color: rgba(99,102,241,.45); } | |
| .search-input::placeholder { color: var(--muted); } | |
| .search-icon { | |
| position: absolute; left: .875rem; top: 50%; | |
| transform: translateY(-50%); | |
| color: var(--muted); pointer-events: none; | |
| } | |
| /* ── view toggle ── */ | |
| .view-toggle-wrap { | |
| display: inline-flex; | |
| background: rgba(255,255,255,.04); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| padding: 3px; | |
| gap: 2px; | |
| } | |
| .view-toggle { | |
| font-family: 'Inter', sans-serif; | |
| font-size: .78125rem; font-weight: 500; | |
| display: inline-flex; align-items: center; gap: .375rem; | |
| padding: .45rem .875rem; | |
| border-radius: 6px; | |
| border: none; cursor: pointer; | |
| background: transparent; | |
| color: var(--muted); | |
| transition: all .15s; | |
| } | |
| .view-toggle.active { background: var(--accent); color: #fff; } | |
| .view-toggle:not(.active):hover { color: #fff; } | |
| /* ── grid card ── */ | |
| .db-card { | |
| background: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: 12px; | |
| overflow: hidden; | |
| cursor: pointer; | |
| transition: border-color .2s, transform .2s; | |
| } | |
| .db-card:hover { | |
| border-color: rgba(99,102,241,.35); | |
| transform: translateY(-3px); | |
| } | |
| .db-card-img { | |
| position: relative; | |
| width: 100%; | |
| aspect-ratio: 4/3; | |
| background: rgba(99,102,241,.05); | |
| overflow: hidden; | |
| } | |
| .db-card-img img { | |
| width: 100%; height: 100%; | |
| object-fit: cover; | |
| display: block; | |
| transition: transform .3s; | |
| } | |
| .db-card:hover .db-card-img img { transform: scale(1.04); } | |
| .db-card-body { padding: 1rem 1.125rem 1.25rem; } | |
| .db-card-body h3 { | |
| font-size: .9375rem; font-weight: 600; | |
| margin: 0 0 .375rem; color: #fff; | |
| } | |
| .db-card-body p { | |
| font-size: .75rem; color: var(--muted); | |
| line-height: 1.6; margin: 0; | |
| } | |
| /* ── list row ── */ | |
| .db-row { | |
| display: flex; align-items: center; gap: 1rem; | |
| background: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: 10px; | |
| padding: .875rem 1.125rem; | |
| cursor: pointer; | |
| transition: border-color .2s, background .2s; | |
| } | |
| .db-row:hover { | |
| border-color: rgba(99,102,241,.3); | |
| background: rgba(99,102,241,.05); | |
| } | |
| .db-row-img { | |
| width: 52px; height: 52px; flex-shrink: 0; | |
| border-radius: 9px; | |
| overflow: hidden; | |
| background: rgba(99,102,241,.08); | |
| } | |
| .db-row-img img { width: 100%; height: 100%; object-fit: cover; display: block; } | |
| .db-row h3 { font-size: .875rem; font-weight: 600; margin: 0 0 .2rem; color: #fff; } | |
| .db-row p { font-size: .75rem; color: var(--muted); margin: 0; line-height: 1.5; } | |
| /* ── filter chips ── */ | |
| .chip { | |
| font-family: 'Inter', sans-serif; | |
| font-size: .75rem; font-weight: 500; | |
| padding: .4rem .875rem; | |
| border-radius: 999px; | |
| border: 1px solid var(--border); | |
| background: rgba(255,255,255,.03); | |
| color: var(--muted); | |
| cursor: pointer; | |
| transition: all .15s; | |
| } | |
| .chip:hover { color: #fff; border-color: rgba(255,255,255,.18); } | |
| .chip.active { | |
| background: var(--accent-dim); | |
| border-color: rgba(99,102,241,.45); | |
| color: #a5b4fc; | |
| } | |
| mark { | |
| background: rgba(99,102,241,.3); | |
| color: inherit; | |
| border-radius: 3px; | |
| padding: 0 1px; | |
| } | |
| /* ── detail modal ── */ | |
| .modal-backdrop { | |
| position: fixed; inset: 0; | |
| background: rgba(3,7,18,.8); | |
| backdrop-filter: blur(6px); | |
| z-index: 100; | |
| display: none; | |
| align-items: center; justify-content: center; | |
| padding: 1.5rem; | |
| } | |
| .modal-backdrop.open { display: flex; } | |
| .modal-card { | |
| background: #0a1226; | |
| border: 1px solid rgba(255,255,255,.1); | |
| border-radius: 16px; | |
| max-width: 480px; width: 100%; | |
| max-height: 88vh; | |
| overflow-y: auto; | |
| animation: modalIn .22s ease; | |
| } | |
| @keyframes modalIn { | |
| from { opacity: 0; transform: translateY(14px) scale(.98); } | |
| to { opacity: 1; transform: none; } | |
| } | |
| .modal-img { | |
| width: 100%; aspect-ratio: 16/10; | |
| object-fit: cover; display: block; | |
| } | |
| .modal-close { | |
| position: absolute; top: 1rem; right: 1rem; | |
| width: 32px; height: 32px; | |
| border-radius: 8px; | |
| border: 1px solid rgba(255,255,255,.15); | |
| background: rgba(6,13,31,.7); | |
| color: #fff; cursor: pointer; | |
| display: flex; align-items: center; justify-content: center; | |
| backdrop-filter: blur(6px); | |
| transition: background .15s; | |
| } | |
| .modal-close:hover { background: rgba(255,255,255,.12); } | |
| .modal-type { | |
| display: inline-block; | |
| font-size: .625rem; font-weight: 700; | |
| letter-spacing: .08em; text-transform: uppercase; | |
| padding: .25rem .625rem; | |
| border-radius: 5px; | |
| background: var(--accent-dim); | |
| color: #a5b4fc; | |
| margin-bottom: .75rem; | |
| } | |
| .fact-card { | |
| background: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: 12px; | |
| padding: 1.75rem; | |
| } | |
| .fact-card h3 { | |
| font-size: .9375rem; font-weight: 600; | |
| margin: 0 0 .625rem; color: #a5b4fc; | |
| } | |
| .fact-card p { font-size: .8125rem; color: var(--muted); line-height: 1.7; margin: 0; } | |
| </style> | |
| {% endblock %} | |
| {% block content %} | |
| <!-- ════ HEADER ════ --> | |
| <section class="section" style="padding-top:4rem; padding-bottom:2rem; text-align:center;"> | |
| <div class="tag" style="margin-bottom:1.25rem;">IAU Official Catalog</div> | |
| <h1 style="font-family:'Orbitron',monospace; font-size:clamp(1.6rem,3.5vw,2.5rem); font-weight:900; margin:0 0 1rem; letter-spacing:-.01em;"> | |
| All 88 Constellations | |
| </h1> | |
| <p style="font-size:.9375rem; color:var(--muted); line-height:1.7; max-width:520px; margin:0 auto 2.25rem;"> | |
| The complete catalog of officially recognized constellations — each with its mythology and place in the night sky. | |
| </p> | |
| <!-- search --> | |
| <div class="search-wrap" style="margin-bottom:1.25rem;"> | |
| <div class="search-icon"> | |
| <svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> | |
| <circle cx="11" cy="11" r="8"/><path stroke-linecap="round" d="m21 21-4.35-4.35"/> | |
| </svg> | |
| </div> | |
| <input type="text" placeholder="Search constellations…" class="search-input" id="searchInput" /> | |
| </div> | |
| <!-- filter chips --> | |
| <div style="display:flex; gap:.5rem; justify-content:center; flex-wrap:wrap; margin-bottom:1.25rem;"> | |
| <button class="chip active" data-filter="all">All 88</button> | |
| <button class="chip" data-filter="zodiac">Zodiac</button> | |
| <button class="chip" data-filter="northern">Northern Sky</button> | |
| <button class="chip" data-filter="southern">Southern Sky</button> | |
| </div> | |
| <!-- view toggle + count --> | |
| <div style="display:flex; align-items:center; justify-content:center; gap:1rem; flex-wrap:wrap;"> | |
| <div class="view-toggle-wrap"> | |
| <button class="view-toggle active" data-view="grid" id="gridBtn"> | |
| <svg width="13" height="13" fill="currentColor" viewBox="0 0 20 20"><path d="M5 3a2 2 0 00-2 2v2a2 2 0 002 2h2a2 2 0 002-2V5a2 2 0 00-2-2H5zM5 11a2 2 0 00-2 2v2a2 2 0 002 2h2a2 2 0 002-2v-2a2 2 0 00-2-2H5zM11 5a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V5zM11 13a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"/></svg> | |
| Grid | |
| </button> | |
| <button class="view-toggle" data-view="list" id="listBtn"> | |
| <svg width="13" height="13" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"/></svg> | |
| List | |
| </button> | |
| </div> | |
| <p style="font-size:.75rem; color:var(--muted); margin:0;" id="resultsCount"> | |
| Showing <span id="filteredCount">88</span> of 88 | |
| </p> | |
| </div> | |
| </section> | |
| <!-- ════ CATALOG ════ --> | |
| <section style="padding:0 1.5rem 3rem;"> | |
| <div style="max-width:1280px; margin:0 auto;"> | |
| <div style="display:grid; grid-template-columns:repeat(auto-fill,minmax(250px,1fr)); gap:1rem;" id="gridView"></div> | |
| <div style="display:none; flex-direction:column; gap:.625rem;" id="listView"></div> | |
| <!-- no results --> | |
| <div style="text-align:center; padding:3.5rem 1rem; display:none;" id="noResults"> | |
| <div style="width:52px; height:52px; border-radius:13px; background:rgba(255,255,255,.04); border:1px solid var(--border); display:flex; align-items:center; justify-content:center; margin:0 auto 1.125rem;"> | |
| <svg width="22" height="22" fill="none" stroke="rgba(221,228,240,.4)" stroke-width="1.6" viewBox="0 0 24 24"> | |
| <circle cx="11" cy="11" r="8"/><path stroke-linecap="round" d="m21 21-4.35-4.35M8 11h6"/> | |
| </svg> | |
| </div> | |
| <h3 style="font-size:.9375rem; font-weight:600; margin:0 0 .375rem;">No constellations found</h3> | |
| <p style="font-size:.8125rem; color:var(--muted); margin:0;">Try a different search term.</p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- ════ FACTS ════ --> | |
| <section style="border-top:1px solid var(--border);"> | |
| <div class="section" style="padding-top:3.5rem; padding-bottom:1rem;"> | |
| <div style="text-align:center; margin-bottom:2rem;"> | |
| <p class="section-label" style="justify-content:center;">Background</p> | |
| <h2 style="font-family:'Orbitron',monospace; font-size:clamp(1.2rem,2.5vw,1.6rem); font-weight:700; margin:0;"> | |
| A Brief History | |
| </h2> | |
| </div> | |
| <div style="display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:1rem;"> | |
| <div class="fact-card"> | |
| <h3>Ancient origins</h3> | |
| <p>Many constellations date back to ancient Mesopotamia and were later adopted by the Greeks and Romans, who wove them into their mythology.</p> | |
| </div> | |
| <div class="fact-card"> | |
| <h3>Celestial navigation</h3> | |
| <p>Before modern instruments, sailors used constellations like Ursa Minor — home of the North Star — to navigate open seas.</p> | |
| </div> | |
| <div class="fact-card"> | |
| <h3>Modern standard</h3> | |
| <p>The 88 official constellations were standardized by the International Astronomical Union in 1922, defining the sky map still used today.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- ════ DETAIL MODAL ════ --> | |
| <div class="modal-backdrop" id="modalBackdrop"> | |
| <div class="modal-card" style="position:relative;"> | |
| <button class="modal-close" id="modalClose" aria-label="Close"> | |
| <svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" d="M6 18L18 6M6 6l12 12"/></svg> | |
| </button> | |
| <img class="modal-img" id="modalImg" src="" alt=""> | |
| <div style="padding:1.5rem 1.75rem 1.75rem;"> | |
| <span class="modal-type" id="modalType"></span> | |
| <h3 id="modalName" style="font-family:'Orbitron',monospace; font-size:1.25rem; font-weight:700; margin:0 0 .625rem; color:#fff;"></h3> | |
| <p id="modalDesc" style="font-size:.875rem; color:var(--muted); line-height:1.75; margin:0 0 1.5rem;"></p> | |
| <a href="{{ CHATBOT_BASE_URL }}" class="btn-accent" style="padding:.6rem 1.25rem; display:inline-block;" id="modalChat"> | |
| Ask the AI assistant about this → | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| {% endblock %} | |
| {% block extra_js %} | |
| <script> | |
| const constellationData = [ | |
| { id: 0, name: "Andromeda", description: "The Royal Sea Monster Bait, a princess chained to a rock as sacrifice", image: "image0.webp" }, | |
| { id: 1, name: "Antlia", description: "The Air Pump, a scientific instrument invented in the 17th century", image: "image1.webp" }, | |
| { id: 2, name: "Apus", description: "The Bird of Paradise, representing exotic birds from New Guinea", image: "image2.webp" }, | |
| { id: 3, name: "Aquarius", description: "The Water-Bearer, representing a figure pouring water from a jar", image: "image3.webp" }, | |
| { id: 4, name: "Aquila", description: "The Thunderbolt Eagle, Zeus's eagle that carried his thunderbolts", image: "image4.webp" }, | |
| { id: 5, name: "Ara", description: "The Altar, where gods formed an alliance before battling the Titans", image: "image5.webp" }, | |
| { id: 6, name: "Aries", description: "The Ram with the golden fleece from Greek mythology", image: "image6.webp" }, | |
| { id: 7, name: "Auriga", description: "The Charioteer, a skilled chariot driver in Greek mythology", image: "image7.webp" }, | |
| { id: 8, name: "Boötes", description: "The Herdsman, said to be hunting the bears of Ursa Major and Minor", image: "image8.webp" }, | |
| { id: 9, name: "Caelum", description: "The Chisel, a tool used by sculptors to create artistic works", image: "image9.webp" }, | |
| { id: 10, name: "Camelopardalis", description: "The Giraffe, one of the larger but fainter constellations", image: "image10.webp" }, | |
| { id: 11, name: "Cancer", description: "The Crab sent by Hera to distract Hercules during his labors", image: "image11.webp" }, | |
| { id: 12, name: "Canes Venatici", description: "The Hunting Dogs, represented by two dogs named Asterion and Chara", image: "image12.webp" }, | |
| { id: 13, name: "Canis Major", description: "The Big Dog, containing Sirius, the brightest star in our night sky", image: "image13.webp" }, | |
| { id: 14, name: "Canis Minor", description: "The Small Dog, companion to Orion the hunter", image: "image14.webp" }, | |
| { id: 15, name: "Capricornus", description: "The Sea Goat, a mythological creature with a goat's head and fish's tail", image: "image15.webp" }, | |
| { id: 16, name: "Carina", description: "The Keel of the ship Argo Navis from Jason and the Argonauts", image: "image16.webp" }, | |
| { id: 17, name: "Cassiopeia", description: "The Vain Queen whose boasting led to her daughter being sacrificed", image: "image17.webp" }, | |
| { id: 18, name: "Centaurus", description: "The Centaur, containing Alpha Centauri, the closest star system to our own", image: "image18.webp" }, | |
| { id: 19, name: "Cepheus", description: "The King, husband of Cassiopeia and father of Andromeda", image: "image19.webp" }, | |
| { id: 20, name: "Cetus", description: "The Whale or sea monster sent to devour Andromeda", image: "image20.webp" }, | |
| { id: 21, name: "Chamaeleon", description: "The Chameleon, a small southern constellation named after the reptile", image: "image21.webp" }, | |
| { id: 22, name: "Circinus", description: "The Compass used for drawing circles, a modern scientific constellation", image: "image22.webp" }, | |
| { id: 23, name: "Columba", description: "The Dove, representing the bird that Noah sent from the Ark", image: "image23.webp" }, | |
| { id: 24, name: "Coma Berenices", description: "Berenice's Hair, named after Queen Berenice II who sacrificed her hair", image: "image24.webp" }, | |
| { id: 25, name: "Corona Australis", description: "The Southern Crown, representing a crown worn by centaurs", image: "image25.webp" }, | |
| { id: 26, name: "Corona Borealis", description: "The Northern Crown, a crown given to Ariadne by Dionysus", image: "image26.webp" }, | |
| { id: 27, name: "Corvus", description: "The Raven, Apollo's sacred bird in Greek mythology", image: "image27.webp" }, | |
| { id: 28, name: "Crater", description: "The Cup, representing the cup of Apollo in Greek mythology", image: "image28.webp" }, | |
| { id: 29, name: "Crux", description: "The Southern Cross, the smallest constellation but one of the most recognizable", image: "image29.webp" }, | |
| { id: 30, name: "Cygnus", description: "The Swan, representing Zeus in disguise or the friend of Phaethon", image: "image30.webp" }, | |
| { id: 31, name: "Delphinus", description: "The Dolphin, representing the creature that saved the poet Arion", image: "image31.webp" }, | |
| { id: 32, name: "Dorado", description: "The Goldfish or Swordfish, home to most of the Large Magellanic Cloud", image: "image32.webp" }, | |
| { id: 33, name: "Draco", description: "The Dragon that guarded the golden apples in the Garden of Hesperides", image: "image33.webp" }, | |
| { id: 34, name: "Equuleus", description: "The Little Horse, representing the brother of Pegasus given to Castor", image: "image34.webp" }, | |
| { id: 35, name: "Eridanus", description: "The River, representing the path Phaethon fell after failing to drive the sun chariot", image: "image35.webp" }, | |
| { id: 36, name: "Fornax", description: "The Furnace, a modern constellation representing a chemist's furnace", image: "image36.webp" }, | |
| { id: 37, name: "Gemini", description: "The Twins Castor and Pollux from Greek mythology", image: "image37.webp" }, | |
| { id: 38, name: "Grus", description: "The Crane, a southern bird constellation created in the 16th century", image: "image38.webp" }, | |
| { id: 39, name: "Hercules", description: "The Strong Man, representing the Greek hero known for his twelve labors", image: "image39.webp" }, | |
| { id: 40, name: "Horologium", description: "The Pendulum Clock, a modern constellation representing a timekeeping device", image: "image40.webp" }, | |
| { id: 41, name: "Hydra", description: "The Water Serpent, the largest constellation in the sky", image: "image41.webp" }, | |
| { id: 42, name: "Hydrus", description: "The Watersnake, a southern constellation distinct from Hydra", image: "image42.webp" }, | |
| { id: 43, name: "Indus", description: "The Indian, representing a native of the East Indies", image: "image43.webp" }, | |
| { id: 44, name: "Lacerta", description: "The Lizard, a small and faint northern constellation", image: "image44.webp" }, | |
| { id: 45, name: "Leo", description: "The Lion that Hercules slew as his first labor", image: "image45.webp" }, | |
| { id: 46, name: "Leo Minor", description: "The Little Lion, a small constellation near Leo", image: "image46.webp" }, | |
| { id: 47, name: "Lepus", description: "The Hare/Rabbit hunted by Orion and his dogs", image: "image47.webp" }, | |
| { id: 48, name: "Libra", description: "The Scales, the only zodiac constellation representing an inanimate object", image: "image48.webp" }, | |
| { id: 49, name: "Lupus", description: "The Wolf, an ancient constellation associated with various myths", image: "image49.webp" }, | |
| { id: 50, name: "Lynx", description: "The Lynx, named for the keen eyesight needed to see its faint stars", image: "image50.webp" }, | |
| { id: 51, name: "Lyra", description: "The Harp played by Orpheus, containing the bright star Vega", image: "image51.webp" }, | |
| { id: 52, name: "Mensa", description: "The Table Mountain in South Africa, containing part of the Large Magellanic Cloud", image: "image52.webp" }, | |
| { id: 53, name: "Microscopium", description: "The Microscope, a modern constellation representing the scientific instrument", image: "image53.webp" }, | |
| { id: 54, name: "Monoceros", description: "The Unicorn, a faint constellation between Orion and Hydra", image: "image54.webp" }, | |
| { id: 55, name: "Musca", description: "The Fly, a small southern constellation near the Southern Cross", image: "image55.webp" }, | |
| { id: 56, name: "Norma", description: "The Level, a carpenter's square used for measuring right angles", image: "image56.webp" }, | |
| { id: 57, name: "Octans", description: "The Octant, a measuring instrument containing the south celestial pole", image: "image57.webp" }, | |
| { id: 58, name: "Ophiuchus", description: "The Serpent-Bearer, representing the healer Asclepius holding a serpent", image: "image58.webp" }, | |
| { id: 59, name: "Orion", description: "The Hunter with his distinctive belt of three stars", image: "image59.webp" }, | |
| { id: 60, name: "Pavo", description: "The Peacock, a southern constellation representing the beautiful bird", image: "image60.webp" }, | |
| { id: 61, name: "Pegasus", description: "The Winged Horse that sprang from Medusa's blood", image: "image61.webp" }, | |
| { id: 62, name: "Perseus", description: "The Greek Hero who rescued Andromeda from Cetus", image: "image62.webp" }, | |
| { id: 63, name: "Phoenix", description: "The Firebird that rises from its own ashes", image: "image63.webp" }, | |
| { id: 64, name: "Pictor", description: "The Painter's Easel, a modern constellation representing an artist's tool", image: "image64.webp" }, | |
| { id: 65, name: "Pisces", description: "The Fishes, representing Venus and Cupid transformed to escape Typhon", image: "image65.webp" }, | |
| { id: 66, name: "Piscis Austrinus", description: "The Southern Fish, drinking the water poured by Aquarius", image: "image66.webp" }, | |
| { id: 67, name: "Puppis", description: "The Stern of the ship Argo Navis from Greek mythology", image: "image67.webp" }, | |
| { id: 68, name: "Pyxis", description: "The Compass of the ship Argo Navis, a navigational instrument", image: "image68.webp" }, | |
| { id: 69, name: "Reticulum", description: "The Reticle, a small net-like pattern used in telescope eyepieces", image: "image69.webp" }, | |
| { id: 70, name: "Sagitta", description: "The Arrow shot by Hercules or used by Apollo to slay the Cyclops", image: "image70.webp" }, | |
| { id: 71, name: "Sagittarius", description: "The Archer, a centaur with a bow pointed at Scorpius", image: "image71.webp" }, | |
| { id: 72, name: "Scorpius", description: "The Scorpion that killed Orion in Greek mythology", image: "image72.webp" }, | |
| { id: 73, name: "Sculptor", description: "The Sculptor, representing an artist's studio with tools", image: "image73.webp" }, | |
| { id: 74, name: "Scutum", description: "The Shield, created to honor King John Sobieski of Poland", image: "image74.webp" }, | |
| { id: 75, name: "Serpens", description: "The Serpent, the only constellation split into two parts (Caput and Cauda)", image: "image75.webp" }, | |
| { id: 76, name: "Sextans", description: "The Sextant, a navigational instrument used by astronomers", image: "image76.webp" }, | |
| { id: 77, name: "Taurus", description: "The Bull, representing Zeus disguised to abduct Europa", image: "image77.webp" }, | |
| { id: 78, name: "Telescopium", description: "The Telescope, honoring the invention that revolutionized astronomy", image: "image78.webp" }, | |
| { id: 79, name: "Triangulum", description: "The Triangle, one of the smallest but oldest recognized constellations", image: "image79.webp" }, | |
| { id: 80, name: "Triangulum Australe", description: "The Southern Triangle, a small but distinctive southern constellation", image: "image80.webp" }, | |
| { id: 81, name: "Tucana", description: "The Toucan, home to the Small Magellanic Cloud galaxy", image: "image81.webp" }, | |
| { id: 82, name: "Ursa Major", description: "The Big Bear, containing the famous Big Dipper asterism", image: "image82.webp" }, | |
| { id: 83, name: "Ursa Minor", description: "The Small Bear, containing Polaris, the North Star", image: "image83.webp" }, | |
| { id: 84, name: "Vela", description: "The Sails of the ship Argo Navis, containing several bright stars", image: "image84.webp" }, | |
| { id: 85, name: "Virgo", description: "The Young Maiden, the second largest constellation containing bright star Spica", image: "image85.webp" }, | |
| { id: 86, name: "Volans", description: "The Flying Fish, a small southern constellation", image: "image86.webp" }, | |
| { id: 87, name: "Vulpecula", description: "The Little Fox, home to the famous Dumbbell Nebula", image: "image87.webp" } | |
| ]; | |
| // zodiac + hemisphere classification (by IAU quadrant of constellation center) | |
| const ZODIAC = new Set([3, 6, 11, 15, 37, 45, 48, 65, 71, 72, 77, 85]); | |
| const NORTHERN = new Set([0, 4, 7, 8, 10, 12, 14, 17, 19, 24, 26, 30, 31, 33, 34, 39, 44, 46, 50, 51, 58, 59, 61, 62, 70, 75, 79, 82, 83, 87]); | |
| function typeOf(c) { | |
| return ZODIAC.has(c.id) ? 'zodiac' : NORTHERN.has(c.id) ? 'northern' : 'southern'; | |
| } | |
| function typeLabel(c) { | |
| const t = typeOf(c); | |
| return t === 'zodiac' ? 'Zodiac' : t === 'northern' ? 'Northern Sky' : 'Southern Sky'; | |
| } | |
| let currentView = 'grid'; | |
| let currentFilter = 'all'; | |
| let currentSearch = ''; | |
| let filteredData = [...constellationData]; | |
| const searchInput = document.getElementById('searchInput'); | |
| const gridView = document.getElementById('gridView'); | |
| const listView = document.getElementById('listView'); | |
| const noResults = document.getElementById('noResults'); | |
| const filteredCount = document.getElementById('filteredCount'); | |
| const gridBtn = document.getElementById('gridBtn'); | |
| const listBtn = document.getElementById('listBtn'); | |
| function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } | |
| function highlight(text) { | |
| if (!currentSearch) return text; | |
| return text.replace(new RegExp(escapeRegex(currentSearch), 'gi'), m => `<mark>${m}</mark>`); | |
| } | |
| function createConstellationCard(c) { | |
| return ` | |
| <div class="db-card" data-constellation="${c.id}"> | |
| <div class="db-card-img"> | |
| <img src="/static/images/${c.image}" alt="${c.name}" loading="lazy" /> | |
| </div> | |
| <div class="db-card-body"> | |
| <h3>${highlight(c.name)}</h3> | |
| <p>${highlight(c.description)}</p> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| function createConstellationListItem(c) { | |
| return ` | |
| <div class="db-row" data-constellation="${c.id}"> | |
| <div class="db-row-img"> | |
| <img src="/static/images/${c.image}" alt="${c.name}" loading="lazy" /> | |
| </div> | |
| <div> | |
| <h3>${highlight(c.name)}</h3> | |
| <p>${highlight(c.description)}</p> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| function renderConstellations() { | |
| if (filteredData.length === 0) { | |
| gridView.style.display = 'none'; | |
| listView.style.display = 'none'; | |
| noResults.style.display = 'block'; | |
| } else { | |
| noResults.style.display = 'none'; | |
| if (currentView === 'grid') { | |
| gridView.style.display = 'grid'; | |
| listView.style.display = 'none'; | |
| gridView.innerHTML = filteredData.map(createConstellationCard).join(''); | |
| } else { | |
| gridView.style.display = 'none'; | |
| listView.style.display = 'flex'; | |
| listView.innerHTML = filteredData.map(createConstellationListItem).join(''); | |
| } | |
| } | |
| filteredCount.textContent = filteredData.length; | |
| } | |
| function applyFilters() { | |
| const term = currentSearch.toLowerCase(); | |
| filteredData = constellationData.filter(c => { | |
| const matchesSearch = !term || | |
| c.name.toLowerCase().includes(term) || | |
| c.description.toLowerCase().includes(term); | |
| const matchesFilter = currentFilter === 'all' || typeOf(c) === currentFilter; | |
| return matchesSearch && matchesFilter; | |
| }); | |
| renderConstellations(); | |
| } | |
| searchInput.addEventListener('input', (e) => { | |
| currentSearch = e.target.value.trim(); | |
| applyFilters(); | |
| }); | |
| document.querySelectorAll('.chip').forEach(chip => { | |
| chip.addEventListener('click', () => { | |
| document.querySelectorAll('.chip').forEach(c => c.classList.remove('active')); | |
| chip.classList.add('active'); | |
| currentFilter = chip.dataset.filter; | |
| applyFilters(); | |
| }); | |
| }); | |
| // ── detail modal ── | |
| const modalBackdrop = document.getElementById('modalBackdrop'); | |
| const modalImg = document.getElementById('modalImg'); | |
| const modalName = document.getElementById('modalName'); | |
| const modalDesc = document.getElementById('modalDesc'); | |
| const modalType = document.getElementById('modalType'); | |
| function openModal(c) { | |
| modalImg.src = `/static/images/${c.image}`; | |
| modalImg.alt = c.name; | |
| modalName.textContent = c.name; | |
| modalDesc.textContent = c.description; | |
| modalType.textContent = typeLabel(c); | |
| modalBackdrop.classList.add('open'); | |
| document.body.style.overflow = 'hidden'; | |
| } | |
| function closeModal() { | |
| modalBackdrop.classList.remove('open'); | |
| document.body.style.overflow = ''; | |
| } | |
| document.getElementById('modalClose').addEventListener('click', closeModal); | |
| modalBackdrop.addEventListener('click', (e) => { | |
| if (e.target === modalBackdrop) closeModal(); | |
| }); | |
| function handleCatalogClick(e) { | |
| const el = e.target.closest('[data-constellation]'); | |
| if (!el) return; | |
| const c = constellationData.find(x => x.id == el.dataset.constellation); | |
| if (c) openModal(c); | |
| } | |
| gridView.addEventListener('click', handleCatalogClick); | |
| listView.addEventListener('click', handleCatalogClick); | |
| function setActiveView(view) { | |
| currentView = view; | |
| gridBtn.classList.toggle('active', view === 'grid'); | |
| listBtn.classList.toggle('active', view === 'list'); | |
| renderConstellations(); | |
| } | |
| gridBtn.addEventListener('click', () => setActiveView('grid')); | |
| listBtn.addEventListener('click', () => setActiveView('list')); | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === '/' && !e.ctrlKey && !e.altKey && !e.metaKey && document.activeElement !== searchInput) { | |
| e.preventDefault(); | |
| searchInput.focus(); | |
| } | |
| if (e.key === 'Escape') { | |
| if (modalBackdrop.classList.contains('open')) { | |
| closeModal(); | |
| } else if (document.activeElement === searchInput) { | |
| searchInput.value = ''; | |
| currentSearch = ''; | |
| applyFilters(); | |
| searchInput.blur(); | |
| } | |
| } | |
| }); | |
| renderConstellations(); | |
| </script> | |
| {% endblock %} | |