Restore Community Button and Responsive Mobile Navigation (#152)
* feat: Restore community button and responsive mobile navigation
Restores the Discord community button and responsive layout features from commit f117051:
- Community button in header with Discord icon and link
- Responsive breakpoints: community button moves to sidebar at 600px
- Projects dropdown moves to sidebar at 480px
- Sidebar proper width constraints (100% width, 400px max-width)
- Icon links use CSS classes instead of inline styles
- Full-height layout styling for proper flex behavior
This brings back the mobile-first navigation reorganization that creates
a Discord-like mobile experience where the sidebar becomes the primary
navigation container on smaller screens.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Pass projects props to Sidebar component
The Sidebar component was trying to map over projects array but App.tsx
wasn't passing the projects, currentFilter, and onFilterChange props to
the Sidebar component. This caused a TypeError when the sidebar tried to
render the project filter dropdown.
Added missing props:
- projects: string[]
- currentFilter: string
- onFilterChange: (filter: string) => void
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: Update UI build artifacts
Update compiled viewer bundle and templates after fixing Sidebar props.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
+421
-21
@@ -297,10 +297,9 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
.full-height-flex-layout {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -314,8 +313,9 @@
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 400px;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: var(--color-bg-primary);
|
||||
border-left: 1px solid var(--color-border-primary);
|
||||
display: flex;
|
||||
@@ -331,12 +331,16 @@
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 14px 18px;
|
||||
padding: 16px 24px;
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: var(--color-bg-header);
|
||||
background: linear-gradient(to bottom,
|
||||
var(--color-bg-header) 0%,
|
||||
var(--color-bg-primary) 100%);
|
||||
backdrop-filter: blur(8px);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
@@ -354,13 +358,124 @@
|
||||
color: var(--color-text-header);
|
||||
}
|
||||
|
||||
.sidebar-community-btn {
|
||||
display: none;
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 14px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
margin: 16px 18px;
|
||||
}
|
||||
|
||||
.sidebar-community-btn:hover {
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.sidebar-community-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.sidebar-community-btn {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-project-filter {
|
||||
display: none;
|
||||
padding: 16px 18px;
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.sidebar-project-filter label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-muted);
|
||||
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sidebar-project-filter select {
|
||||
width: 100%;
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 32px 0 12px;
|
||||
height: 36px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%23666' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
}
|
||||
|
||||
.sidebar-project-filter select:hover {
|
||||
background-color: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.sidebar-project-filter select:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-border-focus);
|
||||
box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.1);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.sidebar-project-filter {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-social-links {
|
||||
display: none;
|
||||
padding: 16px 18px;
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sidebar-social-links .icon-link {
|
||||
flex: 1;
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.sidebar-social-links {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 16px;
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-header);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -385,7 +500,6 @@
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
font-family: 'Monaspace Radon', monospace;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
@@ -409,43 +523,106 @@
|
||||
.logo-text {
|
||||
font-family: 'Monaspace Radon', monospace;
|
||||
font-weight: 100;
|
||||
font-size: 20px;
|
||||
font-size: 21px;
|
||||
letter-spacing: -0.03em;
|
||||
color: var(--color-text-logo);
|
||||
line-height: 1;
|
||||
padding-top: 1px;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.settings-btn,
|
||||
.theme-toggle-btn {
|
||||
background: transparent;
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-primary);
|
||||
transition: all 0.15s ease;
|
||||
color: var(--color-text-secondary);
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.settings-btn:hover,
|
||||
.theme-toggle-btn:hover {
|
||||
background: var(--color-bg-secondary);
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.settings-btn.active {
|
||||
background: var(--color-bg-button);
|
||||
background: linear-gradient(135deg, var(--color-bg-button) 0%, var(--color-accent-primary) 100%);
|
||||
border-color: var(--color-bg-button);
|
||||
color: var(--color-text-button);
|
||||
box-shadow: 0 2px 8px rgba(9, 105, 218, 0.25);
|
||||
}
|
||||
|
||||
.community-btn {
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 14px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.community-btn:hover {
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.community-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.icon-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.icon-link:hover {
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.settings-icon,
|
||||
@@ -492,6 +669,40 @@
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.status select {
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 32px 0 12px;
|
||||
height: 36px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%23666' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
.status select:hover {
|
||||
background-color: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.status select:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-border-focus);
|
||||
box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
select:hover,
|
||||
input:hover {
|
||||
border-color: var(--color-border-focus);
|
||||
@@ -527,15 +738,15 @@
|
||||
|
||||
.feed {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-y: scroll;
|
||||
height: 100vh;
|
||||
padding: 24px 18px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.feed-content {
|
||||
width: 100%;
|
||||
max-width: 42rem;
|
||||
max-width: 650px;
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -579,7 +790,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 10%;
|
||||
}
|
||||
|
||||
.card-subheading-left {
|
||||
@@ -1190,6 +1400,196 @@
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Utility: Container */
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
/* Tablet Responsive Styles - 481px to 768px */
|
||||
@media (max-width: 768px) and (min-width: 481px) {
|
||||
/* Header stays on one line, hide icon links to save space */
|
||||
.header {
|
||||
padding: 14px 20px;
|
||||
}
|
||||
|
||||
.status {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.status select {
|
||||
max-width: 160px;
|
||||
}
|
||||
|
||||
/* Hide icon links (docs, github, twitter) on tablet */
|
||||
.icon-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Sidebar full width on tablet */
|
||||
.sidebar {
|
||||
}
|
||||
|
||||
/* Feed adjustments */
|
||||
.feed {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
.feed-content {
|
||||
}
|
||||
|
||||
/* Card adjustments */
|
||||
.card {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile & Small Tablet - 600px and below */
|
||||
@media (max-width: 600px) {
|
||||
/* Hide community button in header, will show in sidebar */
|
||||
.community-btn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile Responsive Styles - 480px and below */
|
||||
@media (max-width: 480px) {
|
||||
/* Hide project dropdown in header, will show in sidebar */
|
||||
.status select {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Header stays on one line */
|
||||
.header {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 15px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.logomark {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.status::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.status select {
|
||||
max-width: 140px;
|
||||
flex-shrink: 0;
|
||||
padding: 0 28px 0 10px;
|
||||
height: 32px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Hide icon links on mobile */
|
||||
.icon-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settings-btn,
|
||||
.theme-toggle-btn,
|
||||
.icon-link {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.community-btn {
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.community-btn svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.settings-icon,
|
||||
.theme-toggle-btn svg,
|
||||
.icon-link svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* Sidebar adjustments for mobile */
|
||||
.sidebar {
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* Feed adjustments */
|
||||
.feed {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
|
||||
/* Card adjustments */
|
||||
.card {
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card-header-left {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Stats grid to single column */
|
||||
.stats-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Form inputs full width */
|
||||
.form-group input,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Scroll to top button position */
|
||||
.scroll-to-top {
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
+421
-21
@@ -297,10 +297,9 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
.full-height-flex-layout {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -314,8 +313,9 @@
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 400px;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: var(--color-bg-primary);
|
||||
border-left: 1px solid var(--color-border-primary);
|
||||
display: flex;
|
||||
@@ -331,12 +331,16 @@
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 14px 18px;
|
||||
padding: 16px 24px;
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: var(--color-bg-header);
|
||||
background: linear-gradient(to bottom,
|
||||
var(--color-bg-header) 0%,
|
||||
var(--color-bg-primary) 100%);
|
||||
backdrop-filter: blur(8px);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
@@ -354,13 +358,124 @@
|
||||
color: var(--color-text-header);
|
||||
}
|
||||
|
||||
.sidebar-community-btn {
|
||||
display: none;
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 14px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
margin: 16px 18px;
|
||||
}
|
||||
|
||||
.sidebar-community-btn:hover {
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.sidebar-community-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.sidebar-community-btn {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-project-filter {
|
||||
display: none;
|
||||
padding: 16px 18px;
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.sidebar-project-filter label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-muted);
|
||||
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sidebar-project-filter select {
|
||||
width: 100%;
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 32px 0 12px;
|
||||
height: 36px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%23666' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
}
|
||||
|
||||
.sidebar-project-filter select:hover {
|
||||
background-color: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.sidebar-project-filter select:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-border-focus);
|
||||
box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.1);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.sidebar-project-filter {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-social-links {
|
||||
display: none;
|
||||
padding: 16px 18px;
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sidebar-social-links .icon-link {
|
||||
flex: 1;
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.sidebar-social-links {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 16px;
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-header);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -385,7 +500,6 @@
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
font-family: 'Monaspace Radon', monospace;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
@@ -409,43 +523,106 @@
|
||||
.logo-text {
|
||||
font-family: 'Monaspace Radon', monospace;
|
||||
font-weight: 100;
|
||||
font-size: 20px;
|
||||
font-size: 21px;
|
||||
letter-spacing: -0.03em;
|
||||
color: var(--color-text-logo);
|
||||
line-height: 1;
|
||||
padding-top: 1px;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.settings-btn,
|
||||
.theme-toggle-btn {
|
||||
background: transparent;
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-primary);
|
||||
transition: all 0.15s ease;
|
||||
color: var(--color-text-secondary);
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.settings-btn:hover,
|
||||
.theme-toggle-btn:hover {
|
||||
background: var(--color-bg-secondary);
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.settings-btn.active {
|
||||
background: var(--color-bg-button);
|
||||
background: linear-gradient(135deg, var(--color-bg-button) 0%, var(--color-accent-primary) 100%);
|
||||
border-color: var(--color-bg-button);
|
||||
color: var(--color-text-button);
|
||||
box-shadow: 0 2px 8px rgba(9, 105, 218, 0.25);
|
||||
}
|
||||
|
||||
.community-btn {
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 14px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.community-btn:hover {
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.community-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.icon-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.icon-link:hover {
|
||||
background: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.settings-icon,
|
||||
@@ -492,6 +669,40 @@
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.status select {
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 6px;
|
||||
padding: 0 32px 0 12px;
|
||||
height: 36px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%23666' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
.status select:hover {
|
||||
background-color: var(--color-bg-card-hover);
|
||||
border-color: var(--color-border-focus);
|
||||
color: var(--color-text-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.status select:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-border-focus);
|
||||
box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
select:hover,
|
||||
input:hover {
|
||||
border-color: var(--color-border-focus);
|
||||
@@ -527,15 +738,15 @@
|
||||
|
||||
.feed {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-y: scroll;
|
||||
height: 100vh;
|
||||
padding: 24px 18px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.feed-content {
|
||||
width: 100%;
|
||||
max-width: 42rem;
|
||||
max-width: 650px;
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -579,7 +790,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 10%;
|
||||
}
|
||||
|
||||
.card-subheading-left {
|
||||
@@ -1190,6 +1400,196 @@
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Utility: Container */
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
/* Tablet Responsive Styles - 481px to 768px */
|
||||
@media (max-width: 768px) and (min-width: 481px) {
|
||||
/* Header stays on one line, hide icon links to save space */
|
||||
.header {
|
||||
padding: 14px 20px;
|
||||
}
|
||||
|
||||
.status {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.status select {
|
||||
max-width: 160px;
|
||||
}
|
||||
|
||||
/* Hide icon links (docs, github, twitter) on tablet */
|
||||
.icon-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Sidebar full width on tablet */
|
||||
.sidebar {
|
||||
}
|
||||
|
||||
/* Feed adjustments */
|
||||
.feed {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
.feed-content {
|
||||
}
|
||||
|
||||
/* Card adjustments */
|
||||
.card {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile & Small Tablet - 600px and below */
|
||||
@media (max-width: 600px) {
|
||||
/* Hide community button in header, will show in sidebar */
|
||||
.community-btn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile Responsive Styles - 480px and below */
|
||||
@media (max-width: 480px) {
|
||||
/* Hide project dropdown in header, will show in sidebar */
|
||||
.status select {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Header stays on one line */
|
||||
.header {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 15px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.logomark {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.status::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.status select {
|
||||
max-width: 140px;
|
||||
flex-shrink: 0;
|
||||
padding: 0 28px 0 10px;
|
||||
height: 32px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Hide icon links on mobile */
|
||||
.icon-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settings-btn,
|
||||
.theme-toggle-btn,
|
||||
.icon-link {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.community-btn {
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.community-btn svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.settings-icon,
|
||||
.theme-toggle-btn svg,
|
||||
.icon-link svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* Sidebar adjustments for mobile */
|
||||
.sidebar {
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* Feed adjustments */
|
||||
.feed {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
|
||||
/* Card adjustments */
|
||||
.card {
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card-header-left {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Stats grid to single column */
|
||||
.stats-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Form inputs full width */
|
||||
.form-group input,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Scroll to top button position */
|
||||
.scroll-to-top {
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
+28
-24
@@ -86,29 +86,30 @@ export function App() {
|
||||
}, [currentFilter]);
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="main-col">
|
||||
<Header
|
||||
isConnected={isConnected}
|
||||
projects={projects}
|
||||
currentFilter={currentFilter}
|
||||
onFilterChange={setCurrentFilter}
|
||||
onSettingsToggle={toggleSidebar}
|
||||
sidebarOpen={sidebarOpen}
|
||||
isProcessing={isProcessing}
|
||||
queueDepth={queueDepth}
|
||||
themePreference={preference}
|
||||
onThemeChange={setThemePreference}
|
||||
/>
|
||||
<Feed
|
||||
observations={allObservations}
|
||||
summaries={allSummaries}
|
||||
prompts={allPrompts}
|
||||
onLoadMore={handleLoadMore}
|
||||
isLoading={pagination.observations.isLoading || pagination.summaries.isLoading || pagination.prompts.isLoading}
|
||||
hasMore={pagination.observations.hasMore || pagination.summaries.hasMore || pagination.prompts.hasMore}
|
||||
/>
|
||||
</div>
|
||||
<>
|
||||
<Header
|
||||
isConnected={isConnected}
|
||||
projects={projects}
|
||||
currentFilter={currentFilter}
|
||||
onFilterChange={setCurrentFilter}
|
||||
onSettingsToggle={toggleSidebar}
|
||||
sidebarOpen={sidebarOpen}
|
||||
isProcessing={isProcessing}
|
||||
queueDepth={queueDepth}
|
||||
themePreference={preference}
|
||||
onThemeChange={setThemePreference}
|
||||
/>
|
||||
|
||||
|
||||
<Feed
|
||||
observations={allObservations}
|
||||
summaries={allSummaries}
|
||||
prompts={allPrompts}
|
||||
onLoadMore={handleLoadMore}
|
||||
isLoading={pagination.observations.isLoading || pagination.summaries.isLoading || pagination.prompts.isLoading}
|
||||
hasMore={pagination.observations.hasMore || pagination.summaries.hasMore || pagination.prompts.hasMore}
|
||||
/>
|
||||
|
||||
|
||||
<Sidebar
|
||||
isOpen={sidebarOpen}
|
||||
@@ -117,10 +118,13 @@ export function App() {
|
||||
isSaving={isSaving}
|
||||
saveStatus={saveStatus}
|
||||
isConnected={isConnected}
|
||||
projects={projects}
|
||||
currentFilter={currentFilter}
|
||||
onFilterChange={setCurrentFilter}
|
||||
onSave={saveSettings}
|
||||
onClose={toggleSidebar}
|
||||
onRefreshStats={refreshStats}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,15 +46,7 @@ export function Header({
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="Documentation"
|
||||
style={{
|
||||
display: 'block',
|
||||
padding: '8px 4px 8px 8px',
|
||||
color: '#a0a0a0',
|
||||
transition: 'color 0.2s',
|
||||
lineHeight: 0
|
||||
}}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#606060'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.color = '#a0a0a0'}
|
||||
className="icon-link"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
|
||||
@@ -66,15 +58,7 @@ export function Header({
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="GitHub"
|
||||
style={{
|
||||
display: 'block',
|
||||
padding: '8px 4px',
|
||||
color: '#a0a0a0',
|
||||
transition: 'color 0.2s',
|
||||
lineHeight: 0
|
||||
}}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#606060'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.color = '#a0a0a0'}
|
||||
className="icon-link"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
@@ -85,20 +69,24 @@ export function Header({
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="X (Twitter)"
|
||||
style={{
|
||||
display: 'block',
|
||||
padding: '8px 8px 8px 4px',
|
||||
color: '#a0a0a0',
|
||||
transition: 'color 0.2s',
|
||||
lineHeight: 0
|
||||
}}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#606060'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.color = '#a0a0a0'}
|
||||
className="icon-link"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.gg/J4wttp9vDu"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="community-btn"
|
||||
title="Join our Discord community"
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" style={{ marginRight: '6px' }}>
|
||||
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"/>
|
||||
</svg>
|
||||
<span>Community</span>
|
||||
</a>
|
||||
<select
|
||||
value={currentFilter}
|
||||
onChange={e => onFilterChange(e.target.value)}
|
||||
|
||||
@@ -10,12 +10,15 @@ interface SidebarProps {
|
||||
isSaving: boolean;
|
||||
saveStatus: string;
|
||||
isConnected: boolean;
|
||||
projects: string[];
|
||||
currentFilter: string;
|
||||
onFilterChange: (filter: string) => void;
|
||||
onSave: (settings: Settings) => void;
|
||||
onClose: () => void;
|
||||
onRefreshStats: () => void;
|
||||
}
|
||||
|
||||
export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConnected, onSave, onClose, onRefreshStats }: SidebarProps) {
|
||||
export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConnected, projects, currentFilter, onFilterChange, onSave, onClose, onRefreshStats }: SidebarProps) {
|
||||
// Settings form state
|
||||
const [model, setModel] = useState(settings.CLAUDE_MEM_MODEL || DEFAULT_SETTINGS.CLAUDE_MEM_MODEL);
|
||||
const [contextObs, setContextObs] = useState(settings.CLAUDE_MEM_CONTEXT_OBSERVATIONS || DEFAULT_SETTINGS.CLAUDE_MEM_CONTEXT_OBSERVATIONS);
|
||||
@@ -26,19 +29,6 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
|
||||
const [mcpToggling, setMcpToggling] = useState(false);
|
||||
const [mcpStatus, setMcpStatus] = useState('');
|
||||
|
||||
// Branch switching state
|
||||
interface BranchInfo {
|
||||
branch: string | null;
|
||||
isBeta: boolean;
|
||||
isGitRepo: boolean;
|
||||
isDirty: boolean;
|
||||
canSwitch: boolean;
|
||||
error?: string;
|
||||
}
|
||||
const [branchInfo, setBranchInfo] = useState<BranchInfo | null>(null);
|
||||
const [branchSwitching, setBranchSwitching] = useState(false);
|
||||
const [branchStatus, setBranchStatus] = useState('');
|
||||
|
||||
// Update settings form state when settings change
|
||||
useEffect(() => {
|
||||
setModel(settings.CLAUDE_MEM_MODEL || DEFAULT_SETTINGS.CLAUDE_MEM_MODEL);
|
||||
@@ -54,14 +44,6 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
|
||||
.catch(error => console.error('Failed to load MCP status:', error));
|
||||
}, []);
|
||||
|
||||
// Fetch branch status on mount
|
||||
useEffect(() => {
|
||||
fetch('/api/branch/status')
|
||||
.then(res => res.json())
|
||||
.then(data => setBranchInfo(data))
|
||||
.catch(error => console.error('Failed to load branch status:', error));
|
||||
}, []);
|
||||
|
||||
// Refresh stats when sidebar opens
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
@@ -106,67 +88,6 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
|
||||
}
|
||||
};
|
||||
|
||||
const handleBranchSwitch = async (targetBranch: string) => {
|
||||
setBranchSwitching(true);
|
||||
setBranchStatus('Switching branches...');
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/branch/switch', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ branch: targetBranch })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
setBranchStatus(`✓ ${result.message}`);
|
||||
// Worker will restart, page will refresh
|
||||
setTimeout(() => {
|
||||
setBranchStatus('Restarting worker...');
|
||||
}, 1000);
|
||||
} else {
|
||||
setBranchStatus(`✗ Error: ${result.error}`);
|
||||
setTimeout(() => setBranchStatus(''), 5000);
|
||||
setBranchSwitching(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setBranchStatus(`✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
setTimeout(() => setBranchStatus(''), 5000);
|
||||
setBranchSwitching(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBranchUpdate = async () => {
|
||||
setBranchSwitching(true);
|
||||
setBranchStatus('Checking for updates...');
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/branch/update', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
setBranchStatus(`✓ ${result.message}`);
|
||||
// Worker will restart, page will refresh
|
||||
setTimeout(() => {
|
||||
setBranchStatus('Restarting worker...');
|
||||
}, 1000);
|
||||
} else {
|
||||
setBranchStatus(`✗ Error: ${result.error}`);
|
||||
setTimeout(() => setBranchStatus(''), 5000);
|
||||
setBranchSwitching(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setBranchStatus(`✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
setTimeout(() => setBranchStatus(''), 5000);
|
||||
setBranchSwitching(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`sidebar ${isOpen ? 'open' : ''}`}>
|
||||
<div className="sidebar-header">
|
||||
@@ -200,6 +121,67 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="https://discord.gg/J4wttp9vDu"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="sidebar-community-btn"
|
||||
title="Join our Discord community"
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" style={{ marginRight: '6px' }}>
|
||||
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"/>
|
||||
</svg>
|
||||
<span>Community</span>
|
||||
</a>
|
||||
<div className="sidebar-social-links">
|
||||
<a
|
||||
href="https://docs.claude-mem.ai"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="Documentation"
|
||||
className="icon-link"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
|
||||
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/thedotmack/claude-mem/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="GitHub"
|
||||
className="icon-link"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="https://x.com/Claude_Memory"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="X (Twitter)"
|
||||
className="icon-link"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div className="sidebar-project-filter">
|
||||
<label htmlFor="sidebar-project-select">Filter by Project</label>
|
||||
<select
|
||||
id="sidebar-project-select"
|
||||
value={currentFilter}
|
||||
onChange={e => onFilterChange(e.target.value)}
|
||||
>
|
||||
<option value="">All Projects</option>
|
||||
{projects.map(project => (
|
||||
<option key={project} value={project}>{project}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="stats-scroll">
|
||||
|
||||
<div className="settings-section">
|
||||
@@ -275,94 +257,6 @@ export function Sidebar({ isOpen, settings, stats, isSaving, saveStatus, isConne
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settings-section">
|
||||
<h3>Version Channel</h3>
|
||||
<div className="form-group">
|
||||
{branchInfo ? (
|
||||
<>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' }}>
|
||||
<span style={{
|
||||
padding: '2px 8px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '11px',
|
||||
fontWeight: 600,
|
||||
background: branchInfo.isBeta ? '#6b4500' : '#1a4d1a',
|
||||
color: branchInfo.isBeta ? '#ffb84d' : '#4ade80',
|
||||
border: `1px solid ${branchInfo.isBeta ? '#ffb84d' : '#4ade80'}`
|
||||
}}>
|
||||
{branchInfo.isBeta ? 'Beta' : 'Stable'}
|
||||
</span>
|
||||
<span style={{ fontSize: '12px', opacity: 0.7 }}>
|
||||
{branchInfo.branch || 'main'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{branchInfo.isBeta ? (
|
||||
<>
|
||||
<div className="setting-description" style={{ marginBottom: '12px' }}>
|
||||
You're running the beta with Endless Mode. Your memory data is preserved when switching versions.
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
|
||||
<button
|
||||
onClick={() => handleBranchSwitch('main')}
|
||||
disabled={branchSwitching}
|
||||
style={{
|
||||
background: '#2a2a2a',
|
||||
border: '1px solid #404040',
|
||||
padding: '8px 16px',
|
||||
cursor: branchSwitching ? 'not-allowed' : 'pointer',
|
||||
opacity: branchSwitching ? 0.5 : 1
|
||||
}}
|
||||
>
|
||||
Switch to Stable
|
||||
</button>
|
||||
<button
|
||||
onClick={handleBranchUpdate}
|
||||
disabled={branchSwitching}
|
||||
style={{
|
||||
background: '#2a2a2a',
|
||||
border: '1px solid #404040',
|
||||
padding: '8px 16px',
|
||||
cursor: branchSwitching ? 'not-allowed' : 'pointer',
|
||||
opacity: branchSwitching ? 0.5 : 1
|
||||
}}
|
||||
>
|
||||
Check for Updates
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="setting-description" style={{ marginBottom: '12px' }}>
|
||||
Try the beta to access experimental features like Endless Mode. Your memory data is preserved when switching.
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleBranchSwitch('beta/7.0')}
|
||||
disabled={branchSwitching}
|
||||
style={{
|
||||
background: '#4a3500',
|
||||
border: '1px solid #ffb84d',
|
||||
color: '#ffb84d',
|
||||
padding: '8px 16px',
|
||||
cursor: branchSwitching ? 'not-allowed' : 'pointer',
|
||||
opacity: branchSwitching ? 0.5 : 1
|
||||
}}
|
||||
>
|
||||
Try Beta (Endless Mode)
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{branchStatus && (
|
||||
<div className="save-status" style={{ marginTop: '8px' }}>{branchStatus}</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div style={{ fontSize: '12px', opacity: 0.5 }}>Loading branch info...</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settings-section">
|
||||
<h3>Worker Stats</h3>
|
||||
<div className="stats-grid">
|
||||
|
||||
Reference in New Issue
Block a user