diff --git a/compose.yaml b/compose.yaml index 5002b06..fa8a721 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,27 +1,7 @@ services: fantasycron: - image: fantasycron:latest # Use pre-built image + image: fantasycron:latest ports: - "5000:5000" - environment: - - SECRET_KEY=your-secret-key-here - - DATABASE_URL=sqlite:///fantasy_app.db - volumes: - - ./data:/app/data restart: unless-stopped - # Optional PostgreSQL service - # Uncomment to use PostgreSQL instead of SQLite - # postgres: - # image: postgres:13 - # environment: - # POSTGRES_DB: fantasy_app - # POSTGRES_USER: fantasy_user - # POSTGRES_PASSWORD: fantasy_pass - # volumes: - # - postgres_data:/var/lib/postgresql/data - # ports: - # - "5432:5432" - -# volumes: -# postgres_data: diff --git a/config.py b/config.py index d31dafc..3c99977 100644 --- a/config.py +++ b/config.py @@ -6,9 +6,6 @@ class Config: SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key' - # Database settings - support SQLite, PostgreSQL, MariaDB - DATABASE_URL = os.environ.get('DATABASE_URL') or 'sqlite:///fantasy_app.db' - # API settings SLEEPER_BASE_URL = 'https://api.sleeper.app/v1' ESPN_BASE_URL = 'https://site.api.espn.com/apis/site/v2/sports/football/nfl' diff --git a/static/style.css b/static/style.css index 0ef6386..0e2e167 100644 --- a/static/style.css +++ b/static/style.css @@ -1,24 +1,75 @@ -/* Reset and base styles */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; +.sidebar-link { + display: block; + padding: 12px 16px; + background: var(--bg-secondary); + border-radius: 8px; + color: var(--text-primary); + text-decoration: none; + margin-bottom: 10px; + transition: all 0.2s ease; } -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - line-height: 1.6; - color: #333; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - min-height: 100vh; +.sidebar-link:hover { + background: var(--bg-tertiary); + transform: translateX(5px); } -.container { - max-width: 1200px; - margin: 0 auto; +.about-text { + background: var(--bg-secondary); + border-radius: 8px; padding: 20px; } +.about-text p { + color: var(--text-primary); + line-height: 1.6; + margin-bottom: 12px; +} + +.about-text strong { + color: var(--accent); +} + +.about-text ul { + margin-left: 20px; + margin-bottom: 12px; +} + +.about-text li { + color: var(--text-secondary); + margin-bottom: 8px; + line-height: 1.5; +} + +.about-text .cron-note { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 12px; + color: var(--accent); + margin-top: 15px; + padding-top: 15px; + border-top: 1px solid var(--border-light); + font-style: italic; +} + +/* Sidebar Overlay */ +.sidebar-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 999; + opacity: 0; + visibility: hidden; + transition: opacity 0.3s ease, visibility 0.3s ease; +} + +.sidebar-overlay.active { + opacity: 1; + visibility: visible; +} + /* Brand styling */ .brand { margin-bottom: 20px; @@ -26,7 +77,7 @@ body { .app-name { font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; - color: #2c3e50; + color: var(--text-primary); margin-bottom: 8px; font-size: 2.2rem; font-weight: 600; @@ -35,7 +86,7 @@ body { .tagline { font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; - color: #667eea; + color: var(--accent); font-size: 0.9rem; font-weight: 500; opacity: 0.8; @@ -44,10 +95,10 @@ body { /* Welcome page styles */ .welcome-container { text-align: center; - background: white; + background: var(--bg-primary); padding: 40px; border-radius: 12px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); + box-shadow: var(--shadow-lg); margin-top: 100px; max-width: 400px; margin-left: auto; @@ -59,41 +110,25 @@ body { flex-direction: column; gap: 15px; margin: 30px 0; - - & input { - padding: 15px; - border: 2px solid #e1e8ed; - border-radius: 8px; - font-size: 16px; - transition: border-color 0.3s; - - &:focus { - outline: none; - border-color: #667eea; - } - } - - & button { - background: linear-gradient(45deg, #667eea, #764ba2); - color: white; - padding: 15px 20px; - border: none; - border-radius: 8px; - font-size: 16px; - cursor: pointer; - transition: transform 0.2s; - text-decoration: none; - display: inline-block; - text-align: center; - - &:hover { - transform: translateY(-2px); - } - } } -.btn { - background: linear-gradient(45deg, #667eea, #764ba2); +.username-form input { + padding: 15px; + border: 2px solid var(--border-primary); + border-radius: 8px; + font-size: 16px; + transition: border-color 0.3s; + background: var(--bg-primary); + color: var(--text-primary); +} + +.username-form input:focus { + outline: none; + border-color: var(--accent); +} + +.username-form button { + background: linear-gradient(45deg, var(--header-gradient-start), var(--header-gradient-end)); color: white; padding: 15px 20px; border: none; @@ -104,41 +139,59 @@ body { text-decoration: none; display: inline-block; text-align: center; - - &:hover { - transform: translateY(-2px); - } +} + +.username-form button:hover { + transform: translateY(-2px); +} + +.btn { + background: linear-gradient(45deg, var(--header-gradient-start), var(--header-gradient-end)); + color: white; + padding: 15px 20px; + border: none; + border-radius: 8px; + font-size: 16px; + cursor: pointer; + transition: transform 0.2s; + text-decoration: none; + display: inline-block; + text-align: center; +} + +.btn:hover { + transform: translateY(-2px); } .example { - color: #666; + color: var(--text-muted); font-size: 14px; - - & code { - background: #f8f9fa; - padding: 2px 6px; - border-radius: 4px; - font-family: monospace; - } +} + +.example code { + background: var(--bg-secondary); + padding: 2px 6px; + border-radius: 4px; + font-family: monospace; } /* Dashboard header */ .dashboard-header { - background: white; + background: var(--bg-primary); padding: 20px; border-radius: 12px; margin-bottom: 20px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); + box-shadow: var(--shadow-sm); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px; - - & h1 { - color: #2c3e50; - font-size: 1.8rem; - } +} + +.dashboard-header h1 { + color: var(--text-primary); + font-size: 1.8rem; } .week-nav { @@ -148,31 +201,31 @@ body { } .week-btn { - background: #f8f9fa; - color: #495057; + background: var(--bg-secondary); + color: var(--text-secondary); padding: 8px 16px; border-radius: 6px; text-decoration: none; transition: background 0.2s; - - &:hover { - background: #e9ecef; - } +} + +.week-btn:hover { + background: var(--bg-tertiary); } .current-week { font-weight: bold; - color: #667eea; + color: var(--accent); font-size: 1.1rem; } /* League scores - compact at top */ .scores-summary { - background: white; + background: var(--bg-primary); border-radius: 12px; padding: 15px; margin-bottom: 30px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); + box-shadow: var(--shadow-sm); } .score-row { @@ -180,11 +233,11 @@ body { justify-content: space-between; align-items: center; padding: 8px 0; - border-bottom: 1px solid #f1f3f4; - - &:last-child { - border-bottom: none; - } + border-bottom: 1px solid var(--border-light); +} + +.score-row:last-child { + border-bottom: none; } .league-info { @@ -192,16 +245,16 @@ body { align-items: center; gap: 8px; min-width: 140px; - - & .league-dot { - width: 10px; - height: 10px; - } +} + +.league-info .league-dot { + width: 10px; + height: 10px; } .league-name { font-weight: 600; - color: #2c3e50; + color: var(--text-primary); font-size: 14px; } @@ -223,7 +276,7 @@ body { .user-name, .opp-name { font-weight: 500; - color: #495057; + color: var(--text-secondary); min-width: 80px; } @@ -233,13 +286,13 @@ body { .score { font-weight: bold; - color: #667eea; + color: var(--accent); min-width: 30px; text-align: center; } .vs-compact { - color: #666; + color: var(--text-muted); font-size: 11px; font-weight: 500; } @@ -247,13 +300,13 @@ body { /* Schedule section - main focus */ .schedule-section { flex: 1; - - & h2 { - color: white; - margin-bottom: 25px; - font-size: 1.8rem; - text-align: center; - } +} + +.schedule-section h2 { + color: var(--text-light); + margin-bottom: 25px; + font-size: 1.8rem; + text-align: center; } .calendar-rows { @@ -263,23 +316,23 @@ body { /* Day row styling */ .day-row { - background: white; + background: var(--bg-primary); border-radius: 16px; margin-bottom: 20px; - box-shadow: 0 6px 24px rgba(0, 0, 0, 0.1); + box-shadow: var(--shadow-md); overflow: hidden; } .day-header { - background: linear-gradient(45deg, #667eea, #764ba2); + background: linear-gradient(45deg, var(--header-gradient-start), var(--header-gradient-end)); color: white; padding: 15px 20px; - - & h3 { - margin: 0; - font-size: 1.2rem; - font-weight: 600; - } +} + +.day-header h3 { + margin: 0; + font-size: 1.2rem; + font-weight: 600; } .day-games { @@ -291,16 +344,16 @@ body { /* Game card styling */ .game-card { - background: #f8f9fa; + background: var(--bg-secondary); border-radius: 12px; padding: 15px; - border: 1px solid #e9ecef; + border: 1px solid var(--border-secondary); transition: all 0.2s ease; - - &:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - } +} + +.game-card:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-sm); } .game-info { @@ -309,7 +362,7 @@ body { .game-time { font-size: 12px; - color: #667eea; + color: var(--accent); margin-bottom: 8px; font-weight: 600; text-align: center; @@ -325,11 +378,11 @@ body { } .away-team, .home-team { - color: #2c3e50; + color: var(--text-primary); } .at { - color: #666; + color: var(--text-muted); font-size: 12px; } @@ -346,14 +399,14 @@ body { flex-wrap: wrap; gap: 4px; padding: 6px; - background: rgba(255, 255, 255, 0.6); + background: var(--overlay-medium); border-radius: 8px; min-height: 28px; - - & .player-pill { - padding: 3px 6px; - font-size: 10px; - } +} + +.league-player-group .player-pill { + padding: 3px 6px; + font-size: 10px; } /* Player pills */ @@ -364,63 +417,63 @@ body { padding: 4px 8px; border-radius: 16px; font-size: 11px; - border: 2px solid #dee2e6; - background: white; + border: 2px solid var(--border-secondary); + background: var(--bg-primary); font-weight: 500; transition: all 0.2s ease; - - &:hover { - transform: scale(1.05); - } - - & .pos { - font-weight: bold; - font-size: 9px; - opacity: 0.8; - } - - & .name { - font-weight: normal; - color: black; - } - - & .league-dot { - display: none; - } - - /* Position colors */ - &.qb { - border-color: rgb(252, 43, 109); - background: rgba(252, 43, 109, 0.1); - color: rgb(252, 43, 109); - } - - &.rb { - border-color: rgb(0, 206, 184); - background: rgba(0, 206, 184, 0.1); - color: rgb(0, 206, 184); - } - - &.wr { - border-color: rgb(0, 186, 255); - background: rgba(0, 186, 255, 0.1); - color: rgb(0, 186, 255); - } - - &.te { - border-color: rgb(255, 174, 88); - background: rgba(255, 174, 88, 0.1); - color: rgb(255, 174, 88); - } +} + +.player-pill:hover { + transform: scale(1.05); +} + +.player-pill .pos { + font-weight: bold; + font-size: 9px; + opacity: 0.8; +} + +.player-pill .name { + font-weight: normal; + color: var(--player-name-color); +} + +.player-pill .league-dot { + display: none; +} + +/* Position colors */ +.player-pill.qb { + border-color: rgb(252, 43, 109); + background: rgba(252, 43, 109, 0.1); + color: rgb(252, 43, 109); +} + +.player-pill.rb { + border-color: rgb(0, 206, 184); + background: rgba(0, 206, 184, 0.1); + color: rgb(0, 206, 184); +} + +.player-pill.wr { + border-color: rgb(0, 186, 255); + background: rgba(0, 186, 255, 0.1); + color: rgb(0, 186, 255); +} + +.player-pill.te { + border-color: rgb(255, 174, 88); + background: rgba(255, 174, 88, 0.1); + color: rgb(255, 174, 88); } .no-games-week { text-align: center; - color: white; + color: var(--text-light); font-style: italic; font-size: 16px; padding: 60px 0; - background: rgba(255, 255, 255, 0.1); + background: var(--overlay-light); border-radius: 12px; margin: 20px 0; } @@ -435,32 +488,32 @@ body { .version { font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 11px; - color: rgba(255, 255, 255, 0.6); + color: var(--footer-text); opacity: 0.8; } /* Error page */ .error-container { text-align: center; - background: white; + background: var(--bg-primary); padding: 40px; border-radius: 12px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); + box-shadow: var(--shadow-lg); margin-top: 100px; max-width: 500px; margin-left: auto; margin-right: auto; - - & h1 { - color: #e74c3c; - margin-bottom: 20px; - } - - & p { - color: #666; - margin-bottom: 30px; - line-height: 1.6; - } +} + +.error-container h1 { + color: var(--error-color); + margin-bottom: 20px; +} + +.error-container p { + color: var(--text-muted); + margin-bottom: 30px; + line-height: 1.6; } /* Mobile responsive styles */ @@ -469,6 +522,24 @@ body { padding: 15px; } + .menu-toggle { + width: 40px; + height: 40px; + } + + .menu-toggle .menu-icon { + font-size: 20px; + } + + .sidebar { + width: 85%; + right: -85%; + } + + .sidebar-content { + padding: 50px 20px 20px; + } + .dashboard-header { flex-direction: column; text-align: center; @@ -502,16 +573,14 @@ body { .day-header { padding: 12px 15px; - - & h3 { - font-size: 1.1rem; - } } - .schedule-section { - & h2 { - font-size: 1.5rem; - } + .day-header h3 { + font-size: 1.1rem; + } + + .schedule-section h2 { + font-size: 1.5rem; } .welcome-container { @@ -527,16 +596,194 @@ body { @media (max-width: 480px) { .username-form { gap: 12px; - - & input, - & button { - padding: 12px; - font-size: 14px; - } + } + + .username-form input, + .username-form button { + padding: 12px; + font-size: 14px; } .week-nav { flex-direction: column; gap: 10px; } +}/* Theme Variables */ +:root { + /* Light theme (default) */ + --bg-gradient-start: #667eea; + --bg-gradient-end: #764ba2; + --bg-primary: white; + --bg-secondary: #f8f9fa; + --bg-tertiary: #e9ecef; + --text-primary: #333; + --text-secondary: #495057; + --text-muted: #666; + --text-light: white; + --player-name-color: #000; + --border-primary: #e1e8ed; + --border-secondary: #dee2e6; + --border-light: #f1f3f4; + --shadow-sm: 0 4px 16px rgba(0, 0, 0, 0.1); + --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.1); + --accent: #667eea; + --header-gradient-start: #667eea; + --header-gradient-end: #764ba2; + --overlay-light: rgba(255, 255, 255, 0.1); + --overlay-medium: rgba(255, 255, 255, 0.6); + --footer-text: rgba(255, 255, 255, 0.6); + --error-color: #e74c3c; + --sidebar-bg: white; + --sidebar-shadow: 0 0 30px rgba(0, 0, 0, 0.2); } + +[data-theme="dark"] { + --bg-gradient-start: #1a1a2e; + --bg-gradient-end: #16213e; + --bg-primary: #1e1e2e; + --bg-secondary: #2a2a3e; + --bg-tertiary: #35354a; + --text-primary: #e0e0e0; + --text-secondary: #b0b0b0; + --text-muted: #888; + --text-light: #e0e0e0; + --player-name-color: #e0e0e0; + --border-primary: #3a3a4e; + --border-secondary: #4a4a5e; + --border-light: #2a2a3e; + --shadow-sm: 0 4px 16px rgba(0, 0, 0, 0.3); + --shadow-md: 0 6px 24px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5); + --accent: #8b7ff5; + --header-gradient-start: #8b7ff5; + --header-gradient-end: #a085e6; + --overlay-light: rgba(0, 0, 0, 0.2); + --overlay-medium: rgba(0, 0, 0, 0.3); + --footer-text: rgba(255, 255, 255, 0.4); + --error-color: #ff6b6b; + --sidebar-bg: #1e1e2e; + --sidebar-shadow: 0 0 30px rgba(0, 0, 0, 0.5); +} + +/* Reset and base styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + line-height: 1.6; + color: var(--text-primary); + background: linear-gradient(135deg, var(--bg-gradient-start) 0%, var(--bg-gradient-end) 100%); + min-height: 100vh; + transition: background 0.3s ease, color 0.3s ease; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; +} + +/* Hamburger Menu Button */ +.menu-toggle { + position: fixed; + top: 20px; + right: 20px; + z-index: 1000; + background: var(--bg-primary); + border: 2px solid var(--border-primary); + border-radius: 8px; + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + box-shadow: var(--shadow-sm); + transition: all 0.3s ease; +} + +.menu-toggle:hover { + transform: scale(1.1); + box-shadow: var(--shadow-md); +} + +.menu-toggle .menu-icon { + font-size: 24px; + color: var(--text-primary); +} + +/* Sidebar */ +.sidebar { + position: fixed; + top: 0; + right: -400px; + width: 400px; + height: 100%; + background: var(--sidebar-bg); + box-shadow: var(--sidebar-shadow); + transition: right 0.3s ease; + z-index: 1001; + overflow-y: auto; +} + +.sidebar.active { + right: 0; +} + +.close-btn { + position: absolute; + top: 15px; + right: 15px; + background: transparent; + border: none; + font-size: 28px; + color: var(--text-primary); + cursor: pointer; + padding: 5px; +} + +.close-btn:hover { + opacity: 0.7; +} + +.sidebar-content { + padding: 60px 30px 30px; +} + +.sidebar-section { + margin-bottom: 35px; +} + +.sidebar-section h3 { + color: var(--accent); + margin-bottom: 15px; + font-size: 1.1rem; + font-weight: 600; +} + +.theme-button { + display: flex; + align-items: center; + gap: 10px; + background: var(--bg-secondary); + border: 2px solid var(--border-primary); + border-radius: 8px; + padding: 12px 20px; + cursor: pointer; + width: 100%; + transition: all 0.2s ease; + color: var(--text-primary); + font-size: 15px; +} + +.theme-button:hover { + background: var(--bg-tertiary); + transform: translateY(-2px); +} + + diff --git a/templates/base.html b/templates/base.html index 53c8fd3..0d8a86b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -7,6 +7,58 @@ + + + + + + + + +
{% block content %}{% endblock %}
@@ -17,18 +69,81 @@