This commit is contained in:
End 2025-12-21 22:16:21 -07:00
commit 8fc099ab67
No known key found for this signature in database
2 changed files with 266 additions and 0 deletions

Binary file not shown.

266
main.py Normal file
View file

@ -0,0 +1,266 @@
import datetime
from textual.app import App, ComposeResult
from textual.containers import Center, Grid, Vertical
from textual.screen import Screen
from textual.widgets import Button, Footer, Header, Label, Static
class DayScreen(Screen):
CSS = """
DayScreen {
align: center middle;
background: #0a0015;
}
#dialog {
width: 70;
height: auto;
border: heavy #9d4edd;
background: #1a0033;
padding: 3;
align: center middle;
}
#dialog Label {
width: 100%;
text-align: center;
margin-bottom: 1;
color: #e0aaff;
}
#proto-header {
color: #c77dff;
text-style: bold;
margin-bottom: 2;
}
#gift-text {
color: #7b2cbf;
text-style: bold italic;
margin-top: 1;
margin-bottom: 2;
}
#dialog Button {
width: auto;
background: #5a189a;
color: #e0aaff;
border: solid #9d4edd;
}
#dialog Button:hover {
background: #7b2cbf;
border: solid #c77dff;
}
"""
gifts = {
1: "neural uplink initialized",
2: "quantum processor unlocked",
3: "plasma blade module installed",
4: "holographic interface upgrade",
5: "neon trail effects enabled",
6: "cyberdeck access granted",
7: "ghosting protocol learned",
8: "synth wave audio pack",
9: "augmented reality overlay",
10: "encryption key obtained",
11: "memory expansion complete",
12: "stealth mode activated",
13: "biometric scanner upgraded",
14: "ion cannon calibrated",
15: "neural bridge established",
16: "plasma shield generator",
17: "code injection tools",
18: "quantum entanglement link",
19: "void walker ability",
20: "data mining algorithms",
21: "electromagnetic pulse",
22: "chrono distortion field",
23: "full system override",
24: "transcendence achieved",
}
def __init__(self, day: int) -> None:
self.day = day
super().__init__()
def compose(self) -> ComposeResult:
with Vertical(id="dialog"):
yield Label("▲ SYSTEM ACCESS GRANTED ▲", id="proto-header")
yield Label(f"// DAY {str(self.day).zfill(2)} //")
yield Label(
f">>> {self.gifts.get(self.day, 'ERROR: DATA CORRUPTED')}",
id="gift-text",
)
yield Label("*static crackle*")
with Center():
yield Button("[ DISCONNECT ]", id="close")
def on_button_pressed(self, event: Button.Pressed) -> None:
self.dismiss()
event.stop()
class AdventCalendarApp(App):
CSS = """
Screen {
background: #0a0015;
}
Grid {
grid-size: 6 4;
grid-gutter: 1 1;
padding: 2;
}
Grid Button {
width: 100%;
height: 100%;
min-height: 4;
border: solid #5a189a;
background: #240046;
color: #c77dff;
}
Grid Button:hover {
background: #3c096c;
border: solid #9d4edd;
color: #e0aaff;
text-style: bold;
}
Grid Button.opened {
background: #5a189a;
border: solid #c77dff;
text-style: bold;
color: #e0aaff;
}
Grid Button.locked {
background: #10002b;
border: solid #3c096c;
color: #5a189a;
}
#title {
padding: 1;
text-align: center;
color: #e0aaff;
text-style: bold;
background: #10002b;
}
#stats {
dock: bottom;
height: 3;
background: #10002b;
color: #c77dff;
padding: 1;
text-align: center;
border-top: solid #5a189a;
}
Header {
background: #10002b;
color: #c77dff;
}
Footer {
background: #10002b;
}
"""
BINDINGS = [
("d", "toggle_dark", "theme"),
("r", "reset_calendar", "reset"),
("s", "show_stats", "stats"),
("q", "quit", "exit"),
]
START_DATE = datetime.date(datetime.date.today().year, 12, 1)
def __init__(self):
super().__init__()
self.opened_days = set()
def compose(self) -> ComposeResult:
yield Header(show_clock=True)
yield Static("▼ PROTOGEN//ADVENT v2.4 ▼", id="title")
with Grid():
for day in range(1, 25):
button = Button(f"{day:02d}", id=f"day-{day}")
unlock_day = self.START_DATE + datetime.timedelta(days=day - 1)
if datetime.date.today() < unlock_day:
button.add_class("locked")
yield button
yield Static(self.get_stats_text(), id="stats")
yield Footer()
def get_stats_text(self) -> str:
total = 24
opened = len(self.opened_days)
pct = int((opened / total) * 100)
bar_filled = int(pct / 5)
bar = "" * bar_filled + "" * (20 - bar_filled)
return f"[{bar}] {opened}/{total} :: {pct}% COMPLETE"
def update_stats(self) -> None:
stats_widget = self.query_one("#stats", Static)
stats_widget.update(self.get_stats_text())
def on_button_pressed(self, event: Button.Pressed) -> None:
button = event.button
if button.id == "close":
return
day = int(button.id.split("-")[1])
unlock_day = self.START_DATE + datetime.timedelta(days=day - 1)
if datetime.date.today() < unlock_day:
self.notify(
f"⚠ ACCESS DENIED :: UNLOCKS {unlock_day}",
severity="warning",
timeout=3,
)
return None
if not button.has_class("opened"):
button.add_class("opened")
button.remove_class("locked")
self.opened_days.add(day)
self.update_stats()
self.notify(f"✓ DAY {day:02d} ACCESSED", timeout=2)
self.push_screen(DayScreen(day))
def action_toggle_dark(self) -> None:
self.theme = (
"textual-dark" if self.theme == "textual-light" else "textual-light"
)
self.notify("THEME SHIFT", timeout=1)
def action_reset_calendar(self) -> None:
for day in range(1, 25):
button = self.query_one(f"#day-{day}", Button)
if button.has_class("opened"):
button.remove_class("opened")
self.opened_days.clear()
self.update_stats()
self.notify("⟲ SYSTEM RESET", severity="information")
def action_show_stats(self) -> None:
opened = len(self.opened_days)
remaining = 24 - opened
self.notify(f"OPENED: {opened} :: REMAINING: {remaining}", timeout=4)
def main():
app = AdventCalendarApp()
app.run()
if __name__ == "__main__":
main()