diff --git a/run.bash b/run.bash
index 06346d0..80f5336 100644
--- a/run.bash
+++ b/run.bash
@@ -1,17 +1,17 @@
-#!/bin/bash
-
-set -e # exit if any command fails
-
-# Ensure QPP/database directory exists
-mkdir -p src/database
-
-python -m venv venv
-source venv/bin/activate
-
-pip install --upgrade pip
-pip install -r requirements.txt
-
-export FLASK_APP=src.app
-export FLASK_ENV=production
-
-flask run --host=0.0.0.0 --port=5000
+u!/bin/bash
+
+set -e # exit if any command fails
+
+# Ensure QPP/database directory exists
+mkdir -p src/database
+
+python -m venv venv
+source venv/bin/activate
+
+pip install --upgrade pip
+pip install -r requirements.txt
+
+export FLASK_APP=src.app
+export FLASK_ENV=production
+
+flask run --host=0.0.0.0 --port=5000
diff --git a/run.bat b/run.bat
new file mode 100644
index 0000000..ba180fe
--- /dev/null
+++ b/run.bat
@@ -0,0 +1 @@
+python -m flask --app .\src\app.py run --host=0.0.0.0 --port=5000
\ No newline at end of file
diff --git a/src/static/index.css b/src/static/index.css
index fad9bcb..0ebf5fa 100644
--- a/src/static/index.css
+++ b/src/static/index.css
@@ -1,207 +1,326 @@
-:root {
- --bg: #f6f8fb;
- --card: #fff;
- --muted: #6b7280;
- --accent: #2563eb;
- --shadow: 0 4px 12px rgba(16, 24, 40, 0.06);
- --radius: 8px;
- --mono: 'JetBrains Mono', monospace;
-}
-* { box-sizing: border-box; margin: 0; padding: 0; }
-html, body {
- height: 100%;
-}
-body {
- font-family: Inter, sans-serif;
- background: var(--bg);
- color: #0f172a;
- padding: 16px;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-.wrap {
- width: 100%;
- max-width: 1100px;
-}
-header {
- margin-bottom: 14px;
-}
-header h1 {
- text-align: center;
- font-size: 1.6rem;
- color: #111827;
-}
-header p {
- color: var(--muted);
- font-size: 0.9rem;
-}
-.content {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 12px;
-}
-.content.single-column {
- grid-template-columns: 1fr;
-}
-.card {
- background: var(--card);
- border-radius: var(--radius);
- box-shadow: var(--shadow);
- padding: 12px;
-}
-/* Search/filter controls */
-.search-controls {
- margin-bottom: 12px;
- display: flex;
- gap: 8px;
-}
-.search-input {
- flex: 1;
- padding: 6px 10px;
- border: 1px solid #e5e7eb;
- border-radius: 4px;
- font-size: 0.9rem;
-}
-.filter-select {
- padding: 6px 8px;
- border: 1px solid #e5e7eb;
- border-radius: 4px;
- font-size: 0.9rem;
- background: white;
-}
-/* Problems list */
-.problems-list .problem-item {
- padding: 8px;
- border-bottom: 1px solid #e5e7eb;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-.problem-item:last-child {
- border-bottom: none;
-}
-.problem-item a {
- text-decoration: none;
- color: #0077ff;
- font-weight: 600;
-}
-/* Difficulty badge */
-.difficulty {
- display: inline-flex;
- align-items: center;
- padding: 0.25em 0.6em;
- border-radius: 10px;
- font-size: 0.85em;
- font-weight: bold;
- text-transform: uppercase;
- color: white;
- white-space: nowrap;
-}
-.difficulty[data-difficulty="easy"] {
- background-color: #4CAF50; /* Green */
-}
-.difficulty[data-difficulty="medium"] {
- background-color: #FFC107; /* Amber */
- color: #333;
-}
-.difficulty[data-difficulty="hard"] {
- background-color: #F44336; /* Red */
-}
-/* Leaderboard */
-.leaderboard-head {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 6px;
-}
-.leaderboard-controls {
- display: flex;
- gap: 8px;
- margin-bottom: 12px;
-}
-.leaderboard-table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.9rem;
-}
-.leaderboard-table th,
-.leaderboard-table td {
- padding: 6px 8px;
- border-bottom: 1px solid #e5e7eb;
- text-align: left;
-}
-.leaderboard-table th {
- background: #f9fafb;
- font-weight: 600;
- color: var(--muted);
-}
-.leaderboard-table tr:hover {
- background: #f3f4f6;
-}
-/* Sort indicators */
-.sortable {
- cursor: pointer;
- position: relative;
- padding-right: 16px;
-}
-.sortable::after {
- content: "↕";
- position: absolute;
- right: 4px;
- top: 50%;
- transform: translateY(-50%);
- font-size: 0.8em;
- opacity: 0.5;
-}
-.sort-asc::after {
- content: "↑";
- opacity: 1;
-}
-.sort-desc::after {
- content: "↓";
- opacity: 1;
-}
-/* Toggle button */
-.btn {
- border: none;
- background: transparent;
- cursor: pointer;
- color: var(--accent);
- font-size: 0.85rem;
- padding: 4px 6px;
- border-radius: 4px;
-}
-.btn:hover {
- background: rgba(37, 99, 235, 0.08);
-}
-.btn.active {
- background: rgba(37, 99, 235, 0.15);
-}
-@media (max-width: 800px) {
- .content { grid-template-columns: 1fr; }
- .leaderboard-controls {
- flex-direction: column;
- }
-}
-
-/* Leaderboard horizontal collapse */
-#leaderboardSection {
- transition: max-width 0.35s ease, opacity 0.25s ease;
- overflow: hidden;
- max-width: 100%;
-}
-
-#leaderboardSection.hidden {
- max-width: 0;
- opacity: 0;
- pointer-events: none;
-}
-
-#leaderboardSection.visible {
- max-width: 100%; /* take full available space in grid column */
- opacity: 1;
-}
-#rankingExplanation {
- transition: all 0.35s ease;
-}
+:root {
+ --bg: #f6f8fb;
+ --card: #fff;
+ --text: #0f172a;
+ --muted: #6b7280;
+ --accent: #2563eb;
+ --border: #e5e7eb;
+ --hover: #f3f4f6;
+ --shadow: 0 4px 12px rgba(16, 24, 40, 0.06);
+ --radius: 8px;
+ --mono: "JetBrains Mono", monospace;
+}
+
+/* Dark mode variables */
+html.dark {
+ --bg: #0f172a;
+ --card: #1e293b;
+ --text: #f1f5f9;
+ --muted: #94a3b8;
+ --accent: #3b82f6;
+ --border: #334155;
+ --hover: #334155;
+ --shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+}
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+html,
+body {
+ height: 100%;
+}
+body {
+ font-family: Inter, sans-serif;
+ background: var(--bg);
+ color: var(--text);
+ padding: 16px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transition:
+ background-color 0.3s ease,
+ color 0.3s ease;
+}
+.wrap {
+ width: 100%;
+ max-width: 1100px;
+}
+header {
+ margin-bottom: 14px;
+}
+.header-content {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+}
+header h1 {
+ text-align: center;
+ font-size: 1.6rem;
+ color: var(--text);
+}
+header p {
+ color: var(--muted);
+ font-size: 0.9rem;
+}
+.dark-mode-toggle {
+ position: absolute;
+ right: 0;
+ background: none;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ padding: 6px 10px;
+ cursor: pointer;
+ color: var(--text);
+ font-size: 1.2rem;
+ transition: all 0.3s ease;
+}
+.dark-mode-toggle:hover {
+ background: var(--hover);
+ transform: scale(1.05);
+}
+html.dark .dark-mode-icon::before {
+ content: "☀︎️";
+}
+html:not(.dark) .dark-mode-icon::before {
+ content: "⏾";
+}
+.dark-mode-icon {
+ display: inline-block;
+}
+.dark-mode-icon::before {
+ font-size: 1em;
+}
+.content {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+}
+.content.single-column {
+ grid-template-columns: 1fr;
+}
+.card {
+ background: var(--card);
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+ padding: 12px;
+}
+/* Search/filter controls */
+.search-controls {
+ margin-bottom: 12px;
+ display: flex;
+ gap: 8px;
+}
+.search-input {
+ flex: 1;
+ padding: 6px 10px;
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ font-size: 0.9rem;
+ background: var(--card);
+ color: var(--text);
+ transition: border-color 0.3s ease;
+}
+.search-input:focus {
+ outline: none;
+ border-color: var(--accent);
+}
+.filter-select {
+ padding: 6px 8px;
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ font-size: 0.9rem;
+ background: var(--card);
+ color: var(--text);
+ transition: border-color 0.3s ease;
+}
+.filter-select:focus {
+ outline: none;
+ border-color: var(--accent);
+}
+/* Problems list */
+.problems-list .problem-item {
+ padding: 8px;
+ border-bottom: 1px solid var(--border);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ transition: background-color 0.3s ease;
+}
+.problem-item:hover {
+ background: var(--hover);
+}
+.problem-item:last-child {
+ border-bottom: none;
+}
+.problem-item a {
+ text-decoration: none;
+ color: var(--accent);
+ font-weight: 600;
+ transition: color 0.3s ease;
+}
+.problem-item a:hover {
+ text-decoration: underline;
+}
+/* Difficulty badge */
+.difficulty {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.25em 0.6em;
+ border-radius: 10px;
+ font-size: 0.85em;
+ font-weight: bold;
+ text-transform: uppercase;
+ color: white;
+ white-space: nowrap;
+}
+.difficulty[data-difficulty="easy"] {
+ background-color: #4caf50; /* Green */
+}
+.difficulty[data-difficulty="medium"] {
+ background-color: #ffc107; /* Amber */
+ color: #333;
+}
+.difficulty[data-difficulty="hard"] {
+ background-color: #f44336; /* Red */
+}
+/* Leaderboard */
+.leaderboard-head {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 6px;
+}
+.leaderboard-controls {
+ display: flex;
+ gap: 8px;
+ margin-bottom: 12px;
+}
+.leaderboard-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.9rem;
+}
+.leaderboard-table th,
+.leaderboard-table td {
+ padding: 6px 8px;
+ border-bottom: 1px solid var(--border);
+ text-align: left;
+}
+.leaderboard-table th {
+ background: var(--hover);
+ font-weight: 600;
+ color: var(--muted);
+}
+.leaderboard-table tr:hover {
+ background: var(--hover);
+}
+/* Sort indicators */
+.sortable {
+ cursor: pointer;
+ position: relative;
+ padding-right: 16px;
+}
+.sortable::after {
+ content: "↕";
+ position: absolute;
+ right: 4px;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 0.8em;
+ opacity: 0.5;
+}
+.sort-asc::after {
+ content: "↑";
+ opacity: 1;
+}
+.sort-desc::after {
+ content: "↓";
+ opacity: 1;
+}
+/* Toggle button */
+.btn {
+ border: none;
+ background: transparent;
+ cursor: pointer;
+ color: var(--accent);
+ font-size: 0.85rem;
+ padding: 4px 6px;
+ border-radius: 4px;
+}
+.btn:hover {
+ background: rgba(37, 99, 235, 0.08);
+}
+.btn.active {
+ background: rgba(37, 99, 235, 0.15);
+}
+@media (max-width: 800px) {
+ .content {
+ grid-template-columns: 1fr;
+ }
+ .leaderboard-controls {
+ flex-direction: column;
+ }
+}
+
+/* Leaderboard horizontal collapse */
+#leaderboardSection {
+ transition:
+ max-width 0.35s ease,
+ opacity 0.25s ease;
+ overflow: hidden;
+ max-width: 100%;
+}
+
+#leaderboardSection.hidden {
+ max-width: 0;
+ opacity: 0;
+ pointer-events: none;
+}
+
+#leaderboardSection.visible {
+ max-width: 100%; /* take full available space in grid column */
+ opacity: 1;
+}
+#rankingExplanation {
+ transition: all 0.35s ease;
+}
+
+/* Pagination Controls */
+.pagination-controls {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 12px;
+ padding-top: 12px;
+ border-top: 1px solid var(--border);
+}
+.pagination-btn {
+ background: var(--card);
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ padding: 6px 12px;
+ cursor: pointer;
+ color: var(--text);
+ font-size: 0.9rem;
+ transition: all 0.3s ease;
+}
+.pagination-btn:hover:not(:disabled) {
+ background: var(--hover);
+ border-color: var(--accent);
+}
+.pagination-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+.pagination-info {
+ color: var(--muted);
+ font-size: 0.9rem;
+}
+
+/* Hide pagination when not needed */
+.pagination-controls.hidden {
+ display: none;
+}
diff --git a/src/static/problem.css b/src/static/problem.css
index 73572da..83037b4 100644
--- a/src/static/problem.css
+++ b/src/static/problem.css
@@ -1,212 +1,296 @@
-body {
- font-family: 'Inter', sans-serif;
- margin: 0;
- padding: 0;
- background-color: #f9f9f9;
- color: #333;
- min-height: 100vh; /* allow content to grow */
- overflow-y: auto; /* allow vertical scroll */
- box-sizing: border-box;
-}
-
-*, *::before, *::after {
- box-sizing: inherit;
-}
-
-.main-container {
- display: flex;
- flex-wrap: wrap; /* wrap on small screens */
- min-height: 100vh;
- width: 100vw;
-}
-
-.problem-panel {
- flex: 1 1 400px; /* grow/shrink with base 400px */
- min-width: 300px;
- background: white;
- overflow-y: auto;
- padding: 20px;
- border-right: 1px solid #eaeaea;
- max-height: 100vh;
-}
-
-.editor-container {
- flex: 1 1 400px;
- min-width: 300px;
- display: flex;
- flex-direction: column;
- background: white;
- max-height: 100vh;
- overflow: hidden; /* internal scroll handling */
-}
-
-.editor-header {
- padding: 15px 20px;
- border-bottom: 1px solid #eaeaea;
- flex-shrink: 0;
-}
-
-.editor-wrapper {
- flex: 1 1 auto;
- display: flex;
- flex-direction: column;
- min-height: 0;
- padding: 0 20px;
- overflow-y: auto;
-}
-
-.problem-header {
- display: flex;
- align-items: center;
- margin-bottom: 20px;
-}
-
-.back-btn {
- background: none;
- border: none;
- cursor: pointer;
- font-size: 16px;
- color: #666;
- margin-right: 15px;
- padding: 5px;
-}
-
-.back-btn:hover {
- color: #000;
-}
-
-h1 {
- font-size: 22px;
- font-weight: 600;
- margin: 0;
- color: #1a1a1a;
-}
-
-.problem-desc {
- line-height: 1.6;
- font-size: 15px;
- overflow-wrap: break-word;
-}
-
-.problem-desc pre {
- background: #f6f8fa;
- padding: 12px;
- border-radius: 4px;
- overflow-x: auto;
- font-family: 'JetBrains Mono', monospace;
- font-size: 14px;
-}
-
-.problem-desc code {
- background: #f6f8fa;
- padding: 2px 4px;
- border-radius: 3px;
- font-family: 'JetBrains Mono', monospace;
- font-size: 14px;
-}
-
-.editor-actions {
- padding: 15px 0;
- display: flex;
- justify-content: flex-end;
- flex-shrink: 0;
-}
-
-.editor-actions button {
- background-color: #007bff;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 4px;
- cursor: pointer;
- font-weight: 500;
- font-size: 14px;
-}
-
-.editor-actions button:hover {
- background-color: #0069d9;
-}
-
-#editor {
- flex: 1 1 auto;
- min-height: 300px;
- border: 1px solid #ddd;
- border-radius: 4px;
- overflow: auto;
- max-height: 60vh;
-}
-
-.result-panel {
- margin-top: 20px;
- padding: 15px;
- background: #f8f9fa;
- border-radius: 4px;
- margin-bottom: 20px;
- min-height: 120px;
- overflow-y: auto;
- max-height: 30vh;
-}
-
-.result-panel h3 {
- margin-top: 0;
- font-size: 16px;
- margin-bottom: 10px;
-}
-
-.result-panel pre {
- background: #f6f8fa;
- padding: 12px;
- border-radius: 4px;
- overflow-x: auto;
- white-space: pre-wrap;
- font-family: 'JetBrains Mono', monospace;
- font-size: 14px;
- margin: 5px 0;
-}
-
-.placeholder {
- color: #999;
- font-style: italic;
- text-align: center;
- padding: 20px;
-}
-
-label {
- display: block;
- margin-bottom: 5px;
- font-size: 14px;
- color: #666;
-}
-
-input[type="text"] {
- width: 100%;
- padding: 8px;
- border: 1px solid #ddd;
- border-radius: 4px;
- margin-bottom: 15px;
- font-family: 'Inter', sans-serif;
-}
-
-/* Responsive adjustments */
-@media (max-width: 768px) {
- .main-container {
- flex-direction: column;
- height: auto;
- overflow-y: visible;
- }
- .problem-panel, .editor-container {
- flex: none;
- width: 100%;
- min-width: auto;
- max-height: none;
- border-right: none;
- border-bottom: 1px solid #eaeaea;
- }
- #editor {
- min-height: 400px;
- max-height: none;
- }
- .result-panel {
- max-height: none;
- }
-}
\ No newline at end of file
+:root {
+ --bg: #f9f9f9;
+ --card: #fff;
+ --text: #333;
+ --muted: #666;
+ --accent: #007bff;
+ --accent-hover: #0069d9;
+ --border: #eaeaea;
+ --hover: #f8f9fa;
+ --code-bg: #f6f8fa;
+ --editor-border: #ddd;
+}
+
+html.dark {
+ --bg: #0f172a;
+ --card: #1e293b;
+ --text: #f1f5f9;
+ --muted: #94a3b8;
+ --accent: #3b82f6;
+ --accent-hover: #2563eb;
+ --border: #334155;
+ --hover: #334155;
+ --code-bg: #1e293b;
+ --editor-border: #475569;
+}
+
+body {
+ font-family: "Inter", sans-serif;
+ margin: 0;
+ padding: 0;
+ background-color: var(--bg);
+ color: var(--text);
+ min-height: 100vh; /* allow content to grow */
+ overflow-y: auto; /* allow vertical scroll */
+ box-sizing: border-box;
+ transition:
+ background-color 0.3s ease,
+ color 0.3s ease;
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: inherit;
+}
+
+.main-container {
+ display: flex;
+ flex-wrap: wrap; /* wrap on small screens */
+ min-height: 100vh;
+ width: 100vw;
+}
+
+.problem-panel {
+ flex: 1 1 400px; /* grow/shrink with base 400px */
+ min-width: 300px;
+ background: var(--card);
+ overflow-y: auto;
+ padding: 20px;
+ border-right: 1px solid var(--border);
+ max-height: 100vh;
+ transition: background-color 0.3s ease;
+}
+
+.editor-container {
+ flex: 1 1 400px;
+ min-width: 300px;
+ display: flex;
+ flex-direction: column;
+ background: var(--card);
+ max-height: 100vh;
+ overflow: hidden; /* internal scroll handling */
+ transition: background-color 0.3s ease;
+}
+
+.editor-header {
+ padding: 15px 20px;
+ border-bottom: 1px solid var(--border);
+ flex-shrink: 0;
+}
+
+.editor-wrapper {
+ flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
+ min-height: 0;
+ padding: 0 20px;
+ overflow-y: auto;
+}
+
+.problem-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+}
+
+.back-btn {
+ background: none;
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 16px;
+ color: var(--muted);
+ margin-right: 15px;
+ padding: 6px 10px;
+ transition: all 0.3s ease;
+}
+
+.back-btn:hover {
+ color: var(--text);
+ background: var(--hover);
+}
+
+.dark-mode-toggle {
+ background: none;
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ padding: 6px 10px;
+ cursor: pointer;
+ color: var(--text);
+ font-size: 1.2rem;
+ transition: all 0.3s ease;
+}
+
+.dark-mode-toggle:hover {
+ background: var(--hover);
+ transform: scale(1.05);
+}
+
+html.dark .dark-mode-icon::before {
+ content: "☀";
+}
+
+html:not(.dark) .dark-mode-icon::before {
+ content: "⏾";
+}
+
+.dark-mode-icon {
+ display: inline-block;
+}
+
+.dark-mode-icon::before {
+ font-size: 1em;
+}
+
+h1 {
+ font-size: 22px;
+ font-weight: 600;
+ margin: 0;
+ color: var(--text);
+ flex: 1;
+}
+
+.problem-desc {
+ line-height: 1.6;
+ font-size: 15px;
+ overflow-wrap: break-word;
+}
+
+.problem-desc pre {
+ background: var(--code-bg);
+ padding: 12px;
+ border-radius: 4px;
+ overflow-x: auto;
+ font-family: "JetBrains Mono", monospace;
+ font-size: 14px;
+ border: 1px solid var(--border);
+}
+
+.problem-desc code {
+ background: var(--code-bg);
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-family: "JetBrains Mono", monospace;
+ font-size: 14px;
+}
+
+.editor-actions {
+ padding: 15px 0;
+ display: flex;
+ justify-content: flex-end;
+ flex-shrink: 0;
+}
+
+.editor-actions button {
+ background-color: var(--accent);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-weight: 500;
+ font-size: 14px;
+ transition: background-color 0.3s ease;
+}
+
+.editor-actions button:hover {
+ background-color: var(--accent-hover);
+}
+
+#editor {
+ flex: 1 1 auto;
+ min-height: 300px;
+ border: 1px solid var(--editor-border);
+ border-radius: 4px;
+ overflow: auto;
+ max-height: 60vh;
+}
+
+.result-panel {
+ margin-top: 20px;
+ padding: 15px;
+ background: var(--hover);
+ border-radius: 4px;
+ margin-bottom: 20px;
+ min-height: 120px;
+ overflow-y: auto;
+ max-height: 30vh;
+ border: 1px solid var(--border);
+ transition: background-color 0.3s ease;
+}
+
+.result-panel h3 {
+ margin-top: 0;
+ font-size: 16px;
+ margin-bottom: 10px;
+}
+
+.result-panel pre {
+ background: var(--code-bg);
+ padding: 12px;
+ border-radius: 4px;
+ overflow-x: auto;
+ white-space: pre-wrap;
+ font-family: "JetBrains Mono", monospace;
+ font-size: 14px;
+ margin: 5px 0;
+ border: 1px solid var(--border);
+}
+
+.placeholder {
+ color: var(--muted);
+ font-style: italic;
+ text-align: center;
+ padding: 20px;
+}
+
+label {
+ display: block;
+ margin-bottom: 5px;
+ font-size: 14px;
+ color: var(--muted);
+}
+
+input[type="text"] {
+ width: 100%;
+ padding: 8px;
+ border: 1px solid var(--border);
+ border-radius: 4px;
+ margin-bottom: 15px;
+ font-family: "Inter", sans-serif;
+ background: var(--card);
+ color: var(--text);
+ transition: border-color 0.3s ease;
+}
+
+input[type="text"]:focus {
+ outline: none;
+ border-color: var(--accent);
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ .main-container {
+ flex-direction: column;
+ height: auto;
+ overflow-y: visible;
+ }
+ .problem-panel,
+ .editor-container {
+ flex: none;
+ width: 100%;
+ min-width: auto;
+ max-height: none;
+ border-right: none;
+ border-bottom: 1px solid var(--border);
+ }
+ #editor {
+ min-height: 400px;
+ max-height: none;
+ }
+ .result-panel {
+ max-height: none;
+ }
+}
diff --git a/src/static/script.js b/src/static/script.js
new file mode 100644
index 0000000..38d271f
--- /dev/null
+++ b/src/static/script.js
@@ -0,0 +1,403 @@
+document.addEventListener("DOMContentLoaded", () => {
+ // Dark mode functionality
+ const darkModeToggle = document.getElementById("darkModeToggle");
+ const html = document.documentElement;
+
+ // Load saved dark mode preference
+ const savedDarkMode = localStorage.getItem("darkMode");
+ if (
+ savedDarkMode === "true" ||
+ (savedDarkMode === null &&
+ // detect if the user already has a dark mode enabled in the system settings ( works for all systems )
+ window.matchMedia("(prefers-color-scheme: dark)").matches)
+ ) {
+ html.classList.add("dark");
+ }
+
+ darkModeToggle?.addEventListener("click", () => {
+ html.classList.toggle("dark");
+ localStorage.setItem("darkMode", html.classList.contains("dark"));
+ });
+
+ // Problem search and pagination
+ const problemSearch = document.getElementById("problemSearch");
+ const problemsContainer = document.getElementById("problemsContainer");
+ const problemsPagination = document.getElementById("problemsPagination");
+ const problemsPrevBtn = document.getElementById("problemsPrevBtn");
+ const problemsNextBtn = document.getElementById("problemsNextBtn");
+ const problemsPaginationInfo = document.getElementById(
+ "problemsPaginationInfo",
+ );
+
+ let allProblemItems = [];
+ let filteredProblemItems = [];
+ let currentPage = 1;
+ const itemsPerPage = 5;
+
+ // Initialize problem items
+ function initializeProblemItems() {
+ allProblemItems = Array.from(
+ problemsContainer?.querySelectorAll(".problem-item") || [],
+ );
+ filteredProblemItems = [...allProblemItems];
+ updatePagination();
+ }
+
+ function updatePagination() {
+ const totalPages = Math.ceil(filteredProblemItems.length / itemsPerPage);
+ const startIndex = (currentPage - 1) * itemsPerPage;
+ const endIndex = startIndex + itemsPerPage;
+
+ // Hide all items first
+ allProblemItems.forEach((item) => {
+ item.style.display = "none";
+ });
+
+ // Show current page items
+ filteredProblemItems.slice(startIndex, endIndex).forEach((item) => {
+ item.style.display = "";
+ });
+
+ // Update pagination controls
+ if (problemsPrevBtn) problemsPrevBtn.disabled = currentPage <= 1;
+ if (problemsNextBtn) problemsNextBtn.disabled = currentPage >= totalPages;
+ if (problemsPaginationInfo) {
+ problemsPaginationInfo.textContent =
+ totalPages > 0
+ ? `Page ${currentPage} of ${totalPages}`
+ : "No problems found";
+ }
+
+ // Hide pagination if not needed
+ if (problemsPagination) {
+ problemsPagination.classList.toggle("hidden", totalPages <= 1);
+ }
+ }
+
+ function filterProblems() {
+ const term = problemSearch?.value.toLowerCase().trim() || "";
+ filteredProblemItems = allProblemItems.filter((item) => {
+ const name = item.dataset.name?.toLowerCase() || "";
+ const desc = item.dataset.desc?.toLowerCase() || "";
+ return !term || name.includes(term) || desc.includes(term);
+ });
+ currentPage = 1;
+ updatePagination();
+ }
+
+ // Event listeners for pagination
+ problemsPrevBtn?.addEventListener("click", () => {
+ if (currentPage > 1) {
+ currentPage--;
+ updatePagination();
+ }
+ });
+
+ problemsNextBtn?.addEventListener("click", () => {
+ const totalPages = Math.ceil(filteredProblemItems.length / itemsPerPage);
+ if (currentPage < totalPages) {
+ currentPage++;
+ updatePagination();
+ }
+ });
+
+ problemSearch?.addEventListener("input", filterProblems);
+
+ // Initialize problems pagination
+ if (problemsContainer) {
+ initializeProblemItems();
+ }
+
+ // Leaderboard functionality
+ const problemFilter = document.getElementById("problemFilter");
+ const runtimeFilter = document.getElementById("runtimeFilter");
+ const leaderboardBody = document.getElementById("leaderboardBody");
+ const sortableHeaders = document.querySelectorAll(".sortable");
+
+ let currentSort = { column: "rank", direction: "asc" };
+ let allRows = [];
+
+ // Initialize rows array
+ function initializeRows() {
+ allRows = Array.from(leaderboardBody.querySelectorAll("tr")).map((row) => {
+ return {
+ element: row,
+ user: row.dataset.user || "",
+ problem: row.dataset.problem || "",
+ runtime: parseFloat(row.dataset.runtime) || 0,
+ memory: parseFloat(row.dataset.memory) || 0,
+ timestamp: new Date(row.dataset.timestamp || Date.now()).getTime(),
+ language: row.dataset.language || "",
+ originalIndex: Array.from(leaderboardBody.children).indexOf(row),
+ };
+ });
+ }
+
+ function updateRankClasses() {
+ const visibleRows = allRows.filter(
+ (row) => row.element.style.display !== "none",
+ );
+ visibleRows.forEach((rowData, index) => {
+ const rank = index + 1;
+ const row = rowData.element;
+
+ // Update rank cell
+ const rankCell = row.cells[0];
+ if (rankCell) rankCell.textContent = rank;
+
+ // Update rank classes
+ row.className = row.className.replace(/\brank-\d+\b/g, "");
+ if (rank === 1) row.classList.add("rank-1");
+ else if (rank <= 3) row.classList.add("rank-top3");
+ });
+ }
+
+ function calculateOverallRanking() {
+ const visibleRows = allRows.filter(
+ (row) => row.element.style.display !== "none",
+ );
+
+ if (visibleRows.length === 0) return;
+
+ // Group submissions by problem to find the best performance for each
+ const problemBests = {};
+
+ visibleRows.forEach((rowData) => {
+ const problem = rowData.problem;
+ if (!problemBests[problem]) {
+ problemBests[problem] = {
+ bestRuntime: Infinity,
+ bestMemory: Infinity,
+ };
+ }
+
+ problemBests[problem].bestRuntime = Math.min(
+ problemBests[problem].bestRuntime,
+ rowData.runtime,
+ );
+ problemBests[problem].bestMemory = Math.min(
+ problemBests[problem].bestMemory,
+ rowData.memory,
+ );
+ });
+
+ // Calculate normalized scores for each submission
+ visibleRows.forEach((rowData) => {
+ const problemBest = problemBests[rowData.problem];
+
+ // Prevent division by zero
+ const runtimeScore =
+ problemBest.bestRuntime > 0
+ ? rowData.runtime / problemBest.bestRuntime
+ : 1;
+ const memoryScore =
+ problemBest.bestMemory > 0
+ ? rowData.memory / problemBest.bestMemory
+ : 1;
+
+ // Weighted overall score (70% runtime, 30% memory)
+ rowData.overallScore = runtimeScore * 0.7 + memoryScore * 0.3;
+ });
+
+ // Sort by overall score (lower is better), then by timestamp (earlier is better for ties)
+ visibleRows.sort((a, b) => {
+ const scoreDiff = a.overallScore - b.overallScore;
+ if (Math.abs(scoreDiff) > 0.000001) return scoreDiff; // Use small epsilon for float comparison
+
+ // If scores are essentially equal, prefer earlier submission
+ return a.timestamp - b.timestamp;
+ });
+
+ // Reorder DOM elements and update ranks
+ visibleRows.forEach((rowData, index) => {
+ leaderboardBody.appendChild(rowData.element);
+ });
+
+ updateRankClasses();
+ }
+
+ function filterLeaderboard() {
+ const problemTerm = (problemFilter?.value || "").toLowerCase().trim();
+ const runtimeType = runtimeFilter?.value || "all";
+
+ // Reset all rows to visible first
+ allRows.forEach((rowData) => {
+ rowData.element.style.display = "";
+ });
+
+ // Apply problem filter
+ if (problemTerm) {
+ allRows.forEach((rowData) => {
+ const problemMatch = rowData.problem
+ .toLowerCase()
+ .includes(problemTerm);
+ if (!problemMatch) {
+ rowData.element.style.display = "none";
+ }
+ });
+ }
+
+ // Apply runtime filter (best/worst per user per problem)
+ if (runtimeType === "best" || runtimeType === "worst") {
+ const userProblemGroups = {};
+
+ // Group by user + problem combination
+ allRows.forEach((rowData) => {
+ if (rowData.element.style.display === "none") return;
+
+ const key = `${rowData.user}::${rowData.problem}`;
+ if (!userProblemGroups[key]) {
+ userProblemGroups[key] = [];
+ }
+ userProblemGroups[key].push(rowData);
+ });
+
+ // Hide all except best/worst for each user-problem combination
+ Object.values(userProblemGroups).forEach((group) => {
+ if (group.length <= 1) return;
+
+ // Sort by runtime
+ group.sort((a, b) => a.runtime - b.runtime);
+
+ const keepIndex = runtimeType === "best" ? 0 : group.length - 1;
+ group.forEach((rowData, index) => {
+ if (index !== keepIndex) {
+ rowData.element.style.display = "none";
+ }
+ });
+ });
+ }
+
+ calculateOverallRanking();
+ }
+
+ function getCellValue(rowData, column) {
+ switch (column) {
+ case "rank":
+ return parseInt(rowData.element.cells[0]?.textContent) || 0;
+ case "user":
+ return rowData.user.toLowerCase();
+ case "problem":
+ return rowData.problem.toLowerCase();
+ case "runtime":
+ return rowData.runtime;
+ case "memory":
+ return rowData.memory;
+ case "timestamp":
+ return rowData.timestamp;
+ case "language":
+ return rowData.language.toLowerCase();
+ default:
+ return "";
+ }
+ }
+
+ function sortLeaderboard(column, direction) {
+ if (column === "rank") {
+ calculateOverallRanking();
+ return;
+ }
+
+ const visibleRows = allRows.filter(
+ (row) => row.element.style.display !== "none",
+ );
+
+ visibleRows.sort((a, b) => {
+ const valueA = getCellValue(a, column);
+ const valueB = getCellValue(b, column);
+
+ let comparison = 0;
+ if (typeof valueA === "number" && typeof valueB === "number") {
+ comparison = valueA - valueB;
+ } else {
+ comparison = valueA < valueB ? -1 : valueA > valueB ? 1 : 0;
+ }
+
+ return direction === "asc" ? comparison : -comparison;
+ });
+
+ // Reorder DOM elements
+ visibleRows.forEach((rowData) => {
+ leaderboardBody.appendChild(rowData.element);
+ });
+
+ updateRankClasses();
+ }
+
+ // Event listeners for sorting
+ sortableHeaders.forEach((header) => {
+ header.addEventListener("click", () => {
+ const column = header.dataset.sort;
+ if (!column) return;
+
+ // Remove sorting classes from all headers
+ sortableHeaders.forEach((h) =>
+ h.classList.remove("sort-asc", "sort-desc"),
+ );
+
+ // Toggle sort direction
+ if (currentSort.column === column) {
+ currentSort.direction =
+ currentSort.direction === "asc" ? "desc" : "asc";
+ } else {
+ currentSort.column = column;
+ currentSort.direction = "asc";
+ }
+
+ // Add sorting class to current header
+ header.classList.add(`sort-${currentSort.direction}`);
+
+ sortLeaderboard(column, currentSort.direction);
+ });
+ });
+
+ // Filter event listeners
+ problemFilter?.addEventListener("input", filterLeaderboard);
+ runtimeFilter?.addEventListener("change", filterLeaderboard);
+
+ // Rank info popout
+ const rankInfoBtn = document.getElementById("rankInfoBtn");
+ const rankingExplanation = document.getElementById("rankingExplanation");
+
+ rankInfoBtn?.addEventListener("click", (e) => {
+ e.preventDefault();
+ rankingExplanation?.classList.toggle("active");
+ rankInfoBtn?.classList.toggle("active");
+ });
+
+ // Close ranking explanation when clicking outside
+ document.addEventListener("click", (e) => {
+ if (
+ rankingExplanation?.classList.contains("active") &&
+ !rankingExplanation.contains(e.target) &&
+ !rankInfoBtn?.contains(e.target)
+ ) {
+ rankingExplanation.classList.remove("active");
+ rankInfoBtn?.classList.remove("active");
+ }
+ });
+
+ // Initialize everything
+ if (leaderboardBody && leaderboardBody.children.length > 0) {
+ initializeRows();
+ calculateOverallRanking();
+
+ // Set initial sort indicator
+ const defaultHeader = document.querySelector('[data-sort="rank"]');
+ if (defaultHeader) {
+ defaultHeader.classList.add("sort-asc");
+ }
+ }
+
+ // Apply dark mode to dynamically created elements
+ function applyDarkModeToElements() {
+ const isDark = html.classList.contains("dark");
+ // Any additional dark mode styling for dynamically created elements can go here
+ }
+
+ // Watch for dark mode changes
+ new MutationObserver(applyDarkModeToElements).observe(html, {
+ attributes: true,
+ attributeFilter: ["class"],
+ });
+});
diff --git a/src/static/style.css b/src/static/style.css
index b576b4a..2724ba5 100644
--- a/src/static/style.css
+++ b/src/static/style.css
@@ -1,260 +1,317 @@
-/* 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: #333;
- background-color: #f8f9fa;
- padding: 20px;
- max-width: 1200px;
- margin: 0 auto;
-}
-
-/* Main heading */
-h1 {
- color: #2c3e50;
- margin-bottom: -10px;
- padding-bottom: 3px;
- border-bottom: 3px solid #3498db;
- font-size: 2.2em;
-}
-
-h2 {
- color: #34495e;
- margin: 30px 0 20px 0;
- font-size: 1.5em;
-}
-
-h3 {
- color: #34495e;
- margin: 25px 0 15px 0;
- font-size: 1.3em;
-}
-
-/* Links and buttons */
-a {
- color: #3498db;
- text-decoration: none;
- padding: 8px 16px;
- border-radius: 5px;
- transition: background-color 0.3s ease;
-}
-
-a:hover {
- background-color: #e3f2fd;
- text-decoration: none;
-}
-
-/* Primary action link (Submit New Problem) */
-a[href="/problem/new"] {
- background-color: #3498db;
- color: white;
- font-weight: 600;
- margin-bottom: 30px;
- display: inline-block;
- padding: 12px 24px;
- border-radius: 8px;
-}
-
-a[href="/problem/new"]:hover {
- background-color: #2980b9;
-}
-
-/* Problem list */
-ul {
- list-style: none;
- background: white;
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
- padding: 25px;
- margin: 20px 0;
-}
-
-li {
- padding: 15px 0;
- border-bottom: 1px solid #eee;
-}
-
-li:last-child {
- border-bottom: none;
-}
-
-li a {
- display: block;
- padding: 12px 20px;
- margin: -12px -20px;
- border-radius: 6px;
- font-size: 1.1em;
-}
-
-li a:hover {
- background-color: #f8f9fa;
- transform: translateX(5px);
- transition: all 0.2s ease;
-}
-
-/* Problem page specific styles */
-.problem-header {
- display: flex;
- align-items: center;
- margin-bottom: 30px;
- gap: 20px;
-}
-
-.back-btn {
- background-color: #95a5a6;
- color: white;
- border: none;
- padding: 10px 20px;
- border-radius: 6px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 500;
- transition: background-color 0.3s ease;
-}
-
-.back-btn:hover {
- background-color: #7f8c8d;
-}
-
-.problem-desc {
- background: white;
- padding: 30px;
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
- margin-bottom: 30px;
- font-size: 1.1em;
- line-height: 1.7;
-}
-
-/* Editor section */
-.editor-section {
- background: white;
- padding: 30px;
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
- margin-bottom: 30px;
-}
-
-#editor {
- border: 2px solid #ddd;
- border-radius: 8px;
- margin: 20px 0;
- height: 400px;
- overflow: hidden;
-}
-
-.editor-actions {
- margin-top: 20px;
- text-align: right;
-}
-
-form button[type="submit"] {
- background-color: #27ae60;
- color: white;
- border: none;
- padding: 12px 30px;
- border-radius: 8px;
- cursor: pointer;
- font-size: 16px;
- font-weight: 600;
- transition: background-color 0.3s ease;
-}
-
-form button[type="submit"]:hover {
- background-color: #229954;
-}
-
-/* Results section */
-b {
- color: #2c3e50;
- display: inline-block;
- margin: 10px 0 5px 0;
-}
-
-pre {
- background-color: #f4f4f4;
- padding: 20px;
- border-radius: 6px;
- border-left: 4px solid #3498db;
- margin: 10px 0 20px 0;
- overflow-x: auto;
- font-family: 'JetBrains Mono', 'Courier New', monospace;
- font-size: 14px;
- line-height: 1.4;
-}
-
-pre[style*="color:red"] {
- border-left-color: #e74c3c;
- background-color: #fdf2f2;
-}
-
-/* Status messages */
-p[style*="color:green"] {
- background-color: #d4edda;
- color: #155724;
- padding: 15px 20px;
- border-radius: 6px;
- border-left: 4px solid #27ae60;
- margin: 20px 0;
- font-weight: 600;
-}
-
-p[style*="color:red"] {
- background-color: #f8d7da;
- color: #721c24;
- padding: 15px 20px;
- border-radius: 6px;
- border-left: 4px solid #e74c3c;
- margin: 20px 0;
- font-weight: 600;
-}
-
-/* Back to Problems link */
-a[href="/"] {
- display: inline-block;
- margin-top: 30px;
- background-color: #6c757d;
- color: white;
- padding: 10px 20px;
- border-radius: 6px;
- font-weight: 500;
-}
-
-a[href="/"]:hover {
- background-color: #5a6268;
-}
-
-/* Responsive design */
-@media (max-width: 768px) {
- body {
- padding: 15px;
- }
-
- .problem-header {
- flex-direction: column;
- align-items: flex-start;
- gap: 15px;
- }
-
- h1 {
- font-size: 1.8em;
- }
-
- .problem-desc, .editor-section, ul {
- padding: 20px;
- }
-
- #editor {
- height: 300px;
- }
-
- .editor-actions {
- text-align: center;
- }
-}
+:root {
+ --bg: #f8f9fa;
+ --card: #fff;
+ --text: #333;
+ --heading: #2c3e50;
+ --heading-secondary: #34495e;
+ --accent: #3498db;
+ --accent-hover: #2980b9;
+ --success: #27ae60;
+ --success-hover: #229954;
+ --error: #e74c3c;
+ --muted: #6c757d;
+ --muted-hover: #5a6268;
+ --border: #ddd;
+ --code-bg: #f4f4f4;
+ --success-bg: #d4edda;
+ --success-text: #155724;
+ --error-bg: #f8d7da;
+ --error-text: #721c24;
+ --hover-bg: #e3f2fd;
+ --shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+}
+
+html.dark {
+ --bg: #0f172a;
+ --card: #1e293b;
+ --text: #f1f5f9;
+ --heading: #3b82f6;
+ --heading-secondary: #94a3b8;
+ --accent: #3b82f6;
+ --accent-hover: #2563eb;
+ --success: #22c55e;
+ --success-hover: #16a34a;
+ --error: #ef4444;
+ --muted: #64748b;
+ --muted-hover: #475569;
+ --border: #334155;
+ --code-bg: #1e293b;
+ --success-bg: #065f46;
+ --success-text: #d1fae5;
+ --error-bg: #7f1d1d;
+ --error-text: #fecaca;
+ --hover-bg: #1e40af;
+ --shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
+}
+
+/* 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);
+ background-color: var(--bg);
+ padding: 20px;
+ max-width: 1200px;
+ margin: 0 auto;
+ transition:
+ background-color 0.3s ease,
+ color 0.3s ease;
+}
+
+/* Main heading */
+h1 {
+ color: var(--heading);
+ margin-bottom: -10px;
+ padding-bottom: 3px;
+ border-bottom: 3px solid var(--accent);
+ font-size: 2.2em;
+}
+
+h2 {
+ color: var(--heading-secondary);
+ margin: 30px 0 20px 0;
+ font-size: 1.5em;
+}
+
+h3 {
+ color: var(--heading-secondary);
+ margin: 25px 0 15px 0;
+ font-size: 1.3em;
+}
+
+/* Links and buttons */
+a {
+ color: var(--accent);
+ text-decoration: none;
+ padding: 8px 16px;
+ border-radius: 5px;
+ transition: background-color 0.3s ease;
+}
+
+a:hover {
+ background-color: var(--hover-bg);
+ text-decoration: none;
+}
+
+/* Primary action link (Submit New Problem) */
+a[href="/problem/new"] {
+ background-color: var(--accent);
+ color: white;
+ font-weight: 600;
+ margin-bottom: 30px;
+ display: inline-block;
+ padding: 12px 24px;
+ border-radius: 8px;
+}
+
+a[href="/problem/new"]:hover {
+ background-color: var(--accent-hover);
+}
+
+/* Problem list */
+ul {
+ list-style: none;
+ background: var(--card);
+ border-radius: 8px;
+ box-shadow: var(--shadow);
+ padding: 25px;
+ margin: 20px 0;
+ transition: background-color 0.3s ease;
+}
+
+li {
+ padding: 15px 0;
+ border-bottom: 1px solid var(--border);
+}
+
+li:last-child {
+ border-bottom: none;
+}
+
+li a {
+ display: block;
+ padding: 12px 20px;
+ margin: -12px -20px;
+ border-radius: 6px;
+ font-size: 1.1em;
+}
+
+li a:hover {
+ background-color: var(--hover-bg);
+ transform: translateX(5px);
+ transition: all 0.2s ease;
+}
+
+/* Problem page specific styles */
+.problem-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 30px;
+ gap: 20px;
+}
+
+.back-btn {
+ background-color: var(--muted);
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ transition: background-color 0.3s ease;
+}
+
+.back-btn:hover {
+ background-color: var(--muted-hover);
+}
+
+.problem-desc {
+ background: var(--card);
+ padding: 30px;
+ border-radius: 8px;
+ box-shadow: var(--shadow);
+ margin-bottom: 30px;
+ font-size: 1.1em;
+ line-height: 1.7;
+ transition: background-color 0.3s ease;
+}
+
+/* Editor section */
+.editor-section {
+ background: var(--card);
+ padding: 30px;
+ border-radius: 8px;
+ box-shadow: var(--shadow);
+ margin-bottom: 30px;
+ transition: background-color 0.3s ease;
+}
+
+#editor {
+ border: 2px solid var(--border);
+ border-radius: 8px;
+ margin: 20px 0;
+ height: 400px;
+ overflow: hidden;
+}
+
+.editor-actions {
+ margin-top: 20px;
+ text-align: right;
+}
+
+form button[type="submit"] {
+ background-color: var(--success);
+ color: white;
+ border: none;
+ padding: 12px 30px;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 16px;
+ font-weight: 600;
+ transition: background-color 0.3s ease;
+}
+
+form button[type="submit"]:hover {
+ background-color: var(--success-hover);
+}
+
+/* Results section */
+b {
+ color: var(--heading);
+ display: inline-block;
+ margin: 10px 0 5px 0;
+}
+
+pre {
+ background-color: var(--code-bg);
+ padding: 20px;
+ border-radius: 6px;
+ border-left: 4px solid var(--accent);
+ margin: 10px 0 20px 0;
+ overflow-x: auto;
+ font-family: "JetBrains Mono", "Courier New", monospace;
+ font-size: 14px;
+ line-height: 1.4;
+ border: 1px solid var(--border);
+ transition: background-color 0.3s ease;
+}
+
+pre[style*="color:red"] {
+ border-left-color: var(--error);
+ background-color: var(--error-bg);
+}
+
+/* Status messages */
+p[style*="color:green"] {
+ background-color: var(--success-bg);
+ color: var(--success-text);
+ padding: 15px 20px;
+ border-radius: 6px;
+ border-left: 4px solid var(--success);
+ margin: 20px 0;
+ font-weight: 600;
+}
+
+p[style*="color:red"] {
+ background-color: var(--error-bg);
+ color: var(--error-text);
+ padding: 15px 20px;
+ border-radius: 6px;
+ border-left: 4px solid var(--error);
+ margin: 20px 0;
+ font-weight: 600;
+}
+
+/* Back to Problems link */
+a[href="/"] {
+ display: inline-block;
+ margin-top: 30px;
+ background-color: var(--muted);
+ color: white;
+ padding: 10px 20px;
+ border-radius: 6px;
+ font-weight: 500;
+}
+
+a[href="/"]:hover {
+ background-color: var(--muted-hover);
+}
+
+/* Responsive design */
+@media (max-width: 768px) {
+ body {
+ padding: 15px;
+ }
+
+ .problem-header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 15px;
+ }
+
+ h1 {
+ font-size: 1.8em;
+ }
+
+ .problem-desc,
+ .editor-section,
+ ul {
+ padding: 20px;
+ }
+
+ #editor {
+ height: 300px;
+ }
+
+ .editor-actions {
+ text-align: center;
+ }
+}
diff --git a/src/templates/index.html b/src/templates/index.html
index 14dec25..744137b 100644
--- a/src/templates/index.html
+++ b/src/templates/index.html
@@ -1,136 +1,146 @@
-
-
-
-
-
-Quick Problem Platform
-
-
-
-
-
-
-
- Quick Problem Platform
-
-
-
-
-
-
-
- Problems
-
- {% for folder, description, test_code, difficulty in problems %}
-
- {% else %}
-
No problems yet.
- {% endfor %}
-
-
-
-
-
-
-
Leaderboard
- ℹ️
-
-
-
-
-
-
-
-
-
-
- | Rank |
- User |
- Problem |
- Runtime (s) |
- Memory (KB) |
- Line |
- Timestamp |
-
-
-
- {% for entry in leaderboard %}
-
- | {{ loop.index }} |
- {{ entry[0] }} |
-
-
- {{ problem_titles.get(entry[1], 'Unknown') }}
-
- |
- {{ '%.4f'|format(entry[2]) }} |
- {{ entry[3] }} |
- {{ entry[4] if entry[4] else '-' }} |
- {{ entry[5] }} |
-
- {% else %}
- | No leaderboard entries yet. |
- {% endfor %}
-
-
-
-
-
-
-
- How Ranking Works
- The leaderboard uses a weighted scoring system to determine overall rank:
-
- - Runtime: How fast the solution runs (lower is better).
- - Memory Usage: How much memory the solution uses (lower is better).
-
- Overall score is calculated as:
-
-
- runtimeScore = yourRuntime / bestRuntime
- memoryScore = yourMemory / bestMemory
- overallScore = runtimeScore × 0.7 + memoryScore × 0.3
-
-
- Lower overall scores are better. If scores are equal, earlier submission ranks higher.
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+Quick Problem Platform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Problems
+
+ {% for folder, description, test_code, difficulty in problems %}
+
+ {% else %}
+
No problems yet.
+ {% endfor %}
+
+
+
+
+
+
+
+
Leaderboard
+ ℹ️
+
+
+
+
+
+
+
+
+
+
+ | Rank |
+ User |
+ Problem |
+ Runtime (s) |
+ Memory (KB) |
+ Line |
+ Timestamp |
+
+
+
+ {% for entry in leaderboard %}
+
+ | {{ loop.index }} |
+ {{ entry[0] }} |
+
+
+ {{ problem_titles.get(entry[1], 'Unknown') }}
+
+ |
+ {{ '%.4f'|format(entry[2]) }} |
+ {{ entry[3] }} |
+ {{ entry[4] if entry[4] else '-' }} |
+ {{ entry[5] }} |
+
+ {% else %}
+ | No leaderboard entries yet. |
+ {% endfor %}
+
+
+
+
+
+
+
+ How Ranking Works
+ The leaderboard uses a weighted scoring system to determine overall rank:
+
+ - Runtime: How fast the solution runs (lower is better).
+ - Memory Usage: How much memory the solution uses (lower is better).
+
+ Overall score is calculated as:
+
+
+ runtimeScore = yourRuntime / bestRuntime
+ memoryScore = yourMemory / bestMemory
+ overallScore = runtimeScore × 0.7 + memoryScore × 0.3
+
+
+ Lower overall scores are better. If scores are equal, earlier submission ranks higher.
+
+
+
+
+
+