mirror of
https://github.com/onyx-and-iris/lottery-tui.git
synced 2026-02-26 11:09:11 +00:00
Compare commits
No commits in common. "main" and "v0.1.0" have entirely different histories.
@ -1,6 +1,6 @@
|
|||||||
# Lottery TUI
|
# Lottery TUI
|
||||||
|
|
||||||
[](https://pdm-project.org)
|
[](https://pdm.fming.dev)
|
||||||
[](https://github.com/astral-sh/ruff)
|
[](https://github.com/astral-sh/ruff)
|
||||||
[](https://pypi.org/project/lottery-tui)
|
[](https://pypi.org/project/lottery-tui)
|
||||||
[](https://pypi.org/project/lottery-tui)
|
[](https://pypi.org/project/lottery-tui)
|
||||||
@ -25,7 +25,7 @@ uv tool install lottery-tui
|
|||||||
*with pipx*
|
*with pipx*
|
||||||
|
|
||||||
```console
|
```console
|
||||||
pipx install lottery-tui
|
pipx install lotter-tui
|
||||||
```
|
```
|
||||||
|
|
||||||
The TUI should now be discoverable as lottery-tui.
|
The TUI should now be discoverable as lottery-tui.
|
||||||
|
|||||||
BIN
img/tui.png
BIN
img/tui.png
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 18 KiB |
43
pdm.lock
generated
43
pdm.lock
generated
@ -5,23 +5,11 @@
|
|||||||
groups = ["default"]
|
groups = ["default"]
|
||||||
strategy = ["inherit_metadata"]
|
strategy = ["inherit_metadata"]
|
||||||
lock_version = "4.5.0"
|
lock_version = "4.5.0"
|
||||||
content_hash = "sha256:6cd4ed6668a18d93170023df0e7cf183ac36d04df220f4dcb4c091eb6623b65f"
|
content_hash = "sha256:842afa14523f463c1a73e53c7aeb6d697673d95a2db9adbf935807b1fe5d021a"
|
||||||
|
|
||||||
[[metadata.targets]]
|
[[metadata.targets]]
|
||||||
requires_python = "==3.13.*"
|
requires_python = "==3.13.*"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "colorama"
|
|
||||||
version = "0.4.6"
|
|
||||||
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
||||||
summary = "Cross-platform colored terminal text."
|
|
||||||
groups = ["default"]
|
|
||||||
marker = "sys_platform == \"win32\" and python_version == \"3.13\""
|
|
||||||
files = [
|
|
||||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
|
||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linkify-it-py"
|
name = "linkify-it-py"
|
||||||
version = "2.0.3"
|
version = "2.0.3"
|
||||||
@ -37,23 +25,6 @@ files = [
|
|||||||
{file = "linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79"},
|
{file = "linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "loguru"
|
|
||||||
version = "0.7.3"
|
|
||||||
requires_python = "<4.0,>=3.5"
|
|
||||||
summary = "Python logging made (stupidly) simple"
|
|
||||||
groups = ["default"]
|
|
||||||
marker = "python_version == \"3.13\""
|
|
||||||
dependencies = [
|
|
||||||
"aiocontextvars>=0.2.0; python_version < \"3.7\"",
|
|
||||||
"colorama>=0.3.4; sys_platform == \"win32\"",
|
|
||||||
"win32-setctime>=1.0.0; sys_platform == \"win32\"",
|
|
||||||
]
|
|
||||||
files = [
|
|
||||||
{file = "loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c"},
|
|
||||||
{file = "loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown-it-py"
|
name = "markdown-it-py"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
@ -196,15 +167,3 @@ files = [
|
|||||||
{file = "uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a"},
|
{file = "uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a"},
|
||||||
{file = "uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5"},
|
{file = "uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "win32-setctime"
|
|
||||||
version = "1.2.0"
|
|
||||||
requires_python = ">=3.5"
|
|
||||||
summary = "A small Python utility to set file creation time on Windows"
|
|
||||||
groups = ["default"]
|
|
||||||
marker = "sys_platform == \"win32\" and python_version == \"3.13\""
|
|
||||||
files = [
|
|
||||||
{file = "win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390"},
|
|
||||||
{file = "win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0"},
|
|
||||||
]
|
|
||||||
|
|||||||
@ -1,33 +1,15 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "lottery-tui"
|
name = "lottery-tui"
|
||||||
version = "1.0.1"
|
version = "0.1.0"
|
||||||
description = "A terminal user interface for lottery games."
|
description = "A terminal user interface for lottery games."
|
||||||
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
|
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
|
||||||
dependencies = ["textual>=8.0.0", "loguru>=0.7.3"]
|
dependencies = ["textual>=8.0.0"]
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { text = "MIT" }
|
license = { text = "MIT" }
|
||||||
classifiers = [
|
|
||||||
"Development Status :: 5 - Production/Stable",
|
|
||||||
"Programming Language :: Python",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: 3.12",
|
|
||||||
"Programming Language :: Python :: 3.13",
|
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
lottery-tui = "lottery_tui.tui:main"
|
lottery-tui = "lottery_tui.tui:main"
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["pdm-backend"]
|
|
||||||
build-backend = "pdm.backend"
|
|
||||||
|
|
||||||
[tool.pdm]
|
[tool.pdm]
|
||||||
distribution = true
|
distribution = true
|
||||||
|
|
||||||
[tool.pdm.build]
|
|
||||||
package-dir = "src"
|
|
||||||
includes = ["src/**/*", "README.md", "LICENSE"]
|
|
||||||
|
|||||||
@ -1,27 +1,15 @@
|
|||||||
import random
|
import random
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from dataclasses import dataclass
|
from typing import NamedTuple
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
class Result(NamedTuple):
|
||||||
class Result:
|
"""A named tuple to hold the results of a lottery draw."""
|
||||||
"""A dataclass to hold the results of a lottery draw with auto-sorted numbers."""
|
|
||||||
|
|
||||||
kind: str
|
kind: str
|
||||||
numbers: list[int]
|
numbers: list[int]
|
||||||
bonus: list[int] | None
|
bonus: list[int] | None
|
||||||
|
|
||||||
def __post_init__(self):
|
|
||||||
"""Sort the numbers after initialization.
|
|
||||||
|
|
||||||
We use super().__setattr__ to bypass the frozen nature of the dataclass for sorting.
|
|
||||||
"""
|
|
||||||
super().__setattr__('numbers', sorted(self.numbers))
|
|
||||||
if self.bonus:
|
|
||||||
super().__setattr__('bonus', sorted(self.bonus))
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
"""Return a string representation of the lottery result."""
|
"""Return a string representation of the lottery result."""
|
||||||
out = f'Numbers: {", ".join(str(n) for n in self.numbers)}'
|
out = f'Numbers: {", ".join(str(n) for n in self.numbers)}'
|
||||||
@ -29,7 +17,7 @@ class Result:
|
|||||||
match self.kind:
|
match self.kind:
|
||||||
case 'EuroMillions':
|
case 'EuroMillions':
|
||||||
bonus_name = 'Lucky Stars'
|
bonus_name = 'Lucky Stars'
|
||||||
case 'SetForLife':
|
case 'Set For Life':
|
||||||
bonus_name = 'Life Ball'
|
bonus_name = 'Life Ball'
|
||||||
case 'Thunderball':
|
case 'Thunderball':
|
||||||
bonus_name = 'Thunderball'
|
bonus_name = 'Thunderball'
|
||||||
@ -52,24 +40,24 @@ class Lottery(ABC):
|
|||||||
"""An abstract base class for different types of lotteries."""
|
"""An abstract base class for different types of lotteries."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def draw(self) -> Result:
|
def draw(self):
|
||||||
"""Perform a lottery draw."""
|
"""Perform a lottery draw."""
|
||||||
|
|
||||||
|
|
||||||
@register_lottery
|
@register_lottery
|
||||||
class Lotto(Lottery):
|
class UKlotto(Lottery):
|
||||||
"""A class representing the Lotto lottery.
|
"""A class representing the UK Lotto lottery.
|
||||||
|
|
||||||
Lotto draws 6 numbers from a pool of 1 to 59, without replacement.
|
Uk Lotto draws 6 numbers from a pool of 1 to 59, without replacement.
|
||||||
There is no bonus number in Lotto.
|
There is no bonus number in UK Lotto.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
POSSIBLE_NUMBERS = range(1, 60)
|
POSSIBLE_NUMBERS = range(1, 60)
|
||||||
|
|
||||||
def draw(self) -> Result:
|
def draw(self):
|
||||||
"""Perform a Lotto draw."""
|
"""Perform a UK Lotto draw."""
|
||||||
result = random.sample(Lotto.POSSIBLE_NUMBERS, 6)
|
result = random.sample(UKlotto.POSSIBLE_NUMBERS, 6)
|
||||||
return Result(kind=type(self).__name__, numbers=result, bonus=None)
|
return Result(kind='UK Lotto', numbers=result, bonus=None)
|
||||||
|
|
||||||
|
|
||||||
@register_lottery
|
@register_lottery
|
||||||
@ -83,11 +71,11 @@ class EuroMillions(Lottery):
|
|||||||
POSSIBLE_NUMBERS = range(1, 51)
|
POSSIBLE_NUMBERS = range(1, 51)
|
||||||
POSSIBLE_BONUS_NUMBERS = range(1, 13)
|
POSSIBLE_BONUS_NUMBERS = range(1, 13)
|
||||||
|
|
||||||
def draw(self) -> Result:
|
def draw(self):
|
||||||
"""Perform a EuroMillions draw."""
|
"""Perform a EuroMillions draw."""
|
||||||
numbers = random.sample(EuroMillions.POSSIBLE_NUMBERS, 5)
|
numbers = random.sample(EuroMillions.POSSIBLE_NUMBERS, 5)
|
||||||
bonus = random.sample(EuroMillions.POSSIBLE_BONUS_NUMBERS, 2)
|
bonus = random.sample(EuroMillions.POSSIBLE_BONUS_NUMBERS, 2)
|
||||||
return Result(kind=type(self).__name__, numbers=numbers, bonus=bonus)
|
return Result(kind='EuroMillions', numbers=numbers, bonus=bonus)
|
||||||
|
|
||||||
|
|
||||||
@register_lottery
|
@register_lottery
|
||||||
@ -95,16 +83,16 @@ class SetForLife(Lottery):
|
|||||||
"""A class representing the Set For Life lottery.
|
"""A class representing the Set For Life lottery.
|
||||||
|
|
||||||
Set For Life draws 5 numbers from a pool of 1 to 39, without replacement,
|
Set For Life draws 5 numbers from a pool of 1 to 39, without replacement,
|
||||||
and 1 "Life Ball" number from a separate pool of 1 to 10.
|
and 1 "Life Ball" number from a separate pool of 1 to 10, also without replacement.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
POSSIBLE_NUMBERS = range(1, 40)
|
POSSIBLE_NUMBERS = range(1, 40)
|
||||||
|
|
||||||
def draw(self) -> Result:
|
def draw(self):
|
||||||
"""Perform a Set For Life draw."""
|
"""Perform a Set For Life draw."""
|
||||||
numbers = random.sample(SetForLife.POSSIBLE_NUMBERS, 5)
|
numbers = random.sample(SetForLife.POSSIBLE_NUMBERS, 5)
|
||||||
life_ball = [random.randint(1, 10)]
|
life_ball = [random.randint(1, 10)]
|
||||||
return Result(kind=type(self).__name__, numbers=numbers, bonus=life_ball)
|
return Result(kind='Set For Life', numbers=numbers, bonus=life_ball)
|
||||||
|
|
||||||
|
|
||||||
@register_lottery
|
@register_lottery
|
||||||
@ -112,23 +100,21 @@ class Thunderball(Lottery):
|
|||||||
"""A class representing the Thunderball lottery.
|
"""A class representing the Thunderball lottery.
|
||||||
|
|
||||||
Thunderball draws 5 numbers from a pool of 1 to 39, without replacement,
|
Thunderball draws 5 numbers from a pool of 1 to 39, without replacement,
|
||||||
and 1 "Thunderball" number from a separate pool of 1 to 14.
|
and 1 "Thunderball" number from a separate pool of 1 to 14, also without replacement.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
POSSIBLE_NUMBERS = range(1, 40)
|
POSSIBLE_NUMBERS = range(1, 40) # Thunderball numbers range from 1 to 39
|
||||||
|
|
||||||
def draw(self) -> Result:
|
def draw(self):
|
||||||
"""Perform a Thunderball draw."""
|
"""Perform a Thunderball draw."""
|
||||||
numbers = random.sample(Thunderball.POSSIBLE_NUMBERS, 5)
|
numbers = random.sample(Thunderball.POSSIBLE_NUMBERS, 5)
|
||||||
thunderball = [random.randint(1, 14)]
|
thunderball = [random.randint(1, 14)]
|
||||||
return Result(kind=type(self).__name__, numbers=numbers, bonus=thunderball)
|
return Result(kind='Thunderball', numbers=numbers, bonus=thunderball)
|
||||||
|
|
||||||
|
|
||||||
def request_lottery_obj(lottery_name: str) -> Lottery:
|
def request_lottery_obj(lottery_name: str) -> Lottery:
|
||||||
"""Return a lottery object based on the provided lottery name."""
|
"""Return a lottery object based on the provided lottery name."""
|
||||||
lottery_cls = registry.get(lottery_name.lower())
|
lottery_cls = registry.get(lottery_name.lower())
|
||||||
if lottery_cls is None:
|
if lottery_cls is None:
|
||||||
ERR_MSG = f"Lottery '{lottery_name}' not found. Available lotteries: {', '.join(registry.keys())}"
|
raise ValueError(f"Lottery '{lottery_name}' not found.")
|
||||||
logger.error(ERR_MSG)
|
|
||||||
raise ValueError(ERR_MSG)
|
|
||||||
return lottery_cls()
|
return lottery_cls()
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
from typing import NoReturn
|
|
||||||
|
|
||||||
from textual.app import App, ComposeResult
|
from textual.app import App, ComposeResult
|
||||||
from textual.containers import Container
|
from textual.containers import Container
|
||||||
from textual.events import Key
|
|
||||||
from textual.types import SelectType
|
|
||||||
from textual.widgets import Button, Label, Select, Static
|
from textual.widgets import Button, Label, Select, Static
|
||||||
|
|
||||||
from .lottery import request_lottery_obj
|
from .lottery import request_lottery_obj
|
||||||
@ -21,13 +17,11 @@ class LotteryTUI(App):
|
|||||||
Static('Pick a lottery to play:', id='instructions'),
|
Static('Pick a lottery to play:', id='instructions'),
|
||||||
Select(
|
Select(
|
||||||
options=[
|
options=[
|
||||||
('Lotto', 'lotto'),
|
('UK Lotto', 'uklotto'),
|
||||||
('EuroMillions', 'euromillions'),
|
('EuroMillions', 'euromillions'),
|
||||||
('Set For Life', 'setforlife'),
|
('Set For Life', 'setforlife'),
|
||||||
('Thunderball', 'thunderball'),
|
('Thunderball', 'thunderball'),
|
||||||
],
|
],
|
||||||
value='lotto',
|
|
||||||
allow_blank=False,
|
|
||||||
id='lottery-select',
|
id='lottery-select',
|
||||||
),
|
),
|
||||||
Button('Draw', id='draw-button'),
|
Button('Draw', id='draw-button'),
|
||||||
@ -35,29 +29,23 @@ class LotteryTUI(App):
|
|||||||
id='main-container',
|
id='main-container',
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_key(self, event: Key) -> NoReturn:
|
def on_key(self, event):
|
||||||
"""Handle key events."""
|
"""Handle key events."""
|
||||||
if event.key == 'q':
|
if event.key == 'q':
|
||||||
self.exit()
|
self.exit()
|
||||||
|
|
||||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
def on_button_pressed(self, event):
|
||||||
"""Handle button press events."""
|
"""Handle button press events."""
|
||||||
if event.button.id == 'draw-button':
|
if event.button.id == 'draw-button':
|
||||||
self._draw_button_handler()
|
selected_lottery = self.query_one('#lottery-select').value
|
||||||
|
try:
|
||||||
def _draw_button_handler(self) -> None:
|
lottery_obj = request_lottery_obj(selected_lottery)
|
||||||
"""Handle the draw button press."""
|
|
||||||
lottery_obj = request_lottery_obj(self._read_lottery_selection())
|
|
||||||
result = lottery_obj.draw()
|
result = lottery_obj.draw()
|
||||||
self._update_result_label(str(result))
|
self.query_one('#result-label').update(f'Result: {result}')
|
||||||
|
except ValueError as e:
|
||||||
|
self.query_one('#result-label').update(str(e))
|
||||||
|
|
||||||
def _read_lottery_selection(self) -> SelectType:
|
self.query_one('#result-label').update(str(result))
|
||||||
"""Read the selected lottery from the dropdown."""
|
|
||||||
return self.query_one('#lottery-select').value
|
|
||||||
|
|
||||||
def _update_result_label(self, message: str) -> None:
|
|
||||||
"""Update the result label with a new message."""
|
|
||||||
self.query_one('#result-label').update(message)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@ -61,7 +61,9 @@ LotteryTUI {
|
|||||||
text-style: bold italic;
|
text-style: bold italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Button styling */
|
/* Additional styling for potential future widgets */
|
||||||
|
|
||||||
|
/* Button styling for lottery buttons */
|
||||||
Button {
|
Button {
|
||||||
background: #ffd700;
|
background: #ffd700;
|
||||||
border: round #e6c200;
|
border: round #e6c200;
|
||||||
@ -84,6 +86,22 @@ Button:focus {
|
|||||||
color: #1a1a2e;
|
color: #1a1a2e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Input styling for lottery number inputs */
|
||||||
|
Input {
|
||||||
|
background: #2d3748;
|
||||||
|
border: round #4a5568;
|
||||||
|
color: #ffd700;
|
||||||
|
height: 3;
|
||||||
|
margin: 1;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Input:focus {
|
||||||
|
background: #374151;
|
||||||
|
border: round #ffd700;
|
||||||
|
color: #ffed4a;
|
||||||
|
}
|
||||||
|
|
||||||
/* Label styling */
|
/* Label styling */
|
||||||
Label {
|
Label {
|
||||||
color: #e2e8f0;
|
color: #e2e8f0;
|
||||||
@ -114,7 +132,7 @@ Label {
|
|||||||
color: #1a1a2e;
|
color: #1a1a2e;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Results Label Styling */
|
/* Results Label Styling - Enhanced Appearance */
|
||||||
#result-label {
|
#result-label {
|
||||||
background: #1a365d;
|
background: #1a365d;
|
||||||
border: thick #ffd700;
|
border: thick #ffd700;
|
||||||
@ -127,3 +145,132 @@ Label {
|
|||||||
content-align: left middle;
|
content-align: left middle;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Container for lottery number display */
|
||||||
|
.lottery-numbers {
|
||||||
|
align: center middle;
|
||||||
|
background: #2d3748;
|
||||||
|
border: round #ffd700;
|
||||||
|
height: auto;
|
||||||
|
margin: 2;
|
||||||
|
padding: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual lottery number balls */
|
||||||
|
.lottery-ball {
|
||||||
|
background: #ffd700;
|
||||||
|
border: round #e6c200;
|
||||||
|
color: #1a1a2e;
|
||||||
|
height: 3;
|
||||||
|
margin: 0 1;
|
||||||
|
text-align: center;
|
||||||
|
text-style: bold;
|
||||||
|
width: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lottery-ball:hover {
|
||||||
|
background: #ffed4a;
|
||||||
|
color: #16213e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Results display */
|
||||||
|
.results {
|
||||||
|
background: #1a202c;
|
||||||
|
border: round #4a5568;
|
||||||
|
color: #e2e8f0;
|
||||||
|
height: auto;
|
||||||
|
margin: 2;
|
||||||
|
padding: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.winning-number {
|
||||||
|
color: #48bb78;
|
||||||
|
text-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.losing-number {
|
||||||
|
color: #f56565;
|
||||||
|
text-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status bar */
|
||||||
|
.status-bar {
|
||||||
|
background: #2d3748;
|
||||||
|
color: #a0aec0;
|
||||||
|
dock: bottom;
|
||||||
|
height: 1;
|
||||||
|
padding: 0 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
.header {
|
||||||
|
background: #ffd700;
|
||||||
|
color: #1a1a2e;
|
||||||
|
dock: top;
|
||||||
|
height: 3;
|
||||||
|
text-align: center;
|
||||||
|
text-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.footer {
|
||||||
|
background: #1a1a2e;
|
||||||
|
color: #a0aec0;
|
||||||
|
dock: bottom;
|
||||||
|
height: 1;
|
||||||
|
text-align: center;
|
||||||
|
text-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar styling */
|
||||||
|
.sidebar {
|
||||||
|
background: #2d3748;
|
||||||
|
border-right: solid #4a5568;
|
||||||
|
dock: left;
|
||||||
|
width: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content area */
|
||||||
|
.content {
|
||||||
|
background: $surface;
|
||||||
|
margin: 1;
|
||||||
|
padding: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error messages */
|
||||||
|
.error {
|
||||||
|
background: #fed7d7;
|
||||||
|
border: round #f56565;
|
||||||
|
color: #c53030;
|
||||||
|
margin: 1;
|
||||||
|
padding: 1;
|
||||||
|
text-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success messages */
|
||||||
|
.success {
|
||||||
|
background: #c6f6d5;
|
||||||
|
border: round #48bb78;
|
||||||
|
color: #22543d;
|
||||||
|
margin: 1;
|
||||||
|
padding: 1;
|
||||||
|
text-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading spinner */
|
||||||
|
.loading {
|
||||||
|
color: #ffd700;
|
||||||
|
text-align: center;
|
||||||
|
text-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prize display */
|
||||||
|
.prize {
|
||||||
|
background: #ffd700;
|
||||||
|
border: round #e6c200;
|
||||||
|
color: #1a1a2e;
|
||||||
|
margin: 1;
|
||||||
|
padding: 2;
|
||||||
|
text-align: center;
|
||||||
|
text-style: bold;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user