Header/footer polish, fix dead link, add focus rings

- Dashboard header shortened to match every other page (was notably
  taller than the rest).
- Files moved before Settings in the bottom nav.
- Removed the header's course-name badge - purely redundant with the
  page's own heading directly below it.
- Fixed a dead link: "Progress" pointed to #stats, but no element
  with that id existed anywhere on the page.
- Added a visible :focus-visible ring across all pages - tabbing
  through the site previously gave no indication of what was focused.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 10:14:02 -04:00
co-authored by Claude Sonnet 5
parent becbb0b419
commit 9fb193a07e
9 changed files with 69 additions and 35 deletions
+1
View File
@@ -1,3 +1,4 @@
2026-08-26 14:13 UTC — Header/footer polish, fix dead link, add focus rings
2026-08-26 13:41 UTC — Move sidebar left, add collapse toggle and remembered sections 2026-08-26 13:41 UTC — Move sidebar left, add collapse toggle and remembered sections
2026-08-26 13:17 UTC — Add hover tooltips for truncated sidebar titles 2026-08-26 13:17 UTC — Add hover tooltips for truncated sidebar titles
2026-08-26 13:12 UTC — Add course outline sidebar to the lesson page 2026-08-26 13:12 UTC — Add course outline sidebar to the lesson page
+5
View File
@@ -221,6 +221,11 @@ silently stay blank instead of erroring.
- Grid view shows a small progress ring in the corner of each course's - Grid view shows a small progress ring in the corner of each course's
thumbnail (a checkmark once complete) instead of a separate bar, so thumbnail (a checkmark once complete) instead of a separate bar, so
completion reads at a glance without switching to list view completion reads at a glance without switching to list view
- Interface polish: a shorter header (matching every other page instead of
standing out taller), Files moved before Settings in the bottom nav, a
visible focus ring for keyboard navigation, and a redundant course-name
badge removed from the header (the course name is already the page's own
heading right below it)
**Playback & progress** **Playback & progress**
- Video/audio player with resize, playback-speed presets, and resume-from- - Video/audio player with resize, playback-speed presets, and resume-from-
+1 -1
View File
@@ -1 +1 @@
2026-08-26 13:41 UTC — move sidebar left, add collapse toggle and remembered sections 2026-08-26 14:13 UTC — header/footer polish, fix dead link, add focus rings
+15 -22
View File
@@ -84,8 +84,7 @@
.app-header { .app-header {
background: linear-gradient(135deg, var(--bg-secondary), var(--bg-tertiary)); background: linear-gradient(135deg, var(--bg-secondary), var(--bg-tertiary));
padding: 28px 0; padding: 18px 0;
margin-bottom: 30px;
border-bottom: 3px solid var(--accent); border-bottom: 3px solid var(--accent);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25); box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
} }
@@ -124,19 +123,6 @@
margin-top: 2px; margin-top: 2px;
} }
.header-course-badge {
background: var(--bg-primary);
border: 1px solid var(--accent);
color: var(--text-primary);
padding: 8px 16px;
border-radius: var(--radius);
font-size: 0.9em;
max-width: 340px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.header-icon-btn { .header-icon-btn {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -1002,6 +988,15 @@
word-break: break-word; word-break: break-word;
} }
} }
/* Visible keyboard-focus ring - buttons/links otherwise give no
indication which element is focused when tabbing through the
page (mouse clicks don't trigger :focus-visible, so this is
keyboard/switch-navigation only, not a click-ring). */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
</style> </style>
</head> </head>
<body> <body>
@@ -1017,9 +1012,7 @@
<p class="tagline">Your self-hosted course library</p> <p class="tagline">Your self-hosted course library</p>
</div> </div>
</a> </a>
{% if course %} {% if library_stats and library_stats.total_courses %}
<div class="header-course-badge">{{ course.name }}</div>
{% elif library_stats and library_stats.total_courses %}
<a href="/random-pick" class="header-icon-btn" title="Surprise Me - random incomplete course">{{ icons.icon('dice', 20) }}</a> <a href="/random-pick" class="header-icon-btn" title="Surprise Me - random incomplete course">{{ icons.icon('dice', 20) }}</a>
{% endif %} {% endif %}
</div> </div>
@@ -1038,7 +1031,7 @@
</div> </div>
<div class="container"> <div class="container">
<div class="card"> <div class="card" id="stats">
<h2 class="course-name-heading">{{ course.name }}</h2> <h2 class="course-name-heading">{{ course.name }}</h2>
{% if resume_lesson %} {% if resume_lesson %}
<a class="btn resume-btn" href="/lesson/{{ resume_lesson.url }}">▶ Resume: {{ resume_lesson.title }}</a> <a class="btn resume-btn" href="/lesson/{{ resume_lesson.url }}">▶ Resume: {{ resume_lesson.title }}</a>
@@ -1320,12 +1313,12 @@
<a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}"> <a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span> <span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
<a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}"> <a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span> <span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
</nav> </nav>
<div id="toast-container" class="toast-container"></div> <div id="toast-container" class="toast-container"></div>
+10 -3
View File
@@ -139,6 +139,13 @@
.card li { .card li {
padding: 6px 0; padding: 6px 0;
} }
/* Visible keyboard-focus ring - see course_dashboard.html for why
:focus-visible (keyboard/switch only, not mouse clicks). */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
</style> </style>
</head> </head>
<body> <body>
@@ -239,12 +246,12 @@
<a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}"> <a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span> <span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
<a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}"> <a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span> <span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
</nav> </nav>
<script src="/static/theme.js"></script> <script src="/static/theme.js"></script>
+7
View File
@@ -706,6 +706,13 @@
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
} }
/* Visible keyboard-focus ring - see course_dashboard.html for why
:focus-visible (keyboard/switch only, not mouse clicks). */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
</style> </style>
</head> </head>
<body> <body>
+10 -3
View File
@@ -218,6 +218,13 @@
background: var(--bg-tertiary); background: var(--bg-tertiary);
text-decoration: underline; text-decoration: underline;
} }
/* Visible keyboard-focus ring - see course_dashboard.html for why
:focus-visible (keyboard/switch only, not mouse clicks). */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
</style> </style>
</head> </head>
<body> <body>
@@ -279,12 +286,12 @@
<a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}"> <a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span> <span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
<a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}"> <a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span> <span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
</nav> </nav>
<script> <script>
+10 -3
View File
@@ -228,6 +228,13 @@
transition: opacity 0.3s; transition: opacity 0.3s;
} }
#save-status.visible { opacity: 1; } #save-status.visible { opacity: 1; }
/* Visible keyboard-focus ring - see course_dashboard.html for why
:focus-visible (keyboard/switch only, not mouse clicks). */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
</style> </style>
</head> </head>
<body> <body>
@@ -506,12 +513,12 @@
<a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}"> <a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span> <span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
<a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}"> <a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span> <span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
</nav> </nav>
<script src="/static/theme.js"></script> <script src="/static/theme.js"></script>
+10 -3
View File
@@ -553,6 +553,13 @@
.tab-item.active { .tab-item.active {
color: var(--accent); color: var(--accent);
} }
/* Visible keyboard-focus ring - see course_dashboard.html for why
:focus-visible (keyboard/switch only, not mouse clicks). */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
</style> </style>
</head> </head>
<body> <body>
@@ -709,12 +716,12 @@
<a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}"> <a href="/help" class="tab-item {% if active_tab == 'help' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span> <span class="tab-icon">{{ icons.icon('help', 20) }}</span><span class="tab-label">Help</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
<a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}"> <a href="/unsorted" class="tab-item {% if active_tab == 'files' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span> <span class="tab-icon">{{ icons.icon('folder', 20) }}</span><span class="tab-label">Files</span>
</a> </a>
<a href="/settings" class="tab-item {% if active_tab == 'settings' %}active{% endif %}">
<span class="tab-icon">{{ icons.icon('settings', 20) }}</span><span class="tab-label">Settings</span>
</a>
</nav> </nav>
<script src="/static/theme.js"></script> <script src="/static/theme.js"></script>