diff --git a/nostr/commit-signatures.jsonl b/nostr/commit-signatures.jsonl
index 66e1d7b..9c62fa2 100644
--- a/nostr/commit-signatures.jsonl
+++ b/nostr/commit-signatures.jsonl
@@ -41,3 +41,4 @@
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771669826,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","user badge is a universal hyperlink to the profile page"]],"content":"Signed commit: user badge is a universal hyperlink to the profile page","id":"973a406714e586037d81cca323024ff5e2cc1fbaeda8846f6f2994c3829c4fe0","sig":"e7a58526a3786fc1b9ab1f957c87c13a42d3c2cc95effcf4ce4f4710e01ecc45fcff3ca542c5fa223961d7b99fe336a2851c133aebe3bfc1a591ffe1c34b221a"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771680916,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix profile feeds"]],"content":"Signed commit: fix profile feeds","id":"33f33d76f6c79e68fdab72c8fdfc7e1f0ecc53a879a7f5aef02481f17384a06f","sig":"8f9056eab081d66edb693eb35a2e400368aa897746b97ca40a216604dc14ee877eb7f4f16dd2eeac257025b3adfe82e23734c7c106b6cec5e8a1ca661c872cc5"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771681068,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","remove landing page search bar"]],"content":"Signed commit: remove landing page search bar","id":"71087b100ce14a1f2eb975be23450c62143ee11a8fd0429ec7440bfea1751741","sig":"695c704503ed1397f6871770ad55822a17a503bcfb71a0db7b3f2477cacb0e767b9f122075b0216f884e41e175c0ac9f9e3d743086a2aa34db4aa1207c900703"}
+{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771682804,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","repo page refactor"]],"content":"Signed commit: repo page refactor","id":"9ad7610ff7aa61d62d3772d6ae7c0589cda8ff95cd7a60b81c84ba879e0f9d8a","sig":"8918f36d426d352a6787543daaa044cf51855632e2257f29cc18bb87db31d61c877b525113e21045d3bc135376e1c0574454e28bd409d3135bcb80079bc11947"}
diff --git a/src/lib/components/RepoHeaderEnhanced.svelte b/src/lib/components/RepoHeaderEnhanced.svelte
index a28526d..f975b4a 100644
--- a/src/lib/components/RepoHeaderEnhanced.svelte
+++ b/src/lib/components/RepoHeaderEnhanced.svelte
@@ -1,6 +1,7 @@
-
-
diff --git a/src/lib/components/RepoTabs.svelte b/src/lib/components/RepoTabs.svelte
index 87063c3..f6d5684 100644
--- a/src/lib/components/RepoTabs.svelte
+++ b/src/lib/components/RepoTabs.svelte
@@ -1,4 +1,5 @@
-
-
diff --git a/src/lib/components/UserBadge.svelte b/src/lib/components/UserBadge.svelte
index 3a1c659..e35e7b2 100644
--- a/src/lib/components/UserBadge.svelte
+++ b/src/lib/components/UserBadge.svelte
@@ -9,9 +9,10 @@
interface Props {
pubkey: string;
disableLink?: boolean;
+ inline?: boolean;
}
- let { pubkey, disableLink = false }: Props = $props();
+ let { pubkey, disableLink = false, inline = false }: Props = $props();
// Convert pubkey to npub for navigation (reactive)
const profileUrl = $derived.by(() => {
@@ -183,7 +184,21 @@
}
-{#if disableLink}
+{#if inline}
+ {#if disableLink}
+ {truncateHandle(userProfile?.name) || getShortNpub()}
+ {:else}
+ {
+ e.stopPropagation();
+ }}
+ >
+ {truncateHandle(userProfile?.name) || getShortNpub()}
+
+ {/if}
+{:else if disableLink}
{#if userProfile?.picture}

@@ -249,6 +264,18 @@
white-space: nowrap;
}
+ .user-badge-inline {
+ display: inline;
+ color: var(--accent);
+ text-decoration: none;
+ font-weight: 500;
+ font-size: inherit;
+ }
+
+ .user-badge-inline:hover {
+ text-decoration: underline;
+ }
+
/* Hide name on narrow screens, show only picture */
@media (max-width: 768px) {
.user-badge-name {
@@ -257,6 +284,9 @@
.user-badge {
padding: 0.25rem;
+ width: fit-content;
+ display: inline-flex;
+ flex-shrink: 0;
}
}
diff --git a/src/lib/services/git/repo-manager.ts b/src/lib/services/git/repo-manager.ts
index c4c79e8..0e89f85 100644
--- a/src/lib/services/git/repo-manager.ts
+++ b/src/lib/services/git/repo-manager.ts
@@ -3,7 +3,7 @@
* Handles repo provisioning, syncing, and NIP-34 integration
*/
-import { existsSync, mkdirSync, writeFileSync, statSync, readFileSync } from 'fs';
+import { existsSync, mkdirSync, statSync } from 'fs';
import { join } from 'path';
import { readdir, readFile } from 'fs/promises';
import { spawn } from 'child_process';
diff --git a/src/lib/styles/components.css b/src/lib/styles/components.css
new file mode 100644
index 0000000..3f342f9
--- /dev/null
+++ b/src/lib/styles/components.css
@@ -0,0 +1,737 @@
+/* Component Styles - Shared across components */
+
+/* RepoHeaderEnhanced Component */
+.repo-header {
+ padding: 0.75rem 1rem;
+ background: var(--card-bg, #ffffff);
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ position: sticky;
+ top: 0;
+ z-index: 100;
+}
+
+@media (max-width: 768px) {
+ .repo-header {
+ padding: 0.5rem 0.75rem;
+ }
+}
+
+.repo-header-top {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 1rem;
+ margin-bottom: 0.5rem;
+}
+
+@media (max-width: 768px) {
+ .repo-header-top {
+ margin-bottom: 0.25rem;
+ gap: 0.5rem;
+ }
+}
+
+.repo-title-section {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+}
+
+.repo-name {
+ margin: 0;
+ font-size: 1.25rem;
+ font-weight: 600;
+ color: var(--text-primary, #1a1a1a);
+ word-break: break-word;
+}
+
+.repo-badge {
+ display: inline-block;
+ padding: 0.125rem 0.5rem;
+ font-size: 0.75rem;
+ border-radius: 0.25rem;
+ font-weight: 500;
+}
+
+.repo-badge.private {
+ background: var(--error-bg, #fee);
+ color: var(--error-text, #c00);
+}
+
+.bookmark-button {
+ padding: 0.25rem;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+}
+
+.bookmark-button.bookmarked img {
+ filter: brightness(0) saturate(100%) invert(67%) sepia(93%) saturate(1352%) hue-rotate(358deg) brightness(102%) contrast(106%);
+}
+
+.repo-header-actions {
+ display: flex;
+ gap: 0.5rem;
+ flex-shrink: 0;
+}
+
+.menu-button-wrapper {
+ position: relative;
+}
+
+.menu-button,
+.clone-button,
+.branch-button,
+.copy-clone-button {
+ position: relative;
+ padding: 0.5rem;
+ background: transparent;
+ border: 1px solid var(--border-color, #e0e0e0);
+ border-radius: 0.375rem;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ font-size: 0.875rem;
+ color: var(--text-primary, #1a1a1a);
+ transition: all 0.2s ease;
+}
+
+.menu-button:hover,
+.clone-button:hover,
+.branch-button:hover,
+.copy-clone-button:hover {
+ background: var(--bg-secondary, #f5f5f5);
+ border-color: var(--accent, #007bff);
+}
+
+.icon {
+ width: 18px;
+ height: 18px;
+ flex-shrink: 0;
+ /* Theme-aware icon colors */
+ filter: brightness(0) saturate(100%) invert(1); /* Default white for dark themes */
+ opacity: 1;
+}
+
+/* Light theme: black icon */
+:global([data-theme="light"]) .icon {
+ filter: brightness(0) saturate(100%); /* Black in light theme */
+ opacity: 1;
+}
+
+/* Dark themes: white icon */
+:global([data-theme="dark"]) .icon,
+:global([data-theme="black"]) .icon {
+ filter: brightness(0) saturate(100%) invert(1); /* White in dark themes */
+ opacity: 1;
+}
+
+.repo-description {
+ margin: 0.5rem 0;
+ font-size: 0.875rem;
+ color: var(--text-secondary, #666);
+ line-height: 1.5;
+}
+
+@media (max-width: 768px) {
+ .repo-description {
+ margin: 0.25rem 0;
+ }
+}
+
+.repo-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ align-items: center;
+ margin-top: 0.75rem;
+ font-size: 0.875rem;
+}
+
+@media (max-width: 768px) {
+ .repo-meta {
+ margin-top: 0.5rem;
+ gap: 0.75rem;
+ }
+}
+
+.repo-owner {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.owner-badge-button {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.25rem;
+ transition: background 0.2s ease;
+ color: inherit;
+ font-size: inherit;
+}
+
+.owner-badge-button:hover {
+ background: var(--bg-secondary, #f5f5f5);
+}
+
+.owner-badge-button .meta-label {
+ color: var(--text-secondary, #666);
+}
+
+.owner-badge-count {
+ padding: 0.125rem 0.375rem;
+ background: var(--bg-secondary, #f5f5f5);
+ border-radius: 0.75rem;
+ font-size: 0.75rem;
+ font-weight: 500;
+ color: var(--text-secondary, #666);
+}
+
+.owner-menu-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 99;
+}
+
+.owner-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ margin-top: 0.25rem;
+ background: var(--card-bg, #ffffff);
+ border: 1px solid var(--border-color, #e0e0e0);
+ border-radius: 0.375rem;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ z-index: 100;
+ min-width: 250px;
+ max-width: 400px;
+}
+
+.owner-menu-header {
+ padding: 0.75rem 1rem;
+ font-weight: 600;
+ font-size: 0.875rem;
+ color: var(--text-primary, #1a1a1a);
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+}
+
+.owner-menu-list {
+ max-height: 300px;
+ overflow-y: auto;
+}
+
+.owner-menu-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.5rem;
+ padding: 0.75rem 1rem;
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ transition: background 0.2s ease;
+}
+
+.owner-menu-item:last-child {
+ border-bottom: none;
+}
+
+.owner-menu-item:hover {
+ background: var(--bg-secondary, #f5f5f5);
+}
+
+.owner-menu-item :global(.user-badge) {
+ flex: 1;
+ min-width: 0;
+}
+
+.owner-menu-item :global(a.user-badge) {
+ text-decoration: none;
+ color: inherit;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.owner-menu-item :global(a.user-badge:hover) {
+ text-decoration: none;
+ opacity: 0.8;
+}
+
+.owner-menu-badge {
+ padding: 0.125rem 0.5rem;
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ font-weight: 500;
+ flex-shrink: 0;
+}
+
+.owner-menu-badge.owner {
+ background: var(--accent-bg, #e7f3ff);
+ color: var(--accent, #007bff);
+}
+
+.owner-menu-badge.maintainer {
+ background: var(--bg-secondary, #f5f5f5);
+ color: var(--text-secondary, #666);
+}
+
+.meta-label {
+ color: var(--text-secondary, #666);
+}
+
+.repo-clone,
+.repo-branch {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.clone-menu,
+.branch-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ margin-top: 0.25rem;
+ background: var(--card-bg, #ffffff);
+ border: 1px solid var(--border-color, #e0e0e0);
+ border-radius: 0.375rem;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ z-index: 10;
+ min-width: 200px;
+ max-width: 90vw;
+ max-height: 300px;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+@media (max-width: 768px) {
+ .clone-menu {
+ max-width: calc(100vw - 1.5rem);
+ min-width: min(200px, calc(100vw - 1.5rem));
+ }
+
+ .clone-url-item {
+ font-size: 0.8125rem;
+ padding: 0.5rem;
+ }
+}
+
+.clone-url-item,
+.branch-item {
+ display: block;
+ width: 100%;
+ padding: 0.5rem 0.75rem;
+ text-align: left;
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ cursor: pointer;
+ font-size: 0.875rem;
+ color: var(--text-primary, #1a1a1a);
+ word-break: break-all;
+ overflow-wrap: break-word;
+ white-space: normal;
+ line-height: 1.4;
+ box-sizing: border-box;
+ overflow: hidden;
+ word-wrap: break-word;
+}
+
+.branch-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ word-break: normal;
+}
+
+.branch-item.active {
+ background: var(--bg-secondary, #f5f5f5);
+ font-weight: 600;
+}
+
+.branch-badge {
+ font-size: 0.75rem;
+ padding: 0.125rem 0.375rem;
+ background: var(--bg-secondary, #f5f5f5);
+ border-radius: 0.25rem;
+ color: var(--text-secondary, #666);
+}
+
+.clone-url-item:last-child,
+.branch-item:last-child {
+ border-bottom: none;
+}
+
+.clone-url-item:hover,
+.branch-item:hover {
+ background: var(--bg-secondary, #f5f5f5);
+}
+
+.delete-branch-button {
+ padding: 0.25rem 0.5rem;
+ background: var(--error-text, #dc2626);
+ color: #ffffff;
+ border: none;
+ border-radius: 0.25rem;
+ cursor: pointer;
+ font-size: 0.875rem;
+}
+
+.delete-branch-button:hover {
+ background: var(--error-hover, #c82333);
+}
+
+.more-menu-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 99;
+}
+
+.more-menu {
+ position: absolute;
+ top: calc(100% + 0.25rem);
+ right: 0;
+ background: var(--card-bg, #ffffff);
+ border: 1px solid var(--border-color, #e0e0e0);
+ border-radius: 0.375rem;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ z-index: 100;
+ min-width: 240px;
+ max-width: min(90vw, 360px);
+}
+
+/* On mobile, ensure menu doesn't overflow screen */
+@media (max-width: 768px) {
+ .more-menu {
+ right: 0;
+ max-width: calc(100vw - 2rem);
+ min-width: 220px;
+ }
+}
+
+/* On very small screens, position menu to not overflow */
+@media (max-width: 480px) {
+ .more-menu {
+ right: 0;
+ max-width: calc(100vw - 1rem);
+ min-width: auto;
+ }
+}
+
+.menu-item {
+ display: block;
+ width: 100%;
+ padding: 0.5rem 0.75rem;
+ text-align: left;
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ cursor: pointer;
+ font-size: 0.875rem;
+ color: var(--text-primary, #1a1a1a);
+}
+
+.menu-item:last-child {
+ border-bottom: none;
+}
+
+.menu-item:hover:not(:disabled) {
+ background: var(--bg-secondary, #f5f5f5);
+}
+
+.menu-item:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+
+.menu-item-danger {
+ color: var(--error-text, #dc2626);
+}
+
+.menu-item-danger:hover:not(:disabled) {
+ background: var(--error-bg, #fee);
+}
+
+/* Icon button - icon-only button style */
+.icon-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0.5rem;
+ min-width: auto;
+ width: auto;
+}
+
+.icon-button .icon {
+ width: 18px;
+ height: 18px;
+ margin: 0;
+}
+
+@media (min-width: 768px) {
+ .repo-header {
+ padding: 1rem 1.5rem;
+ }
+
+ .repo-name {
+ font-size: 1.5rem;
+ }
+
+ .repo-description {
+ font-size: 1rem;
+ }
+}
+
+/* RepoTabs Component */
+.repo-tabs {
+ position: relative;
+ background: var(--card-bg, #ffffff);
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.mobile-tabs-menu-button {
+ display: none;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 0.5rem;
+ padding: 0.75rem 1rem;
+ width: 100%;
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ cursor: pointer;
+ font-size: 0.875rem;
+ color: var(--text-primary, #1a1a1a);
+ font-weight: 500;
+}
+
+.mobile-tabs-menu-button .icon {
+ width: 20px;
+ height: 20px;
+ flex-shrink: 0;
+}
+
+.current-tab-label {
+ flex: 1;
+ text-align: left;
+}
+
+.tabs-container {
+ display: none;
+ gap: 0;
+}
+
+.tab-button {
+ padding: 0.75rem 1rem;
+ background: transparent;
+ border: none;
+ border-bottom: 2px solid transparent;
+ cursor: pointer;
+ font-size: 0.875rem;
+ color: var(--text-secondary, #666);
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ white-space: nowrap;
+ transition: all 0.2s ease;
+ position: relative;
+}
+
+.tab-button:hover {
+ color: var(--text-primary, #1a1a1a);
+ background: var(--bg-secondary, #f5f5f5);
+}
+
+.tab-button.active {
+ color: var(--accent, #007bff);
+ border-bottom-color: var(--accent, #007bff);
+ font-weight: 600;
+}
+
+.tab-icon {
+ width: 16px;
+ height: 16px;
+ flex-shrink: 0;
+ /* Theme-aware icon colors */
+ filter: brightness(0) saturate(100%) invert(1); /* Default white for dark themes */
+ opacity: 1;
+}
+
+/* Light theme: black icon */
+:global([data-theme="light"]) .tab-icon {
+ filter: brightness(0) saturate(100%); /* Black in light theme */
+ opacity: 1;
+}
+
+/* Dark themes: white icon */
+:global([data-theme="dark"]) .tab-icon,
+:global([data-theme="black"]) .tab-icon {
+ filter: brightness(0) saturate(100%) invert(1); /* White in dark themes */
+ opacity: 1;
+}
+
+/* Active tab: match text color (accent color) */
+.tab-button.active .tab-icon {
+ filter: brightness(0) saturate(100%) invert(48%) sepia(79%) saturate(2476%) hue-rotate(200deg) brightness(118%) contrast(119%);
+ opacity: 1;
+}
+
+.tab-label {
+ display: none;
+}
+
+.tab-count {
+ padding: 0.125rem 0.375rem;
+ background: var(--bg-secondary, #f5f5f5);
+ border-radius: 0.75rem;
+ font-size: 0.75rem;
+ font-weight: 500;
+ color: var(--text-secondary, #666);
+}
+
+.tab-button.active .tab-count {
+ background: var(--accent, #007bff);
+ color: var(--accent-text, #ffffff);
+}
+
+.mobile-menu-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ padding: 0.75rem 1rem;
+ width: 100%;
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ cursor: pointer;
+ font-size: 0.875rem;
+ color: var(--text-primary, #1a1a1a);
+ font-weight: 500;
+}
+
+.mobile-menu-button .icon {
+ width: 20px;
+ height: 20px;
+}
+
+@media (max-width: 480px) {
+ .mobile-menu-button .current-tab-label {
+ display: none;
+ }
+
+ .mobile-menu-button {
+ justify-content: center;
+ }
+}
+
+.mobile-menu-button .icon {
+ width: 18px;
+ height: 18px;
+}
+
+.current-tab-label {
+ flex: 1;
+ text-align: left;
+}
+
+.mobile-tabs-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ right: 0;
+ background: var(--card-bg, #ffffff);
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ z-index: 50;
+ max-height: 70vh;
+ overflow-y: auto;
+ min-width: 200px;
+ max-width: 100vw;
+}
+
+.mobile-tab-item {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.875rem 1rem;
+ width: 100%;
+ min-width: 0;
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ cursor: pointer;
+ font-size: 0.875rem;
+ color: var(--text-primary, #1a1a1a);
+ text-align: left;
+ transition: background 0.2s ease;
+ box-sizing: border-box;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+}
+
+.mobile-tab-item span {
+ flex: 1;
+ min-width: 0;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+}
+
+.mobile-tab-item:hover {
+ background: var(--bg-secondary, #f5f5f5);
+}
+
+.mobile-tab-item.active {
+ background: var(--bg-secondary, #f5f5f5);
+ color: var(--accent, #007bff);
+ font-weight: 600;
+}
+
+.mobile-tab-item .tab-count {
+ margin-left: auto;
+}
+
+@media (min-width: 768px) {
+ .tabs-container {
+ display: flex;
+ }
+
+ .mobile-tabs-menu-button,
+ .mobile-tabs-menu {
+ display: none;
+ }
+
+ .tab-label {
+ display: inline;
+ }
+}
+
+@media (max-width: 767px) {
+ .tabs-container {
+ display: none;
+ }
+
+ .mobile-tabs-menu-button {
+ display: flex;
+ }
+}
diff --git a/src/lib/styles/repo.css b/src/lib/styles/repo.css
new file mode 100644
index 0000000..9031a36
--- /dev/null
+++ b/src/lib/styles/repo.css
@@ -0,0 +1,1879 @@
+/* Repository Page Styles */
+
+.container {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.repo-metadata-section {
+ padding: 0.75rem 1rem;
+ background: var(--card-bg, #ffffff);
+ border-bottom: 1px solid var(--border-color, #e0e0e0);
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ align-items: center;
+ font-size: 0.875rem;
+ width: 100%;
+ max-width: 100%;
+ overflow: hidden;
+ box-sizing: border-box;
+}
+
+@media (min-width: 768px) {
+ .repo-metadata-section {
+ padding: 1rem 1.5rem;
+ }
+}
+
+@media (max-width: 768px) {
+ .repo-clone-urls {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .clone-url-wrapper {
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .clone-url {
+ max-width: calc(100% - 2rem);
+ }
+}
+
+.repo-banner {
+ width: 100%;
+ height: 200px;
+ overflow: hidden;
+ background: var(--bg-secondary);
+ margin-bottom: 0;
+ position: relative;
+ display: none; /* Hidden on mobile by default */
+}
+
+.desktop-only {
+ display: none; /* Hidden on mobile */
+}
+
+@media (min-width: 768px) {
+ .desktop-only {
+ display: block; /* Show on desktop */
+ }
+
+ .repo-banner {
+ display: block; /* Show on desktop */
+ }
+}
+
+.repo-banner::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(
+ to bottom,
+ transparent 0%,
+ transparent 60%,
+ var(--card-bg) 100%
+ );
+ z-index: 1;
+ pointer-events: none;
+}
+
+.repo-banner::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(
+ to right,
+ transparent 0%,
+ transparent 85%,
+ var(--card-bg) 100%
+ );
+ z-index: 1;
+ pointer-events: none;
+}
+
+.repo-banner img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+}
+
+.repo-banner img[src=""],
+.repo-banner img:not([src]) {
+ display: none;
+}
+
+/* Responsive design for smaller screens */
+.mobile-toggle-button {
+ display: none; /* Hidden by default on desktop */
+ padding: 0.5rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ cursor: pointer;
+ transition: background 0.2s;
+ align-items: center;
+ justify-content: center;
+}
+
+.mobile-toggle-button .icon-inline {
+ width: 16px;
+ height: 16px;
+}
+
+.mobile-toggle-button:hover {
+ background: var(--bg-primary);
+}
+
+.hide-on-mobile {
+ display: none;
+}
+
+@media (max-width: 768px) {
+ .repo-banner {
+ height: 150px;
+ }
+
+ /* Mobile toggle button visible on narrow screens */
+ .mobile-toggle-button {
+ display: inline-flex;
+ }
+
+ /* File tree and editor area full width and height on mobile */
+ .file-tree {
+ width: 100%;
+ flex: 1 1 auto;
+ min-height: 0;
+ flex-basis: auto;
+ }
+
+ .editor-area {
+ width: 100%;
+ flex: 1;
+ min-height: 0;
+ max-height: none;
+ }
+
+ /* Hide the appropriate view based on toggle state */
+ .file-tree.hide-on-mobile {
+ display: none !important;
+ }
+
+ .editor-area.hide-on-mobile {
+ display: none !important;
+ }
+
+ /* Stack layout on mobile */
+ .repo-layout {
+ flex-direction: column;
+ flex: 1;
+ min-height: 0;
+ }
+
+ /* Editor header wraps on mobile */
+ .editor-header {
+ flex-wrap: wrap;
+ gap: 0.25rem;
+ padding: 0.5rem 0.75rem;
+ align-items: flex-start;
+ }
+
+ .file-path {
+ flex: 1 1 100%;
+ min-width: 0;
+ word-break: break-all;
+ margin-bottom: 0;
+ padding-bottom: 0;
+ }
+
+ .editor-actions {
+ flex: 1 1 auto;
+ justify-content: flex-end;
+ min-width: 0;
+ gap: 0.5rem;
+ }
+
+ /* Modal responsive styles */
+ .modal {
+ width: 95%;
+ max-width: 95%;
+ max-height: 90vh;
+ margin: 1rem;
+ padding: 1rem;
+ overflow-y: auto;
+ }
+
+ .modal h3 {
+ font-size: 1.25rem;
+ margin-bottom: 1rem;
+ }
+
+ .modal label {
+ display: block;
+ margin-bottom: 0.75rem;
+ font-size: 0.9rem;
+ }
+
+ .modal input,
+ .modal textarea,
+ .modal select {
+ width: 100%;
+ font-size: 0.9rem;
+ padding: 0.5rem;
+ }
+
+ .modal-actions {
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
+ .modal-actions button {
+ width: 100%;
+ padding: 0.75rem;
+ }
+
+ /* Issue and PR lists responsive */
+ .issue-item, .pr-item {
+ padding: 0.5rem;
+ }
+
+ .issue-header, .pr-header {
+ flex-wrap: wrap;
+ gap: 0.25rem;
+ }
+
+ .issue-subject, .pr-subject {
+ font-size: 0.9rem;
+ word-break: break-word;
+ }
+
+ .issue-meta, .pr-meta {
+ flex-wrap: wrap;
+ font-size: 0.7rem;
+ gap: 0.5rem;
+ }
+
+ .issue-actions {
+ flex-direction: column;
+ width: 100%;
+ }
+
+ .issue-action-btn {
+ width: 100%;
+ padding: 0.5rem;
+ }
+
+ /* Sidebars responsive */
+ .prs-sidebar, .issues-sidebar {
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .prs-header, .issues-header {
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ }
+
+ .create-pr-button, .create-issue-button {
+ width: 100%;
+ padding: 0.75rem;
+ }
+
+ /* File tree responsive */
+ .file-tree-header {
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ }
+
+ .file-tree-actions {
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ }
+
+ .create-file-button {
+ font-size: 0.85rem;
+ padding: 0.5rem 0.75rem;
+ }
+
+ /* Back button responsive */
+ .back-btn {
+ width: 100%;
+ margin-bottom: 1rem;
+ padding: 0.75rem;
+ }
+
+ .non-maintainer-notice {
+ font-size: 0.7rem;
+ flex: 1 1 100%;
+ order: 2;
+ margin-top: 0;
+ padding-top: 0.25rem;
+ line-height: 1.3;
+ }
+}
+
+/* Desktop: always show both file tree and editor */
+@media (min-width: 769px) {
+ .file-tree.hide-on-mobile {
+ display: flex;
+ }
+
+ .editor-area.hide-on-mobile {
+ display: flex;
+ }
+
+ .mobile-toggle-button {
+ display: none;
+ }
+}
+
+.fork-badge {
+ padding: 0.25rem 0.5rem;
+ background: var(--accent);
+ color: var(--accent-text, #ffffff);
+ border-radius: 4px;
+ font-size: 0.85rem;
+ margin-left: 0.5rem;
+ font-weight: 600;
+ border: 1px solid var(--accent);
+}
+
+.fork-badge a {
+ color: var(--accent-text, #ffffff);
+ text-decoration: none;
+ font-weight: 600;
+}
+
+.fork-badge a:hover {
+ text-decoration: underline;
+ opacity: 1;
+}
+
+.repo-language {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ font-size: 0.875rem;
+ color: var(--text-secondary);
+ font-weight: 500;
+}
+
+.repo-language .icon-inline {
+ opacity: 0.9;
+}
+
+.repo-topics {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ align-items: center;
+}
+
+.topic-tag {
+ padding: 0.25rem 0.5rem;
+ background: var(--accent);
+ color: var(--accent-text, #ffffff);
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ font-weight: 600;
+ border: 1px solid var(--accent);
+}
+
+.repo-website {
+ margin-top: 0.5rem;
+ font-size: 0.875rem;
+}
+
+.repo-website a {
+ color: var(--link-color);
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+}
+
+.repo-website a:hover {
+ text-decoration: underline;
+}
+
+.repo-clone-urls {
+ margin-top: 0.5rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.75rem;
+ width: 100%;
+ max-width: 100%;
+ overflow: hidden;
+}
+
+.clone-label {
+ color: var(--text-muted);
+ font-weight: 500;
+}
+
+.clone-url-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+ max-width: 100%;
+ min-width: 0;
+}
+
+.clone-url {
+ padding: 0.125rem 0.375rem;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.25rem;
+ font-family: 'IBM Plex Mono', monospace;
+ font-size: 0.75rem;
+ color: var(--text-primary);
+ word-break: break-all;
+ overflow-wrap: break-word;
+ white-space: normal;
+ max-width: 100%;
+ min-width: 0;
+ flex: 1 1 auto;
+ box-sizing: border-box;
+}
+
+.clone-more {
+ color: var(--text-muted);
+ font-size: 0.75rem;
+}
+
+.repo-contributors {
+ margin-top: 0.75rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.75rem;
+}
+
+.contributors-label {
+ font-size: 0.875rem;
+ color: var(--text-muted);
+ font-weight: 500;
+}
+
+.contributors-list {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.contributor-item {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ text-decoration: none;
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.5rem;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ transition: all 0.2s ease;
+}
+
+.contributor-item:hover {
+ border-color: var(--accent);
+ background: var(--card-bg);
+}
+
+.contributor-item.contributor-owner {
+ background: var(--accent-light);
+ border: 2px solid var(--accent);
+ font-weight: 600;
+ box-shadow: 0 0 0 1px var(--accent-light);
+}
+
+.contributor-item.contributor-owner:hover {
+ background: var(--accent-light);
+ border-color: var(--accent-hover);
+ box-shadow: 0 0 0 2px var(--accent-light);
+}
+
+.contributor-badge {
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.25rem;
+ font-size: 0.7rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ white-space: nowrap;
+ letter-spacing: 0.05em;
+ border: 1px solid transparent;
+ /* Ensure minimum size for touch targets */
+ min-height: 1.5rem;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.contributor-badge.owner {
+ /* High contrast colors for all themes */
+ background: var(--bg-tertiary, #4a5568);
+ color: var(--text-primary, #ffffff);
+ border-color: var(--border-color, #2d3748);
+}
+
+.contributor-badge.maintainer {
+ /* High contrast colors for all themes */
+ background: var(--success-bg, #22543d);
+ color: var(--success-text, #ffffff);
+ border-color: var(--border-color, #1a202c);
+}
+
+.repo-view {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.repo-layout {
+ flex: 1;
+ display: flex;
+ overflow: hidden;
+}
+
+.file-tree {
+ width: 300px;
+ min-width: 300px;
+ max-width: 300px;
+ border-right: 1px solid var(--border-color);
+ background: var(--bg-secondary);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ flex: 0 0 300px; /* Fixed width, don't grow or shrink */
+ min-height: 0; /* Allow flex child to shrink */
+}
+
+.file-tree-header {
+ padding: 1rem;
+ border-bottom: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.file-tree-header h2 {
+ margin: 0;
+ font-size: 1rem;
+ color: var(--text-primary);
+}
+
+.back-button {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.875rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.25rem;
+ cursor: pointer;
+ color: var(--text-primary);
+ transition: background 0.2s ease;
+}
+
+.back-button:hover {
+ background: var(--bg-secondary);
+}
+
+.file-list {
+ list-style: none;
+ padding: 0.5rem 0;
+ margin: 0;
+ overflow-y: auto;
+ overflow-x: hidden;
+ flex: 1;
+ min-height: 0; /* Allows flex child to shrink below content size */
+ width: 100%; /* Fill horizontal space */
+}
+
+.file-item {
+ margin: 0;
+}
+
+.file-button {
+ width: 100%;
+ padding: 0.5rem 1rem;
+ text-align: left;
+ background: none;
+ border: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.875rem;
+ color: var(--text-primary);
+ font-weight: 500;
+ transition: background 0.2s ease, color 0.2s ease;
+ box-sizing: border-box;
+}
+
+.file-button:hover {
+ background: var(--bg-tertiary);
+ color: var(--text-primary);
+}
+
+.file-item.selected .file-button {
+ background: var(--accent);
+ color: var(--accent-text, #ffffff);
+ font-weight: 600;
+}
+
+.file-item.selected .file-button:hover {
+ background: var(--accent-hover);
+ color: var(--accent-text, #ffffff);
+}
+
+.file-size {
+ color: var(--text-secondary);
+ font-size: 0.75rem;
+ margin-left: auto;
+ opacity: 0.9;
+}
+
+.file-item.selected .file-size {
+ color: var(--accent-text, #ffffff);
+ opacity: 0.9;
+}
+
+.editor-area {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ background: var(--card-bg);
+ max-height: calc(200vh - 400px); /* Twice the original height */
+}
+
+.editor-header {
+ padding: 0.75rem 1rem;
+ border-bottom: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.file-path {
+ font-family: 'IBM Plex Mono', monospace;
+ font-size: 0.875rem;
+ color: var(--text-primary);
+}
+
+.editor-actions {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ flex-wrap: wrap;
+}
+
+.unsaved-indicator {
+ color: var(--warning-text);
+ font-size: 0.875rem;
+}
+
+.non-maintainer-notice {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ white-space: normal;
+ line-height: 1.4;
+}
+
+.save-button {
+ padding: 0.5rem 1rem;
+ background: var(--button-primary);
+ color: var(--accent-text, #ffffff);
+ border: none;
+ border-radius: 0.25rem;
+ cursor: pointer;
+ font-size: 0.875rem;
+ font-family: 'IBM Plex Serif', serif;
+ transition: background 0.2s ease;
+}
+
+.save-button:hover:not(:disabled) {
+ background: var(--button-primary-hover);
+}
+
+.save-button:disabled {
+ background: var(--text-muted);
+ cursor: not-allowed;
+ opacity: 0.6;
+}
+
+.editor-container {
+ flex: 1;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ min-height: 0; /* Allows flex child to shrink below content size */
+}
+
+.empty-state {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--text-muted);
+}
+
+.loading {
+ padding: 2rem;
+ text-align: center;
+ color: var(--text-muted);
+}
+
+.error {
+ background: var(--error-bg);
+ color: var(--error-text);
+ padding: 1rem;
+ margin: 1rem;
+ border-radius: 0.5rem;
+ border: 1px solid var(--error-text);
+}
+
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+}
+
+.modal {
+ background: var(--card-bg);
+ padding: 2rem;
+ border-radius: 0.5rem;
+ min-width: 400px;
+ max-width: 600px;
+ border: 1px solid var(--border-color);
+}
+
+.modal h3 {
+ margin: 0 0 1rem 0;
+ color: var(--text-primary);
+}
+
+.verification-modal {
+ max-width: 800px;
+ min-width: 600px;
+ max-height: 90vh;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.modal-header {
+ flex-shrink: 0;
+ margin-bottom: 1rem;
+}
+
+.modal-body {
+ flex: 1;
+ overflow-y: auto;
+ min-height: 0;
+}
+
+.verification-instructions {
+ color: var(--text-secondary);
+ margin-bottom: 1rem;
+ line-height: 1.6;
+}
+
+.verification-instructions code {
+ background: var(--bg-secondary);
+ padding: 0.125rem 0.375rem;
+ border-radius: 0.25rem;
+ font-family: monospace;
+ color: var(--accent);
+}
+
+.verification-file-content {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.375rem;
+ overflow: hidden;
+ margin-bottom: 1rem;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ min-height: 0;
+}
+
+.file-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.75rem 1rem;
+ background: var(--bg-tertiary);
+ border-bottom: 1px solid var(--border-color);
+}
+
+.filename {
+ font-family: monospace;
+ font-weight: 500;
+ color: var(--text-primary);
+}
+
+.file-actions {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.copy-button,
+.download-button {
+ padding: 0.375rem 0.75rem;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.25rem;
+ font-size: 0.875rem;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.copy-button:hover,
+.download-button:hover {
+ background: var(--bg-secondary);
+ border-color: var(--accent);
+}
+
+.file-content {
+ margin: 0;
+ padding: 1rem;
+ overflow-x: auto;
+ overflow-y: auto;
+ background: var(--bg-primary);
+ max-height: 400px;
+}
+
+.file-content code {
+ font-family: 'Courier New', monospace;
+ font-size: 0.875rem;
+ color: var(--text-primary);
+ white-space: pre;
+}
+
+.modal label {
+ display: block;
+ margin-bottom: 1rem;
+ color: var(--text-primary);
+}
+
+.modal input,
+.modal textarea,
+.modal select {
+ width: 100%;
+ padding: 0.5rem;
+ border: 1px solid var(--input-border);
+ border-radius: 0.25rem;
+ font-family: 'IBM Plex Serif', serif;
+ background: var(--input-bg);
+ color: var(--text-primary);
+ margin-top: 0.5rem;
+}
+
+.modal input:focus,
+.modal textarea:focus,
+.modal select:focus {
+ outline: none;
+ border-color: var(--input-focus);
+}
+
+.modal-actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: 1rem;
+}
+
+.cancel-button {
+ padding: 0.5rem 1rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.25rem;
+ cursor: pointer;
+ color: var(--text-primary);
+ font-family: 'IBM Plex Serif', serif;
+ transition: background 0.2s ease;
+}
+
+.cancel-button:hover {
+ background: var(--bg-secondary);
+}
+
+/* File tree actions */
+.file-tree-actions {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.create-file-button, .create-tag-button {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.75rem;
+ background: var(--button-primary);
+ color: white;
+ border: none;
+ border-radius: 0.25rem;
+ cursor: pointer;
+ font-family: 'IBM Plex Serif', serif;
+ transition: background 0.2s ease;
+}
+
+.create-file-button:hover, .create-tag-button:hover {
+ background: var(--button-primary-hover);
+}
+
+.delete-file-button {
+ padding: 0.25rem;
+ background: none;
+ border: none;
+ cursor: pointer;
+ font-size: 0.75rem;
+ opacity: 0.6;
+}
+
+.delete-file-button:hover {
+ opacity: 1;
+}
+
+.file-item {
+ display: flex;
+ align-items: center;
+}
+
+.file-item .file-button {
+ flex: 1;
+}
+
+/* History sidebar */
+.history-sidebar, .tags-sidebar {
+ width: 300px;
+ border-right: 1px solid var(--border-color);
+ background: var(--bg-secondary);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.history-header, .tags-header {
+ padding: 1rem;
+ border-bottom: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.history-header h2, .tags-header h2 {
+ margin: 0;
+ font-size: 1rem;
+ color: var(--text-primary);
+}
+
+.refresh-button {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.75rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.25rem;
+ cursor: pointer;
+ color: var(--text-primary);
+ transition: background 0.2s ease;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.375rem;
+}
+
+.refresh-button:hover {
+ background: var(--bg-secondary);
+}
+
+.refresh-button .icon-inline {
+ width: 0.875rem;
+ height: 0.875rem;
+}
+
+.commit-list, .tag-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ overflow-y: auto;
+ flex: 1;
+}
+
+.commit-item, .tag-item {
+ border-bottom: 1px solid var(--border-color);
+}
+
+.commit-button {
+ width: 100%;
+ padding: 0.75rem 1rem;
+ text-align: left;
+ background: none;
+ border: none;
+ cursor: pointer;
+ display: block;
+}
+
+.commit-button:hover {
+ background: var(--bg-tertiary);
+}
+
+.commit-item.selected .commit-button {
+ background: var(--accent);
+ color: var(--accent-text, #ffffff);
+}
+
+.commit-hash {
+ font-family: 'IBM Plex Mono', monospace;
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ margin-bottom: 0.25rem;
+}
+
+.commit-message {
+ font-weight: 500;
+ margin-bottom: 0.25rem;
+ color: var(--text-primary);
+}
+
+.commit-meta {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ display: flex;
+ gap: 1rem;
+}
+
+.tag-item {
+ padding: 0.75rem 1rem;
+}
+
+.tag-name {
+ font-weight: 500;
+ color: var(--link-color);
+ margin-bottom: 0.25rem;
+}
+
+.tag-hash {
+ font-family: 'IBM Plex Mono', monospace;
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ margin-bottom: 0.25rem;
+}
+
+.tag-message {
+ font-size: 0.875rem;
+ color: var(--text-muted);
+}
+
+/* Diff view */
+.diff-view {
+ flex: 1;
+ overflow: auto;
+ padding: 1rem;
+}
+
+.diff-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 1rem;
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.diff-header h3 {
+ margin: 0;
+ color: var(--text-primary);
+}
+
+.close-button {
+ padding: 0.25rem 0.5rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.25rem;
+ cursor: pointer;
+ font-size: 1.25rem;
+ line-height: 1;
+ color: var(--text-primary);
+ transition: background 0.2s ease;
+}
+
+.close-button:hover {
+ background: var(--bg-secondary);
+}
+
+.diff-file {
+ margin-bottom: 2rem;
+}
+
+.diff-file-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.5rem;
+ background: var(--bg-secondary);
+ border-radius: 0.25rem;
+ margin-bottom: 0.5rem;
+}
+
+.diff-file-name {
+ font-family: 'IBM Plex Mono', monospace;
+ font-weight: 500;
+ color: var(--text-primary);
+}
+
+.diff-stats {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.additions {
+ color: var(--success-text);
+}
+
+.deletions {
+ color: var(--error-text);
+}
+
+.diff-content {
+ background: var(--bg-tertiary);
+ color: var(--text-primary);
+ padding: 1rem;
+ border-radius: 0.25rem;
+ overflow-x: auto;
+ font-size: 0.875rem;
+ line-height: 1.5;
+ border: 1px solid var(--border-color);
+}
+
+.diff-content code {
+ font-family: 'IBM Plex Mono', monospace;
+ white-space: pre;
+}
+
+.read-only-editor {
+ height: 100%;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 1.5rem;
+ min-height: 0; /* Allows flex child to shrink below content size */
+}
+
+.read-only-editor :global(.hljs) {
+ padding: 1rem;
+ background: var(--bg-tertiary);
+ color: var(--text-primary);
+ border-radius: 4px;
+ overflow-x: auto;
+ margin: 0;
+ border: 1px solid var(--border-color);
+}
+
+.read-only-editor :global(pre) {
+ margin: 0;
+ padding: 0;
+}
+
+.read-only-editor :global(code) {
+ font-family: 'IBM Plex Mono', monospace;
+ font-size: 14px;
+ line-height: 1.5;
+ display: block;
+ white-space: pre;
+}
+
+.readme-section {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: hidden;
+}
+
+.readme-header {
+ padding: 1rem;
+ border-bottom: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-shrink: 0;
+}
+
+.readme-header h3 {
+ margin: 0;
+ font-size: 1.25rem;
+ color: var(--text-primary);
+}
+
+.readme-actions {
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+}
+
+.discussions-content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow-y: auto;
+ overflow-x: hidden;
+ background: var(--card-bg);
+ min-height: 0; /* Allows flex child to shrink below content size */
+}
+
+.discussions-header {
+ padding: 1rem 1.5rem;
+ border-bottom: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-shrink: 0;
+}
+
+@media (max-width: 767px) {
+ .discussions-header {
+ padding: 0.75rem 1rem;
+ }
+}
+
+.discussions-actions {
+ display: flex;
+ gap: 0.75rem;
+ align-items: center;
+}
+
+.btn-secondary {
+ padding: 0.5rem 1rem;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: 0.25rem;
+ color: var(--text-primary);
+ cursor: pointer;
+ font-size: 0.875rem;
+ transition: background 0.2s;
+}
+
+.btn-secondary:hover:not(:disabled) {
+ background: var(--bg-tertiary);
+}
+
+.btn-secondary:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.discussions-header h2 {
+ margin: 0;
+ font-size: 1.25rem;
+ color: var(--text-primary);
+}
+
+.discussion-item {
+ padding: 1rem 1.5rem;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.discussion-header {
+ margin-bottom: 0.5rem;
+}
+
+.discussion-header h3 {
+ margin: 0 0 0.25rem 0;
+ font-size: 1.1rem;
+ color: var(--text-primary);
+}
+
+.discussion-meta {
+ display: flex;
+ gap: 1rem;
+ font-size: 0.875rem;
+ color: var(--text-muted);
+}
+
+.discussion-type {
+ padding: 0.125rem 0.5rem;
+ border-radius: 0.25rem;
+ background: var(--bg-secondary);
+ font-weight: 500;
+}
+
+.discussion-body {
+ margin-top: 0.5rem;
+ color: var(--text-primary);
+ white-space: pre-wrap;
+}
+
+.discussion-title-row {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.expand-button {
+ background: none;
+ border: none;
+ color: var(--text-muted);
+ cursor: pointer;
+ font-size: 0.75rem;
+ padding: 0.25rem 0.5rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 1.5rem;
+ transition: color 0.2s;
+}
+
+.expand-button:hover {
+ color: var(--text-primary);
+}
+
+.comment-count {
+ font-weight: 500;
+}
+
+.btn-small {
+ padding: 0.25rem 0.75rem;
+ font-size: 0.875rem;
+}
+
+.comments-section {
+ margin-top: 1rem;
+ padding-top: 1rem;
+ border-top: 1px solid var(--border-color);
+}
+
+.comments-section h4 {
+ margin: 0 0 0.75rem 0;
+ font-size: 0.9rem;
+ color: var(--text-muted);
+ font-weight: 500;
+}
+
+.comment-item {
+ padding: 0.75rem 0;
+ border-bottom: 1px solid var(--border-light);
+}
+
+.comment-item:last-child {
+ border-bottom: none;
+}
+
+.comment-meta {
+ display: flex;
+ gap: 0.75rem;
+ align-items: center;
+ margin-bottom: 0.5rem;
+ font-size: 0.875rem;
+ color: var(--text-muted);
+}
+
+.comment-content {
+ color: var(--text-primary);
+ white-space: pre-wrap;
+ line-height: 1.5;
+}
+
+.referenced-event {
+ margin-bottom: 1rem;
+ padding: 0.75rem;
+ background: var(--bg-primary);
+ border-left: 3px solid var(--border-color);
+ border-radius: 0.5rem;
+ font-size: 0.875rem;
+}
+
+:global([data-theme="light"]) .referenced-event {
+ background: #e8e8e8;
+}
+
+:global([data-theme="dark"]) .referenced-event {
+ background: rgba(0, 0, 0, 0.2);
+}
+
+:global([data-theme="black"]) .referenced-event {
+ background: #0a0a0a;
+}
+
+.referenced-event-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+
+.referenced-event-time {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+}
+
+.referenced-event-content {
+ color: var(--text-secondary);
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ line-height: 1.5;
+ max-height: 10rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.nostr-link-event {
+ margin: 0.75rem 0;
+ padding: 0.75rem;
+ background: var(--bg-primary);
+ border-left: 3px solid var(--border-color);
+ border-radius: 0.5rem;
+ font-size: 0.875rem;
+}
+
+:global([data-theme="light"]) .nostr-link-event {
+ background: #e8e8e8;
+}
+
+:global([data-theme="dark"]) .nostr-link-event {
+ background: rgba(0, 0, 0, 0.2);
+}
+
+:global([data-theme="black"]) .nostr-link-event {
+ background: #0a0a0a;
+}
+
+.nostr-link-event-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+
+.nostr-link-event-time {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+}
+
+.nostr-link-event-content {
+ color: var(--text-secondary);
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ line-height: 1.5;
+ max-height: 10rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.nostr-link-placeholder {
+ color: var(--text-muted);
+ font-style: italic;
+}
+
+.nested-replies {
+ margin-left: 2rem;
+ margin-top: 0.75rem;
+ padding-left: 1rem;
+ border-left: 2px solid var(--border-light);
+}
+
+.nested-comment {
+ margin-top: 0.75rem;
+}
+
+.readme-content {
+ flex: 1;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 1.5rem;
+ min-height: 0; /* Allows flex child to shrink below content size */
+}
+
+.readme-content.markdown {
+ padding: 1.5rem;
+}
+
+.readme-content.markdown :global(h1),
+.readme-content.markdown :global(h2),
+.readme-content.markdown :global(h3),
+.readme-content.markdown :global(h4),
+.readme-content.markdown :global(h5),
+.readme-content.markdown :global(h6) {
+ margin-top: 1.5rem;
+ margin-bottom: 0.75rem;
+ color: var(--text-primary);
+}
+
+.readme-content.markdown :global(p) {
+ margin-bottom: 1rem;
+ line-height: 1.6;
+}
+
+.readme-content.markdown :global(code) {
+ background: var(--bg-secondary);
+ padding: 0.2rem 0.4rem;
+ border-radius: 3px;
+ font-family: 'IBM Plex Mono', monospace;
+ font-size: 0.9em;
+}
+
+.readme-content.markdown :global(pre) {
+ background: var(--bg-secondary);
+ padding: 1rem;
+ border-radius: 4px;
+ overflow-x: auto;
+ border: 1px solid var(--border-light);
+ margin: 1rem 0;
+}
+
+.readme-content.markdown :global(pre code) {
+ background: none;
+ padding: 0;
+}
+
+.readme-content :global(.hljs) {
+ background: var(--bg-secondary);
+ padding: 1rem;
+ border-radius: 4px;
+ overflow-x: auto;
+ border: 1px solid var(--border-light);
+}
+
+.readme-content :global(pre.hljs) {
+ margin: 1rem 0;
+}
+
+/* Documentation */
+.docs-content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ background: var(--card-bg);
+}
+
+.documentation-body {
+ flex: 1;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 1.5rem;
+ min-height: 0;
+}
+
+.documentation-body :global(h1),
+.documentation-body :global(h2),
+.documentation-body :global(h3),
+.documentation-body :global(h4),
+.documentation-body :global(h5),
+.documentation-body :global(h6) {
+ margin-top: 1.5rem;
+ margin-bottom: 0.75rem;
+ color: var(--text-primary);
+}
+
+.documentation-body :global(p) {
+ margin-bottom: 1rem;
+ line-height: 1.6;
+}
+
+.documentation-body :global(code) {
+ background: var(--bg-secondary);
+ padding: 0.2rem 0.4rem;
+ border-radius: 3px;
+ font-family: 'IBM Plex Mono', monospace;
+ font-size: 0.9em;
+}
+
+.documentation-body :global(pre) {
+ background: var(--bg-secondary);
+ padding: 1rem;
+ border-radius: 4px;
+ overflow-x: auto;
+ border: 1px solid var(--border-light);
+ margin: 1rem 0;
+}
+
+.documentation-body :global(pre code) {
+ background: none;
+ padding: 0;
+}
+
+.documentation-body :global(.hljs) {
+ background: var(--bg-secondary);
+ padding: 1rem;
+ border-radius: 4px;
+ overflow-x: auto;
+ border: 1px solid var(--border-light);
+}
+
+.documentation-body :global(pre.hljs) {
+ margin: 1rem 0;
+}
+
+/* Issues and PRs */
+.issues-sidebar, .prs-sidebar {
+ width: 300px;
+ border-right: 1px solid var(--border-color);
+ background: var(--bg-secondary);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.issues-header, .prs-header {
+ padding: 1rem;
+ border-bottom: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.issues-header h2, .prs-header h2 {
+ margin: 0;
+ font-size: 1rem;
+ color: var(--text-primary);
+}
+
+.create-issue-button, .create-pr-button {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.75rem;
+ background: var(--button-primary);
+ color: white;
+ border: none;
+ border-radius: 0.25rem;
+ cursor: pointer;
+ font-family: 'IBM Plex Serif', serif;
+ transition: background 0.2s ease;
+}
+
+.create-issue-button:hover, .create-pr-button:hover {
+ background: var(--button-primary-hover);
+}
+
+.issue-list, .pr-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ overflow-y: auto;
+ flex: 1;
+}
+
+.issue-actions {
+ display: flex;
+ gap: 0.5rem;
+ margin-top: 0.5rem;
+ flex-wrap: wrap;
+}
+
+.issue-action-btn {
+ padding: 0.4rem 0.8rem;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 0.85rem;
+ font-family: 'IBM Plex Serif', serif;
+ transition: background 0.2s ease;
+}
+
+.issue-action-btn:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
+
+.issue-action-btn.close-btn {
+ background: var(--error-text, #dc3545);
+ color: white;
+}
+
+.issue-action-btn.close-btn:hover:not(:disabled) {
+ background: var(--error-hover, #c82333);
+}
+
+.issue-action-btn.resolve-btn {
+ background: var(--success-text, #28a745);
+ color: white;
+}
+
+.issue-action-btn.resolve-btn:hover:not(:disabled) {
+ background: var(--success-hover, #218838);
+}
+
+.issue-action-btn.reopen-btn {
+ background: var(--accent, #007bff);
+ color: white;
+}
+
+.issue-action-btn.reopen-btn:hover:not(:disabled) {
+ background: var(--accent-hover, #0056b3);
+}
+
+.issue-item, .pr-item {
+ padding: 0.75rem 1rem;
+ border-bottom: 1px solid var(--border-color);
+ cursor: pointer;
+ transition: background 0.2s ease;
+}
+
+.issue-item:hover, .pr-item:hover {
+ background: var(--bg-tertiary);
+}
+
+.issue-header, .pr-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin-bottom: 0.25rem;
+}
+
+.issue-status, .pr-status {
+ padding: 0.125rem 0.5rem;
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ font-weight: 500;
+ text-transform: uppercase;
+}
+
+.issue-status.open, .pr-status.open {
+ background: var(--accent);
+ color: var(--accent-text, #ffffff);
+ font-weight: 600;
+}
+
+.issue-status.closed, .pr-status.closed {
+ background: var(--error-bg);
+ color: var(--error-text);
+}
+
+.issue-status.resolved, .pr-status.merged {
+ background: var(--success-bg);
+ color: var(--success-text);
+}
+
+.issue-subject, .pr-subject {
+ font-weight: 500;
+ flex: 1;
+ color: var(--text-primary);
+}
+
+.issue-meta, .pr-meta {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ display: flex;
+ gap: 0.75rem;
+}
+
+.pr-commit {
+ font-family: 'IBM Plex Mono', monospace;
+}
+
+.issues-content, .prs-content {
+ flex: 1;
+ overflow-y: auto;
+ padding: 2rem;
+ background: var(--card-bg);
+}
+
+.issue-detail, .pr-detail {
+ margin-bottom: 2rem;
+ padding-bottom: 2rem;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.issue-detail h3, .pr-detail h3 {
+ margin: 0 0 0.5rem 0;
+ font-size: 1.5rem;
+ color: var(--text-primary);
+}
+
+.issue-meta-detail, .pr-meta-detail {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ margin-bottom: 1rem;
+ font-size: 0.875rem;
+ color: var(--text-muted);
+}
+
+.issue-body, .pr-body {
+ line-height: 1.6;
+ color: var(--text-primary);
+}
+
+.verification-badge {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.125rem 0.25rem;
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ flex-shrink: 0;
+}
+
+.verification-badge.loading {
+ opacity: 0.6;
+}
+
+.verification-badge.verified {
+ color: var(--success-text, #10b981);
+}
+
+.verification-badge.unverified {
+ color: var(--error-text, #f59e0b);
+}
+
+.verification-badge .icon-inline {
+ width: 1em;
+ height: 1em;
+ margin: 0;
+}
+
+.icon-inline {
+ width: 1em;
+ height: 1em;
+ vertical-align: middle;
+ display: inline-block;
+ margin-right: 0.25rem;
+ /* Make icons visible on dark backgrounds by inverting to light */
+ filter: brightness(0) saturate(100%) invert(1);
+}
+
+.icon-small {
+ width: 16px;
+ height: 16px;
+ vertical-align: middle;
+ /* Make icons visible on dark backgrounds by inverting to light */
+ filter: brightness(0) saturate(100%) invert(1);
+}
+
+/* Theme-aware icon colors */
+
+.verification-badge.verified .icon-inline {
+ /* Green checkmark for verified */
+ filter: brightness(0) saturate(100%) invert(48%) sepia(79%) saturate(2476%) hue-rotate(86deg) brightness(118%) contrast(119%);
+}
+
+.verification-badge.unverified .icon-inline {
+ /* Orange/yellow warning for unverified */
+ filter: brightness(0) saturate(100%) invert(67%) sepia(93%) saturate(1352%) hue-rotate(358deg) brightness(102%) contrast(106%);
+}
+
+.file-button .icon-inline {
+ filter: brightness(0) saturate(100%) invert(1);
+ opacity: 0.7;
+}
+
+.delete-file-button .icon-small {
+ /* Red for delete button */
+ filter: brightness(0) saturate(100%) invert(27%) sepia(51%) saturate(2878%) hue-rotate(346deg) brightness(104%) contrast(97%);
+}
diff --git a/src/routes/repos/+page.svelte b/src/routes/repos/+page.svelte
index 80185dd..92d4b29 100644
--- a/src/routes/repos/+page.svelte
+++ b/src/routes/repos/+page.svelte
@@ -37,7 +37,7 @@
let mostFavoritedRepos = $state
>([]);
let loadingMostFavorited = $state(false);
let mostFavoritedPage = $state(0);
- let mostFavoritedCache: { data: typeof mostFavoritedRepos; timestamp: number } | null = null;
+ let mostFavoritedCache = $state<{ data: typeof mostFavoritedRepos; timestamp: number } | null>(null);
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
import { DEFAULT_NOSTR_RELAYS } from '$lib/config.js';
@@ -962,6 +962,7 @@
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
+ line-clamp: 2;
-webkit-box-orient: vertical;
}
diff --git a/src/routes/repos/[npub]/[repo]/+page.svelte b/src/routes/repos/[npub]/[repo]/+page.svelte
index 9e27f56..e957f5d 100644
--- a/src/routes/repos/[npub]/[repo]/+page.svelte
+++ b/src/routes/repos/[npub]/[repo]/+page.svelte
@@ -9,6 +9,7 @@
import RepoHeaderEnhanced from '$lib/components/RepoHeaderEnhanced.svelte';
import RepoTabs from '$lib/components/RepoTabs.svelte';
import NostrLinkRenderer from '$lib/components/NostrLinkRenderer.svelte';
+ import '$lib/styles/repo.css';
import { getPublicKeyWithNIP07, isNIP07Available, signEventWithNIP07 } from '$lib/services/nostr/nip07-signer.js';
import { NostrClient } from '$lib/services/nostr/nostr-client.js';
import { DEFAULT_NOSTR_RELAYS, DEFAULT_NOSTR_SEARCH_RELAYS, combineRelays } from '$lib/config.js';
@@ -3663,49 +3664,11 @@
deletingAnnouncement={deletingAnnouncement}
hasUnlimitedAccess={hasUnlimitedAccess($userStore.userLevel)}
needsClone={needsClone}
+ allMaintainers={allMaintainers}
/>
{/if}
-
- {#if allMaintainers.length > 0 || pageData.repoOwnerPubkey}
-
- {/if}
+
{#if pageData.repoWebsite || (pageData.repoCloneUrls && pageData.repoCloneUrls.length > 0) || pageData.repoLanguage || (pageData.repoTopics && pageData.repoTopics.length > 0) || forkInfo?.isFork}
{/if}
-
-
diff --git a/src/routes/users/[npub]/+page.svelte b/src/routes/users/[npub]/+page.svelte
index 992c361..ecc799c 100644
--- a/src/routes/users/[npub]/+page.svelte
+++ b/src/routes/users/[npub]/+page.svelte
@@ -89,21 +89,22 @@
let nostrLinkProfiles = $state