Your library
@@ -72,6 +135,34 @@ onMounted(async () => {
margin: clamp(4.5rem, 10vh, 7rem) auto 0;
}
+.schedules-catalog {
+ width: min(100%, 72rem);
+ margin: clamp(4.5rem, 10vh, 7rem) auto 0;
+}
+
+.schedules-catalog__heading {
+ display: flex;
+ align-items: end;
+ justify-content: space-between;
+ gap: 2rem;
+}
+
+.schedules-catalog__heading h2 {
+ margin: 0;
+ font-family: Georgia, 'Times New Roman', serif;
+ font-size: clamp(2.25rem, 5vw, 3.5rem);
+ font-weight: 500;
+ line-height: 1;
+ letter-spacing: -0.045em;
+}
+
+.schedules-catalog__heading > p {
+ max-width: 24rem;
+ margin: 0;
+ color: #68776f;
+ line-height: 1.6;
+}
+
.sets-catalog__introduction {
max-width: 44rem;
}
@@ -120,6 +211,11 @@ h1 {
gap: 1rem;
}
+.catalog-state--compact {
+ min-height: 7rem;
+ margin-top: 2rem;
+}
+
.catalog-state--error p {
margin: 0;
}
@@ -155,6 +251,78 @@ h1 {
list-style: none;
}
+.schedule-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
+ gap: 1rem;
+ margin: 2rem 0 0;
+ padding: 0;
+ list-style: none;
+}
+
+.schedule-card-link {
+ display: block;
+ height: 100%;
+ border-radius: 1rem;
+ text-decoration: none;
+}
+
+.schedule-card {
+ height: 100%;
+ padding: 1.4rem;
+ border: 1px solid rgb(24 48 41 / 12%);
+ border-radius: 1rem;
+ background: rgb(255 253 247 / 88%);
+ box-shadow: 0 0.75rem 2rem rgb(40 62 52 / 7%);
+ transition:
+ border-color 160ms ease,
+ transform 160ms ease;
+}
+
+.schedule-card-link:hover .schedule-card {
+ border-color: rgb(40 92 78 / 35%);
+ transform: translateY(-2px);
+}
+
+.schedule-card-link:focus-visible {
+ outline: 3px solid rgb(86 127 112 / 38%);
+ outline-offset: 0.25rem;
+}
+
+.schedule-card__heading {
+ display: flex;
+ justify-content: space-between;
+ gap: 1rem;
+ color: #926044;
+ font-size: 0.68rem;
+ font-weight: 800;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+.schedule-card__heading p {
+ margin: 0;
+}
+
+.schedule-card__kind {
+ text-transform: none;
+}
+
+.schedule-card h3 {
+ margin: 2rem 0 0;
+ font-family: Georgia, 'Times New Roman', serif;
+ font-size: 1.8rem;
+ font-weight: 500;
+ line-height: 1.1;
+}
+
+.schedule-card__dates {
+ display: block;
+ margin-top: 1rem;
+ color: #68776f;
+ font-size: 0.78rem;
+}
+
.set-card {
height: 100%;
min-height: 11rem;
@@ -225,6 +393,15 @@ h1 {
margin-top: 3.75rem;
}
+ .schedules-catalog {
+ margin-top: 3.75rem;
+ }
+
+ .schedules-catalog__heading {
+ display: grid;
+ gap: 1rem;
+ }
+
.set-grid {
margin-top: 2.25rem;
}
diff --git a/frontend/website/src/views/ScheduleDetailView.vue b/frontend/website/src/views/ScheduleDetailView.vue
new file mode 100644
index 0000000..352f44f
--- /dev/null
+++ b/frontend/website/src/views/ScheduleDetailView.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+ ←
+ Back to dashboard
+
+
+ Loading schedule...
+
+
+
Schedule not found
+
This schedule is not available.
+
+
+
+
{{ detailError }}
+
+
+
+
+
+
+ {{ activeSchedule.elementKind }} plan
+
+ {{ activeSchedule.set.name }} schedule
+
+ {{ activeSchedule.assignmentCount }}
+ {{ activeSchedule.elementKind }}
+ {{ activeSchedule.assignmentCount === 1 ? 'assignment' : 'assignments' }} across
+ {{ activeSchedule.days.length }}
+ {{ activeSchedule.days.length === 1 ? 'day' : 'days' }}
+
+
+ {{ formatDate(activeSchedule.startDate) }} to
+ {{ formatDate(activeSchedule.targetDate) }}
+
+
+
+
+ -
+
+
+
Rest day
+
+
+ -
+ {{ assignment.element.path.join(' / ') }}
+ {{ assignment.element.kind }}
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/website/src/views/SetLayoutView.vue b/frontend/website/src/views/SetLayoutView.vue
index 582f6b5..6edf2b9 100644
--- a/frontend/website/src/views/SetLayoutView.vue
+++ b/frontend/website/src/views/SetLayoutView.vue
@@ -63,6 +63,14 @@ async function retry(): Promise
{
Explore every element in this set and see how each level fits into the whole.
+
+ Schedule this set
+ →
+