-
- {/* Quota cost preview */}
- {quota?.enabled && !quota?.unlimited && (
-
+ {/* LEFT: Resource picker */}
+
+
+
Choose a Resource
+ {totalResources} {totalResources === 1 ? 'resource' : 'resources'}
+
+
+ {nonEmptyGroups.map((group) => (
+
+ ))}
+
- {/* Shareable link - available for all resources */}
- {shareableUrl && (
-
-
Share link:
-
{shareableUrl}
-
navigator.clipboard.writeText(shareableUrl)}
- title="Copy link"
- >
- Copy
+ {/* RIGHT: Configuration sidebar */}
+
+
+
Configuration
+
+ {!selectedResource && (
+
Select a resource to configure
+ )}
+
+ {/* GPU selection */}
+ {selectedResource && availableAccelerators.length > 0 && (
+
+
+ {acceleratorType} Node
+
+
+ {availableAccelerators.map(acc => (
+
handleSelectAccelerator(acc)}
+ >
+
handleSelectAccelerator(acc)}
+ />
+
+
{acc.displayName}
+
{acc.description}
+
+
+ ))}
+
+
+ )}
+
+ {/* Git repo input */}
+ {selectedResource && allowGitClone && (
+
+
+ Git Repository (optional)
+
+
handleRepoUrlChange(e.target.value)}
+ placeholder="https://github.com/owner/repo"
+ autoComplete="off"
+ spellCheck={false}
+ />
+ {repoValidating &&
Checking repository... }
+ {repoValid && !repoValidating && (
+
+ ✓ Repository verified{repoBranch ? ` · Branch: ${repoBranch}` : ''}
+
+ )}
+ {repoUrlError && !repoValidating &&
{repoUrlError} }
+ {githubAppName && isGitHub && (
+
+ {githubAppInstalled ? 'Add access to more repositories' : 'Authorize private repo access'}
+
+ )}
+
+ )}
+
+ {/* Runtime */}
+ {selectedResource && (
+
+
Runtime
+
+
+ minutes
+
+ {quota?.enabled && !quota?.unlimited && (
+
+ Est. cost: {cost}
+ {' · '}Remaining: {(quota?.balance ?? 0) - cost}
+
+ )}
+
+ )}
+
+ {/* Launch button */}
+
+ Launch Server
+
+ {quota?.enabled && (
+
+ Quota:{' '}
+
+ {quota?.unlimited ? 'Unlimited' : quota?.balance ?? 0}
+
+
+ )}
- )}
-
- {/* Launch section */}
-
-
- Launch
-
-
- {quota?.enabled && (
-
- Quota:
- {quota?.unlimited ? 'Unlimited' : quota?.balance ?? 0}
-
-
+
+ {/* Share link */}
+ {shareableUrl && (
+
+ Share link:
+ {shareableUrl}
+ navigator.clipboard.writeText(shareableUrl)}
+ title="Copy link"
+ >
+ Copy
+
+
)}
-
- >
+
+
)}
>
);
diff --git a/runtime/hub/frontend/apps/spawn/src/styles.css b/runtime/hub/frontend/apps/spawn/src/styles.css
index 06d0a66..4397adb 100644
--- a/runtime/hub/frontend/apps/spawn/src/styles.css
+++ b/runtime/hub/frontend/apps/spawn/src/styles.css
@@ -1,707 +1,374 @@
/* Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+ SPDX-License-Identifier: MIT */
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap');
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-/* ========== Original Spawn UI Styles ========== */
+/* ================================================================
+ Spawn UI — 方案三 two-column layout
+ Left: resource picker | Right: sticky config sidebar
+ ================================================================ */
:root {
- --dark-bg-primary: #212529;
- --dark-bg-secondary: #2b3035;
- --dark-bg-tertiary: #343a40;
- --dark-border: #495057;
- --dark-text-primary: #e9ecef;
- --dark-text-secondary: #adb5bd;
- --dark-text-muted: #6c757d;
-}
-
-/* Main container */
-[data-bs-theme="dark"] #spawn-root { background: var(--dark-bg-secondary) !important; }
-
-/* Resource container */
-[data-bs-theme="dark"] .resource-container { background: var(--dark-bg-secondary) !important; border-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .resource-container:hover { background-color: var(--dark-bg-tertiary) !important; }
-[data-bs-theme="dark"] .resource-container.selected { background-color: var(--dark-bg-tertiary) !important; border-color: var(--dark-text-secondary) !important; box-shadow: 0 0 0 1px var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .resource-container strong { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .env-desc { color: var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .dot { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .resource-tag { background: var(--dark-bg-tertiary) !important; border-color: var(--dark-border) !important; color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .git-clone-badge { background: #1a3a18 !important; border-color: #2d5a28 !important; color: #7ec87a !important; }
-
-/* Category section */
-[data-bs-theme="dark"] .resource-category { border-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .resource-category-header { background: var(--dark-bg-tertiary) !important; color: var(--dark-text-primary) !important; border-bottom-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .resource-category-header:hover { background: linear-gradient(to right, var(--dark-bg-tertiary), #3d444b) !important; }
-[data-bs-theme="dark"] .resource-category-header h5 { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .collapse-icon { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .collapsible-content { background: var(--dark-bg-secondary) !important; }
-
-/* GPU selection */
-[data-bs-theme="dark"] .gpu-selection { background: var(--dark-bg-secondary) !important; border-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .gpu-selection h6 { color: var(--dark-text-primary) !important; border-bottom-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .gpu-option { background: var(--dark-bg-tertiary) !important; border-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .gpu-option:hover { background: #3d444b !important; border-color: var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .gpu-option.selected { background: #3d444b !important; border-color: var(--dark-text-secondary) !important; box-shadow: 0 0 0 1px var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .gpu-option-name { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .gpu-option-desc { color: var(--dark-text-secondary) !important; }
-
-/* Runtime section */
-[data-bs-theme="dark"] .runtime-container { border-top-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .runtime-container label { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .runtime-container input { background: var(--dark-bg-tertiary) !important; color: var(--dark-text-primary) !important; border-color: var(--dark-border) !important; }
-
-/* Launch section */
-[data-bs-theme="dark"] .launch-button { background: var(--dark-text-primary) !important; color: var(--dark-bg-primary) !important; }
-[data-bs-theme="dark"] .launch-button:hover:not(:disabled) { background: #ffffff !important; }
-[data-bs-theme="dark"] .quota-display-simple { color: var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .quota-cost-preview { color: var(--dark-text-secondary) !important; }
-
-/* Repo URL (inside gpu-selection card) */
-[data-bs-theme="dark"] .repo-url-input { background: var(--dark-bg-tertiary) !important; color: var(--dark-text-primary) !important; border-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .repo-url-input:focus { border-color: var(--dark-text-secondary) !important; box-shadow: 0 0 0 3px rgba(173,181,189,0.15) !important; }
-[data-bs-theme="dark"] .repo-url-input.input-error { border-color: #dc3545 !important; }
-[data-bs-theme="dark"] .repo-url-input.input-valid { border-color: #2d6a27 !important; }
-[data-bs-theme="dark"] .repo-url-hint { background: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .repo-url-tooltip { background: var(--dark-bg-primary) !important; color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .repo-url-tooltip::after { border-top-color: var(--dark-bg-primary) !important; }
-[data-bs-theme="dark"] .repo-url-error { color: #f8888e !important; }
-[data-bs-theme="dark"] .repo-url-validating { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .repo-url-success { color: #7ec87a !important; }
-[data-bs-theme="dark"] .shareable-link { background: var(--dark-bg-tertiary) !important; border-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .shareable-link-label { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .shareable-link-url { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .shareable-link-copy { background: var(--dark-bg-secondary) !important; border-color: var(--dark-border) !important; color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .shareable-link-copy:hover { background: var(--dark-bg-primary) !important; }
-
-/* Warning box */
-[data-bs-theme="dark"] .warning-box { background: #4a3f2a !important; border-color: #6b5c3a !important; color: #ffc107 !important; }
-
-/* Loading spinner */
-[data-bs-theme="dark"] .loading-spinner { color: var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .spinner-icon { border-color: var(--dark-border) !important; border-top-color: var(--dark-text-primary) !important; }
-
+ --home-primary: #2c3e50;
+ --home-primary-hover: #1a252f;
+ --home-green: #34c759;
+ --home-red: #c0392b;
+ --home-surface-0: #ffffff;
+ --home-surface-1: #f5f5f7;
+ --home-surface-2: #e8e8ed;
+ --home-text: #1d1d1f;
+ --home-text-secondary: #86868b;
+ --home-text-muted: #aeaeb2;
+ --home-border: rgba(0,0,0,0.08);
+ --home-radius: 16px;
+ --home-radius-sm: 12px;
+ --home-hover-shadow: 0 4px 18px rgba(0,0,0,0.08);
+}
+[data-bs-theme="dark"] {
+ --home-primary: #86a8c7;
+ --home-primary-hover: #9dbdd8;
+ --home-green: #30d158;
+ --home-red: #ff453a;
+ --home-surface-0: #1c1c1e;
+ --home-surface-1: #2c2c2e;
+ --home-surface-2: #3a3a3c;
+ --home-text: #f5f5f7;
+ --home-text-secondary: #98989d;
+ --home-text-muted: #636366;
+ --home-border: rgba(255,255,255,0.08);
+ --home-hover-shadow: 0 4px 18px rgba(0,0,0,0.25);
+}
+
+/* ---- Root container ---- */
#spawn-root {
- max-width: 1000px;
- margin: 0 auto;
- padding: 25px;
- background: #f8f9fa;
- border-radius: 16px;
- box-shadow: 0 2px 6px rgba(0,0,0,0.05);
-}
-
-.resource-category {
- margin-bottom: 20px;
- border: 1px solid #e0e0e0;
- border-radius: 12px;
- overflow: visible;
- box-shadow: 0 1px 3px rgba(0,0,0,0.05);
-}
-
-.collapsed .resource-category,
-.resource-category.collapsed {
- overflow: hidden;
-}
-
-.resource-category-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 16px 20px;
- background: #f8f9fa;
- cursor: pointer;
- border-bottom: 1px solid #e0e0e0;
- transition: background 0.2s;
-}
-
-.resource-category-header:hover {
- background: linear-gradient(to right, #eef1f5, #e8ecf2);
-}
-
-.resource-category-header h5 {
- margin: 0;
- color: #2c3e50;
- font-size: 16px;
- font-weight: 600;
-}
-
-.collapse-icon {
- font-size: 16px;
- transition: transform 0.2s ease;
- color: #2c3e50;
-}
-
-.collapsed .collapse-icon {
- transform: rotate(-90deg);
-}
-
-.collapsible-content {
- max-height: 2000px;
- overflow: visible;
- transition: max-height 0.3s ease-out, padding 0.3s ease-out;
- background: #ffffff;
- padding: 20px;
-}
-
-.collapsed .collapsible-content {
- max-height: 0;
- padding: 0 20px;
- overflow: hidden;
-}
-
-.resource-container {
- margin-bottom: 14px;
- padding: 16px;
- border: 1px solid #e0e0e0;
- border-radius: 10px;
- display: flex;
- flex-direction: column;
- background: white;
- box-shadow: 0 1px 3px rgba(0,0,0,0.05);
- cursor: pointer;
- transition: background-color 0.2s ease;
-}
-
-.resource-container:hover {
- background-color: #f9fafb;
-}
-
-.resource-container.selected {
- background-color: #f5f7fa;
- border-color: #2c3e50;
- box-shadow: 0 0 0 1px #2c3e50;
-}
+ max-width: 1120px;
+ margin: 0 auto;
+ padding: 1.5rem;
+ background: transparent;
+ border-radius: 0;
+ box-shadow: none;
+ font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ color: var(--home-text);
+}
+[data-bs-theme="dark"] #spawn-root { background: transparent !important; }
+
+/* ---- Spawn header ---- */
+.spawn-header { text-align: center; margin-bottom: 1.5rem; }
+.spawn-breadcrumb {
+ display: inline-flex; align-items: center; gap: 0.4rem;
+ font-size: 0.78rem; color: var(--home-text-muted); margin-bottom: 0.75rem;
+}
+.spawn-breadcrumb a { color: var(--home-primary); text-decoration: none; font-weight: 500; }
+.spawn-breadcrumb a:hover { text-decoration: underline; }
+.spawn-header h1 {
+ font-family: 'Plus Jakarta Sans', sans-serif;
+ font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em;
+ margin-bottom: 0.3rem; color: var(--home-text);
+}
+.spawn-header p { font-size: 0.88rem; color: var(--home-text-secondary); }
+
+/* ---- Two-column layout ---- */
+.spawn-layout {
+ display: grid;
+ grid-template-columns: 1fr 360px;
+ gap: 1.5rem;
+ align-items: start;
+}
+
+/* ---- LEFT: Resource picker ---- */
+.spawn-picker {
+ background: var(--home-surface-0);
+ border: 1px solid var(--home-border);
+ border-radius: var(--home-radius);
+ overflow: hidden;
+}
+.picker-header {
+ padding: 1rem 1.25rem;
+ border-bottom: 1px solid var(--home-border);
+ display: flex; align-items: center; justify-content: space-between;
+}
+.picker-header h2 {
+ font-family: 'Plus Jakarta Sans', sans-serif;
+ font-size: 1.05rem; font-weight: 700; color: var(--home-text);
+}
+.picker-count {
+ font-size: 0.72rem; color: var(--home-text-muted);
+ background: var(--home-surface-2); padding: 2px 8px; border-radius: 100px;
+}
+.picker-body { /* categories render inside */ }
+
+/* Hide inline GPU/Git panels from CourseCard — sidebar handles them */
+.spawn-picker .gpu-selection { display: none; }
+
+/* Category accordion — fits inside picker */
+.spawn-picker .resource-category {
+ margin-bottom: 0;
+ border: none;
+ border-bottom: 1px solid var(--home-border);
+ border-radius: 0;
+ box-shadow: none;
+ background: transparent;
+}
+.spawn-picker .resource-category:last-child { border-bottom: none; }
+.spawn-picker .resource-category-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.75rem 1.25rem;
+ background: var(--home-surface-0);
+ border-bottom: 1px solid var(--home-border);
+ cursor: pointer;
+ transition: background 0.15s;
+}
+.spawn-picker .resource-category-header:hover { background: var(--home-surface-1); }
+.spawn-picker .resource-category-header h5 {
+ margin: 0; color: var(--home-text);
+ font-size: 0.88rem; font-weight: 600;
+ font-family: 'Plus Jakarta Sans', sans-serif;
+ flex: 1; min-width: 0;
+}
+.spawn-picker .collapse-icon { font-size: 0.7rem; color: var(--home-text-muted); }
+.spawn-picker .collapsed .collapse-icon { transform: rotate(-90deg); }
+
+.spawn-picker .collapsible-content {
+ background: var(--home-surface-1);
+ padding: 0.75rem 1rem;
+ max-height: 2000px;
+ overflow: visible;
+ transition: max-height 0.3s ease-out, padding 0.3s ease-out;
+}
+.spawn-picker .collapsed .collapsible-content {
+ max-height: 0; padding: 0 1rem; overflow: hidden;
+}
+
+/* Resource cards in picker */
+.spawn-picker .resource-container {
+ margin-bottom: 0.5rem;
+ padding: 0.75rem 0.85rem;
+ border: 2px solid var(--home-border);
+ border-radius: 10px;
+ display: flex; flex-direction: column;
+ background: var(--home-surface-0);
+ cursor: pointer;
+ transition: border-color 0.2s, box-shadow 0.15s;
+}
+.spawn-picker .resource-container:last-child { margin-bottom: 0; }
+.spawn-picker .resource-container:hover { border-color: rgba(44,62,80,0.2); }
+.spawn-picker .resource-container.selected {
+ border-color: var(--home-primary);
+ box-shadow: 0 0 0 1px var(--home-primary);
+ background: rgba(44,62,80,0.015);
+}
+[data-bs-theme="dark"] .spawn-picker .resource-container { background: var(--home-surface-0) !important; border-color: var(--home-border) !important; }
+[data-bs-theme="dark"] .spawn-picker .resource-container:hover { border-color: rgba(134,168,199,0.3) !important; }
+[data-bs-theme="dark"] .spawn-picker .resource-container.selected { border-color: var(--home-primary) !important; box-shadow: 0 0 0 1px var(--home-primary) !important; }
.resource-container input[type="radio"] {
- margin-right: 15px;
- width: 16px;
- height: 16px;
- accent-color: #6c7a89;
+ margin-right: 0.7rem; width: 16px; height: 16px;
+ accent-color: var(--home-primary); flex-shrink: 0; cursor: pointer;
}
-
.resource-container strong {
- display: block;
- font-size: 15px;
- color: #2c3e50;
- margin-bottom: 4px;
+ display: block; font-size: 0.85rem; font-weight: 600;
+ color: var(--home-text); margin-bottom: 0.1rem;
+ font-family: 'Plus Jakarta Sans', sans-serif;
}
+[data-bs-theme="dark"] .resource-container strong { color: var(--home-text) !important; }
+.env-desc { color: var(--home-text-secondary); font-size: 0.72rem; }
+[data-bs-theme="dark"] .env-desc { color: var(--home-text-secondary) !important; }
+.dot { color: var(--home-text-muted); }
+[data-bs-theme="dark"] .dot { color: var(--home-text-muted) !important; }
-.env-desc { color: #34495e; }
-.dot { color: #95a5a6; }
.resource-tag {
- color: #2c3e50;
- background: #e8e8e8;
- padding: 2px 8px;
- border-radius: 3px;
- border: 1px solid #d0d0d0;
- font-size: 13px;
+ display: inline-flex; align-items: center; gap: 3px;
+ font-size: 0.6rem; font-weight: 600; padding: 1px 6px; border-radius: 5px;
+ background: var(--home-surface-1); color: var(--home-text-secondary);
+ border: none; font-family: 'Plus Jakarta Sans', sans-serif;
}
+[data-bs-theme="dark"] .resource-tag { background: var(--home-surface-2) !important; color: var(--home-text-secondary) !important; border: none !important; }
.git-clone-badge {
- display: inline-flex;
- align-items: center;
- gap: 4px;
- padding: 2px 7px;
- border-radius: 3px;
- border: 1px solid #b7ddb0;
- background: #eaf6e8;
- color: #2d6a27;
- font-size: 12px;
- font-weight: 500;
- white-space: nowrap;
-}
-
-.gpu-selection {
- margin-top: 15px;
- margin-left: 40px;
- padding: 18px;
- background: #ffffff;
- border: 1px solid #e5e9f0;
- border-radius: 12px;
- box-shadow: 0 3px 8px rgba(0,0,0,0.06);
-}
-
-.gpu-selection h6 {
- color: #2e3440;
- font-size: 1rem;
- margin-bottom: 16px;
- padding-bottom: 10px;
- border-bottom: 2px solid #ebecf0;
- font-weight: 600;
-}
-
-.gpu-options-container {
- max-height: 180px;
- overflow-y: auto;
- padding: 0 2px;
- box-sizing: border-box;
-}
-
-.gpu-option {
- margin: 10px 0;
- padding: 14px 16px;
- background: #f8f9fc;
- border: 1px solid #e5e9f0;
- border-radius: 10px;
- display: flex;
- align-items: center;
- cursor: pointer;
- transition: all 0.2s;
-}
-
-.gpu-option:hover {
- background: #eceff4;
- border-color: #2c3e50;
-}
-
-.gpu-option.selected {
- background: #e5e9f0;
- border-color: #2c3e50;
- box-shadow: 0 0 0 1px #2c3e50;
-}
-
-.gpu-option input[type="radio"] {
- margin-right: 12px;
- width: 18px;
- height: 18px;
- accent-color: #2c3e50;
-}
-
-.gpu-option-details { flex: 1; }
-.gpu-option-name { font-weight: 600; color: #2e3440; margin-bottom: 4px; font-size: 0.95rem; }
-.gpu-option-desc { font-size: 0.85rem; color: #4c566a; line-height: 1.4; }
-
-.runtime-container {
- margin-top: 30px;
- padding-top: 25px;
- border-top: 1px solid #e0e0e0;
- display: flex;
- align-items: center;
- flex-wrap: wrap;
-}
-
-.runtime-container label {
- color: #2c3e50;
- margin-right: 15px;
- font-weight: 500;
-}
-
-.runtime-container input[type="number"] {
- width: 120px;
- padding: 10px 12px;
- border: 1px solid #d0d7de;
- border-radius: 8px;
- font-size: 14px;
- color: #2c3e50;
-}
-
-.quota-cost-preview {
- margin-left: 20px;
- font-size: 14px;
-}
-
-.launch-section {
- margin-top: 25px;
- display: flex;
- align-items: center;
- gap: 20px;
-}
-
-.launch-button {
- padding: 10px 20px;
- font-weight: 500;
- border-radius: 8px;
- background: #2c3e50;
- color: white;
- border: none;
- cursor: pointer;
-}
-
-.launch-button:hover:not(:disabled) {
- background: #1a252f;
-}
-
-.launch-button:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
-
-.quota-display-simple { font-size: 14px; color: #666; }
-
+ display: inline-flex; align-items: center; gap: 4px;
+ padding: 1px 6px; border-radius: 5px;
+ border: 1px solid #b7ddb0; background: #eaf6e8; color: #2d6a27;
+ font-size: 0.6rem; font-weight: 600; white-space: nowrap;
+}
+[data-bs-theme="dark"] .git-clone-badge { background: rgba(45,106,39,0.15) !important; border-color: rgba(45,106,39,0.3) !important; color: #4ade80 !important; }
+
+/* ---- RIGHT: Sidebar ---- */
+.spawn-sidebar {
+ position: sticky;
+ top: 1rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.sidebar-panel {
+ background: var(--home-surface-0);
+ border: 1px solid var(--home-border);
+ border-radius: var(--home-radius);
+ padding: 1.25rem;
+ display: flex; flex-direction: column; gap: 1rem;
+}
+.sidebar-panel-title {
+ font-family: 'Plus Jakarta Sans', sans-serif;
+ font-size: 0.95rem; font-weight: 700; color: var(--home-text);
+ padding-bottom: 0.65rem; border-bottom: 1px solid var(--home-border);
+}
+.sidebar-empty {
+ font-size: 0.82rem; color: var(--home-text-muted);
+ text-align: center; padding: 1rem 0;
+}
+.sidebar-section { display: flex; flex-direction: column; gap: 0.4rem; }
+.sidebar-label {
+ font-size: 0.78rem; font-weight: 600; color: var(--home-text);
+ font-family: 'Plus Jakarta Sans', sans-serif;
+}
+.sidebar-optional { font-weight: 400; font-size: 0.68rem; color: var(--home-text-muted); }
+
+/* Sidebar GPU cards */
+.sidebar-gpu-list { display: flex; flex-direction: column; gap: 0.4rem; }
+.sidebar-gpu-card {
+ display: flex; align-items: center; gap: 0.6rem;
+ padding: 0.6rem 0.75rem;
+ border: 2px solid var(--home-border); border-radius: 10px;
+ cursor: pointer; background: var(--home-surface-0);
+ transition: border-color 0.15s, box-shadow 0.15s;
+}
+.sidebar-gpu-card:hover { border-color: rgba(44,62,80,0.25); }
+.sidebar-gpu-card.selected {
+ border-color: var(--home-primary);
+ box-shadow: 0 0 0 1px var(--home-primary);
+}
+[data-bs-theme="dark"] .sidebar-gpu-card { background: var(--home-surface-1) !important; border-color: var(--home-border) !important; }
+[data-bs-theme="dark"] .sidebar-gpu-card:hover { border-color: rgba(134,168,199,0.3) !important; }
+[data-bs-theme="dark"] .sidebar-gpu-card.selected { border-color: var(--home-primary) !important; box-shadow: 0 0 0 1px var(--home-primary) !important; }
+.sidebar-gpu-radio { width: 14px; height: 14px; accent-color: var(--home-primary); cursor: pointer; }
+.sidebar-gpu-name { font-size: 0.78rem; font-weight: 600; color: var(--home-text); }
+.sidebar-gpu-desc { font-size: 0.65rem; color: var(--home-text-secondary); line-height: 1.3; }
+
+/* Sidebar Git input */
+.sidebar-git-input {
+ width: 100%; padding: 0.5rem 0.75rem;
+ border: 1px solid var(--home-border); border-radius: 10px;
+ font-size: 0.78rem; color: var(--home-text);
+ font-family: 'Plus Jakarta Sans', sans-serif;
+ background: var(--home-surface-0);
+ transition: border-color 0.2s, box-shadow 0.2s;
+}
+.sidebar-git-input:focus { outline: none; border-color: var(--home-primary); box-shadow: 0 0 0 3px rgba(44,62,80,0.08); }
+.sidebar-git-input.input-error { border-color: var(--home-red); box-shadow: 0 0 0 3px rgba(192,57,43,0.08); }
+.sidebar-git-input.input-valid { border-color: var(--home-green); box-shadow: 0 0 0 3px rgba(52,199,89,0.08); }
+[data-bs-theme="dark"] .sidebar-git-input { background: var(--home-surface-1) !important; color: var(--home-text) !important; border-color: var(--home-border) !important; }
+
+.sidebar-git-status { display: block; font-size: 0.68rem; margin-top: 0.25rem; }
+.sidebar-git-status.loading { color: var(--home-text-muted); font-style: italic; }
+.sidebar-git-status.success { color: #2d6a27; font-weight: 500; }
+.sidebar-git-status.error { color: var(--home-red); }
+[data-bs-theme="dark"] .sidebar-git-status.success { color: #4ade80; }
+[data-bs-theme="dark"] .sidebar-git-status.error { color: #ff6b6b; }
+
+.sidebar-github-link {
+ display: inline-flex; align-items: center; gap: 0.3rem;
+ font-size: 0.72rem; color: var(--home-text-muted);
+ text-decoration: none; margin-top: 0.15rem;
+}
+.sidebar-github-link:hover { color: #2d6a27; text-decoration: underline; }
+
+/* Sidebar Runtime */
+.sidebar-runtime-row { display: flex; align-items: center; gap: 0.5rem; }
+.sidebar-runtime-input {
+ width: 65px; padding: 0.4rem 0.5rem;
+ border: 1px solid var(--home-border); border-radius: 8px;
+ font-size: 0.78rem; text-align: center;
+ font-family: 'Plus Jakarta Sans', sans-serif;
+ color: var(--home-text); background: var(--home-surface-0);
+}
+.sidebar-runtime-input:focus { outline: none; border-color: var(--home-primary); box-shadow: 0 0 0 3px rgba(44,62,80,0.08); }
+[data-bs-theme="dark"] .sidebar-runtime-input { background: var(--home-surface-1) !important; color: var(--home-text) !important; border-color: var(--home-border) !important; }
+.sidebar-runtime-unit { font-size: 0.72rem; color: var(--home-text-secondary); }
+.sidebar-quota-preview { font-size: 0.72rem; color: var(--home-text-secondary); margin-top: 0.25rem; }
+
+/* Sidebar Launch button */
+.sidebar-launch-btn {
+ display: flex; align-items: center; justify-content: center; gap: 0.5rem;
+ width: 100%; background: var(--home-primary); color: #fff; border: none;
+ padding: 0.75rem; border-radius: 980px;
+ font-size: 0.92rem; font-weight: 600; cursor: pointer;
+ transition: background 0.2s, transform 0.15s;
+ font-family: 'Plus Jakarta Sans', sans-serif;
+}
+.sidebar-launch-btn:hover:not(:disabled) { background: var(--home-primary-hover); transform: scale(1.01); }
+.sidebar-launch-btn:active:not(:disabled) { transform: scale(0.98); }
+.sidebar-launch-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }
+[data-bs-theme="dark"] .sidebar-launch-btn { background: var(--home-primary) !important; color: #fff !important; }
+
+.sidebar-quota-display {
+ font-size: 0.78rem; color: var(--home-text-secondary); text-align: center;
+}
+
+/* Sidebar share link */
+.sidebar-share {
+ display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
+ padding: 0.5rem 0.85rem;
+ background: var(--home-surface-0);
+ border: 1px solid var(--home-border); border-radius: 10px;
+}
+.sidebar-share-label { font-size: 0.68rem; color: var(--home-text-muted); white-space: nowrap; font-weight: 500; }
+.sidebar-share-url { font-size: 0.62rem; color: var(--home-text-secondary); word-break: break-all; flex: 1; }
+.sidebar-share-copy {
+ padding: 0.2rem 0.5rem; border-radius: 5px;
+ border: 1px solid var(--home-border); background: var(--home-surface-0);
+ cursor: pointer; font-size: 0.62rem; font-weight: 500;
+ font-family: 'Plus Jakarta Sans', sans-serif;
+ color: var(--home-text-secondary); transition: background 0.15s;
+}
+.sidebar-share-copy:hover { background: var(--home-surface-2); }
+
+/* ---- Legacy classes (still used by old runtime/launch/warning) ---- */
.warning-box {
- padding: 15px 20px;
- background: #fff3cd;
- border: 1px solid #ffc107;
- border-radius: 8px;
- color: #856404;
- margin-bottom: 20px;
-}
-
-.loading-spinner {
- text-align: center;
- padding: 40px;
- color: #4c566a;
+ padding: 0.85rem 1.15rem;
+ background: #fffbe6; border: 1px solid #ffe58f;
+ border-radius: var(--home-radius-sm);
+ color: #7c6a0a; font-size: 0.82rem; margin-bottom: 1rem;
}
+[data-bs-theme="dark"] .warning-box { background: rgba(255,193,7,0.1) !important; border-color: rgba(255,193,7,0.25) !important; color: #ffc107 !important; }
+.loading-spinner { text-align: center; padding: 3rem; color: var(--home-text-secondary); font-size: 0.88rem; }
+[data-bs-theme="dark"] .loading-spinner { color: var(--home-text-secondary) !important; }
.spinner-icon {
- display: inline-block;
- width: 24px;
- height: 24px;
- border: 3px solid #e5e9f0;
- border-radius: 50%;
- border-top-color: #2c3e50;
- animation: spin 1s ease-in-out infinite;
- margin-right: 12px;
+ display: inline-block; width: 24px; height: 24px;
+ border: 3px solid var(--home-border); border-radius: 50%;
+ border-top-color: var(--home-primary);
+ animation: spin 1s ease-in-out infinite; margin-right: 0.75rem;
}
-
@keyframes spin { to { transform: rotate(360deg); } }
-
.feedback-container { display: none !important; }
-.optional-label {
- font-weight: 400;
- font-size: 13px;
- color: #6c757d;
-}
-
-.repo-url-input {
- width: 100%;
- padding: 10px 12px;
- border: 1px solid #d0d7de;
- border-radius: 8px;
- font-size: 14px;
- color: #2c3e50;
- box-sizing: border-box;
- transition: border-color 0.2s ease, box-shadow 0.2s ease;
-}
-
-.repo-url-input:focus {
- outline: none;
- border-color: #2c3e50;
- box-shadow: 0 0 0 3px rgba(94, 129, 172, 0.2);
-}
-
-.repo-url-input.input-error {
- border-color: #dc3545;
- box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.15);
-}
-
-.repo-url-input.input-valid {
- border-color: #2d6a27;
- box-shadow: 0 0 0 3px rgba(45, 106, 39, 0.15);
-}
-
-.repo-url-error {
- display: block;
- margin-top: 6px;
- font-size: 12px;
- color: #dc3545;
-}
-
-.repo-url-validating {
- display: block;
- margin-top: 6px;
- color: #6c757d;
- font-size: 12px;
- font-style: italic;
-}
-
-.repo-url-success {
- display: block;
- margin-top: 6px;
- color: #2d6a27;
- font-size: 12px;
- font-weight: 500;
-}
-
-.repo-branch-hint code {
- font-size: 12px;
- background: #eaf6e8;
- padding: 1px 4px;
- border-radius: 3px;
+/* Legacy classes from CourseCard that are still rendered but hidden in sidebar mode */
+.optional-label { font-weight: 400; font-size: 0.68rem; color: var(--home-text-muted); }
+.gpu-option, .gpu-option-details, .gpu-option-name, .gpu-option-desc,
+.gpu-options-container, .gpu-selection h6 { /* kept for inline fallback */ }
+.repo-url-input, .repo-url-error, .repo-url-validating, .repo-url-success,
+.repo-url-hint, .repo-url-tooltip, .repo-branch-hint,
+.repo-picker, .repo-picker-trigger, .repo-picker-dropdown, .repo-picker-filter,
+.repo-picker-list, .repo-picker-item, .repo-picker-footer, .repo-picker-empty,
+.repo-picker-name, .repo-picker-private, .repo-picker-chevron,
+.repo-picker-trigger-text, .repo-picker-trigger-placeholder,
+.github-app-prompt { /* kept for potential inline usage */ }
+
+/* Legacy bottom sections are hidden — sidebar replaces them */
+.runtime-container, .launch-section, .shareable-link { display: none; }
+
+/* ---- Responsive ---- */
+@media (max-width: 900px) {
+ .spawn-layout {
+ grid-template-columns: 1fr;
+ }
+ .spawn-sidebar {
+ position: static;
+ }
+}
+@media (max-width: 600px) {
+ #spawn-root { padding: 1rem; }
}
-
-.shareable-link {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-top: 8px;
- padding: 6px 10px;
- background: #f5f5f5;
- border: 1px solid #e0e0e0;
- border-radius: 6px;
- flex-wrap: wrap;
-}
-
-.shareable-link-label {
- font-size: 12px;
- color: #666;
- white-space: nowrap;
-}
-
-.shareable-link-url {
- font-size: 11px;
- color: #2c3e50;
- word-break: break-all;
- flex: 1;
-}
-
-.shareable-link-copy {
- font-size: 11px;
- padding: 2px 8px;
- border: 1px solid #bbb;
- border-radius: 4px;
- background: white;
- cursor: pointer;
- white-space: nowrap;
- color: #444;
-}
-
-.shareable-link-copy:hover {
- background: #e8e8e8;
-}
-
-.repo-url-hint {
- position: relative;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 15px;
- height: 15px;
- margin-left: 6px;
- border-radius: 50%;
- background: #adb5bd;
- color: #fff;
- font-size: 10px;
- font-weight: 700;
- font-style: normal;
- cursor: default;
- vertical-align: middle;
- user-select: none;
-}
-
-.repo-url-tooltip {
- display: none;
- position: absolute;
- bottom: calc(100% + 8px);
- left: 50%;
- transform: translateX(-50%);
- width: 260px;
- padding: 8px 12px;
- background: #2c3e50;
- color: #fff;
- font-size: 12px;
- font-weight: 400;
- border-radius: 6px;
- line-height: 1.5;
- white-space: normal;
- z-index: 100;
- pointer-events: none;
-}
-
-.repo-url-tooltip::after {
- content: '';
- position: absolute;
- top: 100%;
- left: 50%;
- transform: translateX(-50%);
- border: 5px solid transparent;
- border-top-color: #2c3e50;
-}
-
-.repo-url-hint:hover .repo-url-tooltip {
- display: block;
-}
-
-/* ========== Repo Picker (GitHub App) ========== */
-
-.repo-picker {
- margin-bottom: 14px;
- position: relative;
-}
-
-.repo-picker h6 {
- color: #2e3440;
- font-size: 1rem;
- margin-bottom: 10px;
- font-weight: 600;
-}
-
-.repo-picker-trigger {
- display: flex;
- align-items: center;
- padding: 9px 12px;
- border: 1px solid #e5e9f0;
- border-radius: 8px;
- cursor: pointer;
- background: #f8f9fc;
- transition: border-color 0.2s, border-radius 0.15s;
-}
-
-.repo-picker-trigger:hover { border-color: #2c3e50; }
-
-.repo-picker-trigger.open {
- border-color: #2c3e50;
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- border-bottom-color: transparent;
-}
-
-.repo-picker-trigger-text {
- flex: 1;
- font-size: 13px;
- color: #2c3e50;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.repo-picker-trigger-placeholder {
- flex: 1;
- font-size: 13px;
- color: #adb5bd;
-}
-
-.repo-picker-chevron {
- font-size: 11px;
- color: #6c757d;
- margin-left: 8px;
- transition: transform 0.2s;
-}
-
-.repo-picker-trigger.open .repo-picker-chevron { transform: rotate(180deg); }
-
-.repo-picker-dropdown {
- position: absolute;
- top: 100%;
- left: 0;
- right: 0;
- z-index: 10;
- border: 1px solid #2c3e50;
- border-top: none;
- border-radius: 0 0 8px 8px;
- max-height: 210px;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- background: #f8f9fc;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-}
-
-.repo-picker-filter {
- padding: 8px 12px;
- border: none;
- border-bottom: 1px solid #e5e9f0;
- outline: none;
- font-size: 13px;
- color: #2c3e50;
- background: transparent;
- box-sizing: border-box;
- width: 100%;
-}
-
-.repo-picker-filter::placeholder { color: #adb5bd; }
-
-.repo-picker-list {
- overflow-y: auto;
- flex: 1;
-}
-
-.repo-picker-item {
- padding: 7px 12px;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: space-between;
- font-size: 13px;
- color: #2c3e50;
- transition: background 0.15s;
-}
-
-.repo-picker-item:hover { background: #eceff4; }
-.repo-picker-item.selected { background: #e0e6ee; }
-
-.repo-picker-name {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- flex: 1;
-}
-
-.repo-picker-private {
- font-size: 11px;
- color: #6c757d;
- margin-left: 8px;
- flex-shrink: 0;
-}
-
-.repo-picker-empty {
- padding: 10px 12px;
- color: #6c757d;
- font-size: 13px;
-}
-
-.repo-picker-footer {
- padding: 7px 12px;
- border-top: 1px solid #e5e9f0;
- font-size: 12px;
- color: #4c566a;
- text-decoration: none;
- display: block;
-}
-
-.repo-picker-footer:hover { text-decoration: underline; }
-
-/* ========== GitHub App Install Prompt ========== */
-
-.github-app-prompt {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- margin-top: 10px;
- font-size: 13px;
- color: #6c757d;
- text-decoration: none;
-}
-
-.github-app-prompt:hover {
- color: #2d6a27;
- text-decoration: underline;
-}
-
-.github-app-prompt svg { flex-shrink: 0; }
-
-/* ========== Dark Mode — Repo Picker ========== */
-[data-bs-theme="dark"] .repo-picker h6 { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .repo-picker-trigger { background: var(--dark-bg-tertiary) !important; border-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .repo-picker-trigger:hover { border-color: var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .repo-picker-trigger.open { border-color: var(--dark-text-secondary) !important; border-bottom-color: transparent !important; }
-[data-bs-theme="dark"] .repo-picker-trigger-text { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .repo-picker-trigger-placeholder { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .repo-picker-chevron { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .repo-picker-dropdown { background: var(--dark-bg-tertiary) !important; border-color: var(--dark-text-secondary) !important; }
-[data-bs-theme="dark"] .repo-picker-filter { color: var(--dark-text-primary) !important; border-bottom-color: var(--dark-border) !important; }
-[data-bs-theme="dark"] .repo-picker-filter::placeholder { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .repo-picker-item { color: var(--dark-text-primary) !important; }
-[data-bs-theme="dark"] .repo-picker-item:hover { background: #3d444b !important; }
-[data-bs-theme="dark"] .repo-picker-item.selected { background: #3a4550 !important; }
-[data-bs-theme="dark"] .repo-picker-private { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .repo-picker-empty { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .repo-picker-footer { color: var(--dark-text-secondary) !important; border-top-color: var(--dark-border) !important; }
-
-/* ========== Dark Mode — GitHub App Prompt ========== */
-[data-bs-theme="dark"] .github-app-prompt { color: var(--dark-text-muted) !important; }
-[data-bs-theme="dark"] .github-app-prompt:hover { color: #7ec87a !important; }
diff --git a/runtime/hub/frontend/package.json b/runtime/hub/frontend/package.json
index fd809f4..a6ce303 100644
--- a/runtime/hub/frontend/package.json
+++ b/runtime/hub/frontend/package.json
@@ -7,9 +7,11 @@
"dev": "pnpm -r --parallel run dev",
"dev:admin": "pnpm --filter @auplc/admin run dev",
"dev:spawn": "pnpm --filter @auplc/spawn run dev",
+ "dev:home": "pnpm --filter @auplc/home run dev",
"build": "pnpm -r run build",
"build:admin": "pnpm --filter @auplc/admin run build",
"build:spawn": "pnpm --filter @auplc/spawn run build",
+ "build:home": "pnpm --filter @auplc/home run build",
"lint": "pnpm -r run lint",
"clean": "pnpm -r exec rm -rf dist node_modules"
},
diff --git a/runtime/hub/frontend/pnpm-lock.yaml b/runtime/hub/frontend/pnpm-lock.yaml
index c4e9aab..ce3c710 100644
--- a/runtime/hub/frontend/pnpm-lock.yaml
+++ b/runtime/hub/frontend/pnpm-lock.yaml
@@ -132,6 +132,55 @@ importers:
specifier: 'catalog:'
version: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.32.0)
+ apps/home:
+ dependencies:
+ '@auplc/shared':
+ specifier: workspace:*
+ version: link:../../packages/shared
+ react:
+ specifier: 'catalog:'
+ version: 19.2.4
+ react-dom:
+ specifier: 'catalog:'
+ version: 19.2.4(react@19.2.4)
+ devDependencies:
+ '@eslint/js':
+ specifier: 'catalog:'
+ version: 9.39.2
+ '@types/node':
+ specifier: 'catalog:'
+ version: 25.2.3
+ '@types/react':
+ specifier: 'catalog:'
+ version: 19.2.14
+ '@types/react-dom':
+ specifier: 'catalog:'
+ version: 19.2.3(@types/react@19.2.14)
+ '@vitejs/plugin-react':
+ specifier: 'catalog:'
+ version: 5.1.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.32.0))
+ eslint:
+ specifier: 'catalog:'
+ version: 9.39.2(jiti@2.6.1)
+ eslint-plugin-react-hooks:
+ specifier: 'catalog:'
+ version: 5.2.0(eslint@9.39.2(jiti@2.6.1))
+ eslint-plugin-react-refresh:
+ specifier: 'catalog:'
+ version: 0.4.26(eslint@9.39.2(jiti@2.6.1))
+ globals:
+ specifier: 'catalog:'
+ version: 16.5.0
+ typescript:
+ specifier: 'catalog:'
+ version: 5.9.3
+ typescript-eslint:
+ specifier: 'catalog:'
+ version: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
+ vite:
+ specifier: 'catalog:'
+ version: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.32.0)
+
apps/spawn:
dependencies:
'@auplc/shared':
diff --git a/runtime/hub/frontend/templates/home.html b/runtime/hub/frontend/templates/home.html
index 8a0943b..e93f4a1 100644
--- a/runtime/hub/frontend/templates/home.html
+++ b/runtime/hub/frontend/templates/home.html
@@ -2,93 +2,30 @@
{% if announcement_home is string %}
{% set announcement = announcement_home %}
{% endif %}
+
+{%- block title -%}Home - AUP Learning Cloud{%- endblock title -%}
+
+{% block stylesheet %}
+{{ super() }}
+
+{% endblock %}
+
{% block main %}
-
-
JupyterHub home page
-
- {% if allow_named_servers %}
-
Named Servers
-
- In addition to your default server,
- you may have additional
- {% if named_server_limit_per_user > 0 %}{{ named_server_limit_per_user }}{% endif %}
- server(s) with names.
- This allows you to have more than one server running at the same time.
-
- {% set named_spawners = user.all_spawners(include_default=False)|list %}
-
- {% endif %}
-
-{% endblock main %}
+
+
+
+{% endblock %}
+
{% block script %}
- {{ super() }}
-
-{% endblock script %}
+{{ super() }}
+{% endblock %}
diff --git a/runtime/values.yaml b/runtime/values.yaml
index 8cb99fc..d8d6efb 100644
--- a/runtime/values.yaml
+++ b/runtime/values.yaml
@@ -343,23 +343,14 @@ hub:
# If you want to edit the notice on login.html, change here.
mountPath: /usr/local/share/jupyterhub/static/announcement.txt
stringData: |
-
-
Welcome to AUP Learning Cloud!
-
This is a dynamic announcement .
-
My location is on runtime/values.yaml
-
You can edit this via ConfigMap without rebuilding the image.
-
+ Hello, World!
config:
# ---- Hub Core ----
- # JupyterHub:
- # Enable JupyterHub REST API
- # API Documentation: https://jupyterhub.readthedocs.io/en/stable/reference/rest-api.html
- # api_tokens:
- # Configure API tokens for external services
- # Format: token: username
- # It's recommended to use environment variables or secrets to manage tokens
- # Example: "your-secure-api-token-here": "admin-service"
+ JupyterHub:
+ # Always show Home page first, even when a server is already running.
+ # Users can access their running server via the "My Server" button on Home.
+ redirect_to_server: false
Authenticator:
allow_all: true