Browse Source

refactor 9

Nostr-Signature: 0d92496bc69fe5a2005be0eba26653a729d358f9d9f227e1af01c330eb0c4387 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc 9203dcc9cfb44804957d37d3b47079ac324bffb42e445a3a79130622e5e20fd10513d987f48edf195514ebf6cb136ba6c5992b39de21b8b47a086194e22cbaeb
main
Silberengel 2 weeks ago
parent
commit
227033d316
  1. 1
      nostr/commit-signatures.jsonl
  2. 27
      src/routes/repos/[npub]/[repo]/+page.svelte
  3. 154
      src/routes/repos/[npub]/[repo]/components/DocsTab.svelte
  4. 16
      src/routes/repos/[npub]/[repo]/components/HistoryTab.svelte
  5. 8
      src/routes/repos/[npub]/[repo]/components/IssuesTab.svelte
  6. 8
      src/routes/repos/[npub]/[repo]/components/PRsTab.svelte
  7. 8
      src/routes/repos/[npub]/[repo]/components/PatchesTab.svelte
  8. 53
      src/routes/repos/[npub]/[repo]/components/StatusTabLayout.svelte
  9. 19
      src/routes/repos/[npub]/[repo]/components/TabLayout.svelte
  10. 27
      src/routes/repos/[npub]/[repo]/components/dialogs/CreateIssueDialog.svelte
  11. 27
      src/routes/repos/[npub]/[repo]/components/dialogs/CreatePRDialog.svelte
  12. 26
      src/routes/repos/[npub]/[repo]/components/dialogs/CreatePatchDialog.svelte
  13. 5
      src/routes/repos/[npub]/[repo]/components/dialogs/Modal.svelte

1
nostr/commit-signatures.jsonl

@ -101,3 +101,4 @@
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772111536,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 5"]],"content":"Signed commit: refactor 5","id":"47651ed0aee8072f356fbac30b6168f2c985bcca392f9ed7d7c38d9670d90f16","sig":"2ca5d04d4a619dc3e02962249f7c650e3a561315897b329f4493e87148c5dd89fbcb6694515a72d0d17e64c9930e57bd7761e27b353275bb1ada9449330f4e1c"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772111536,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 5"]],"content":"Signed commit: refactor 5","id":"47651ed0aee8072f356fbac30b6168f2c985bcca392f9ed7d7c38d9670d90f16","sig":"2ca5d04d4a619dc3e02962249f7c650e3a561315897b329f4493e87148c5dd89fbcb6694515a72d0d17e64c9930e57bd7761e27b353275bb1ada9449330f4e1c"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772112054,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 6"]],"content":"Signed commit: refactor 6","id":"cd9b7e015ee3bd6a4c4ab7d54d90ab411a08c29f249158c4cdea2b12996b6b44","sig":"2a8fd0a3718169df1517c0b939ec9ea9793da4dc07b20d9366f09fe70b5268e94451916f975e2cea1a3741419440189d31f844e79863e84de00c0be7c449e92a"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772112054,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 6"]],"content":"Signed commit: refactor 6","id":"cd9b7e015ee3bd6a4c4ab7d54d90ab411a08c29f249158c4cdea2b12996b6b44","sig":"2a8fd0a3718169df1517c0b939ec9ea9793da4dc07b20d9366f09fe70b5268e94451916f975e2cea1a3741419440189d31f844e79863e84de00c0be7c449e92a"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772112920,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 7"]],"content":"Signed commit: refactor 7","id":"80f54ac61390cfbc8f2496a162d7065c447033a2e085ab5886c8138e337e93f9","sig":"f64bd2c965eff3534ad68e245651c189dc925d9613dd85557d88af8c692361ade13ccdd9deb88ae07eb227aa002af99d525a7fdf6f29eca854b5a02882ef226f"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772112920,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 7"]],"content":"Signed commit: refactor 7","id":"80f54ac61390cfbc8f2496a162d7065c447033a2e085ab5886c8138e337e93f9","sig":"f64bd2c965eff3534ad68e245651c189dc925d9613dd85557d88af8c692361ade13ccdd9deb88ae07eb227aa002af99d525a7fdf6f29eca854b5a02882ef226f"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772130529,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 8"]],"content":"Signed commit: refactor 8","id":"716cfe7b5d8b788e6e24092a6ad7e92de0b3d383c43a343f3c5bec4d2bbdd4b9","sig":"e80ed3d9d471bd6907e212edfd7cf3f6039fa80e4434c35f0591729515eaa98c7a8ac54f2ac6f7a2fefb7846de0e2f0a120543a0dbe862c47c7710a653189b0c"}

27
src/routes/repos/[npub]/[repo]/+page.svelte

@ -294,26 +294,19 @@
const lastBranch = { value: null as string | null }; const lastBranch = { value: null as string | null };
// Initialize activeTab from URL query parameter // Initialize activeTab from URL query parameter
// Sync activeTab to match URL state
$effect(() => { $effect(() => {
if (typeof window === 'undefined' || !state.isMounted) return; if (typeof window === 'undefined' || !state.isMounted) return;
const tabFromQuery = $page.url.searchParams.get('tab'); const tabFromQuery = $page.url.searchParams.get('tab');
const validTabs = ['docs', 'files', 'issues', 'prs', 'patches', 'discussions', 'history', 'tags', 'code-search']; const validTabs = ['docs', 'files', 'issues', 'prs', 'patches', 'discussions', 'history', 'tags', 'code-search'];
if (tabFromQuery && validTabs.includes(tabFromQuery)) { // Determine what tab the URL represents
// Update from URL query parameter const urlTab = tabFromQuery && validTabs.includes(tabFromQuery) ? tabFromQuery : 'files';
if (tabFromQuery !== state.ui.activeTab) {
state.ui.activeTab = tabFromQuery as typeof state.ui.activeTab; // Only update if activeTab doesn't match URL state
} if (state.ui.activeTab !== urlTab) {
} else if (!tabFromQuery) { state.ui.activeTab = urlTab as typeof state.ui.activeTab;
// No tab in query params - 'files' is the default (no param = files tab)
// Only set default if activeTab is not already a valid tab
if (!validTabs.includes(state.ui.activeTab)) {
state.ui.activeTab = 'files';
}
// If activeTab is already 'files', do nothing (user is on files tab)
// If activeTab is another valid tab but URL has no param, don't override
// This allows onTabChange handlers to manage state without interference
} }
}); });
@ -2325,6 +2318,8 @@
} }
goto(url.pathname + url.search, { replaceState: true, noScroll: true }); goto(url.pathname + url.search, { replaceState: true, noScroll: true });
}} }}
onCreate={() => { state.openDialog = 'createIssue'; }}
userPubkey={state.user.pubkey || null}
/> />
{/if} {/if}
@ -2385,6 +2380,8 @@
} }
goto(url.pathname + url.search, { replaceState: true, noScroll: true }); goto(url.pathname + url.search, { replaceState: true, noScroll: true });
}} }}
onCreate={() => { state.openDialog = 'createPR'; }}
userPubkey={state.user.pubkey || null}
/> />
{/if} {/if}
@ -2466,6 +2463,8 @@
} }
goto(url.pathname + url.search, { replaceState: true, noScroll: true }); goto(url.pathname + url.search, { replaceState: true, noScroll: true });
}} }}
onCreate={() => { state.openDialog = 'createPatch'; }}
userPubkey={state.user.pubkey || null}
/> />
{/if} {/if}

154
src/routes/repos/[npub]/[repo]/components/DocsTab.svelte

@ -36,9 +36,11 @@
let documentationKind = $state<'markdown' | 'asciidoc' | 'text' | '30040' | null>(null); let documentationKind = $state<'markdown' | 'asciidoc' | 'text' | '30040' | null>(null);
let indexEvent = $state<NostrEvent | null>(null); let indexEvent = $state<NostrEvent | null>(null);
let loading = $state(false); let loading = $state(false);
let loadingDocs = $state(false);
let error = $state<string | null>(null); let error = $state<string | null>(null);
let docFiles: Array<{ name: string; path: string }> = $state([]); let docFiles: Array<{ name: string; path: string }> = $state([]);
let selectedDoc: string | null = $state(null); let selectedDoc: string | null = $state(null);
let hasReadme = $state(false);
$effect(() => { $effect(() => {
if (npub && repo && currentBranch) { if (npub && repo && currentBranch) {
@ -48,83 +50,67 @@
async function loadDocumentation() { async function loadDocumentation() {
loading = true; loading = true;
loadingDocs = true;
error = null; error = null;
documentationContent = null; documentationContent = null;
documentationKind = null; documentationKind = null;
indexEvent = null; indexEvent = null;
hasReadme = false;
try { try {
logger.operation('Loading documentation', { npub, repo, branch: currentBranch }); logger.operation('Loading documentation', { npub, repo, branch: currentBranch });
// Try README first (faster, always available if repo has content) // Load README FIRST and display immediately
const readmePromise = (async () => { try {
try { const readmeResponse = await fetch(`/api/repos/${npub}/${repo}/readme?ref=${currentBranch || 'HEAD'}`);
const readmeResponse = await fetch(`/api/repos/${npub}/${repo}/readme?ref=${currentBranch || 'HEAD'}`); if (readmeResponse.ok) {
if (readmeResponse.ok) { const readmeData = await readmeResponse.json();
const readmeData = await readmeResponse.json(); if (readmeData.content) {
if (readmeData.content) { documentationContent = readmeData.content;
return { documentationKind = readmeData.type || 'markdown';
content: readmeData.content, selectedDoc = 'README.md';
kind: readmeData.type || 'markdown', hasReadme = true;
path: 'README.md' loading = false; // Stop showing loading once README is loaded
}; logger.debug({ npub, repo }, 'README loaded and displayed');
}
} }
} catch (readmeErr) {
logger.debug({ error: readmeErr, npub, repo }, 'No README found');
} }
return null; } catch (readmeErr) {
})(); logger.debug({ error: readmeErr, npub, repo }, 'No README found');
}
// Try docs folder in parallel
const docsPromise = (async () => { // Now check for docs folder in the background
try { try {
const response = await fetch(`/api/repos/${npub}/${repo}/tree?ref=${currentBranch || 'HEAD'}&path=docs`); const response = await fetch(`/api/repos/${npub}/${repo}/tree?ref=${currentBranch || 'HEAD'}&path=docs`);
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
return Array.isArray(data) ? data : (data.files || []); const docsFiles = Array.isArray(data) ? data : (data.files || []);
if (docsFiles.length > 0) {
docFiles = docsFiles;
logger.debug({ npub, repo, fileCount: docsFiles.length }, 'Docs folder found');
} }
} catch (err) {
logger.debug({ error: err, npub, repo }, 'Docs folder not found');
} }
return []; } catch (err) {
})(); logger.debug({ error: err, npub, repo }, 'Docs folder not found');
// Wait for both, prefer docs folder if it has files
const [readmeResult, docsFiles] = await Promise.all([readmePromise, docsPromise]);
docFiles = docsFiles;
if (docsFiles.length > 0) {
// Look for README or index files first in docs folder
const readmeFile = docsFiles.find((f: { name: string; path: string }) =>
f.name.toLowerCase() === 'readme.md' ||
f.name.toLowerCase() === 'readme.adoc' ||
f.name.toLowerCase() === 'index.md'
);
if (readmeFile) {
await loadDocFile(readmeFile.path);
} else {
// Load first file from docs folder
await loadDocFile(docsFiles[0].path);
}
} else if (readmeResult) {
// No docs folder, use README from root
documentationContent = readmeResult.content;
documentationKind = readmeResult.kind as 'markdown' | 'asciidoc';
selectedDoc = readmeResult.path;
} }
// Check for kind 30040 publication index (only if no content found yet) // Check for kind 30040 publication index (only if no README found)
if (!documentationContent && !indexEvent) { if (!hasReadme && !indexEvent) {
await checkForPublicationIndex(); await checkForPublicationIndex();
if (indexEvent) {
loading = false;
}
} }
} catch (err) { } catch (err) {
error = err instanceof Error ? err.message : 'Failed to load documentation'; error = err instanceof Error ? err.message : 'Failed to load documentation';
logger.error({ error: err, npub, repo }, 'Error loading documentation'); logger.error({ error: err, npub, repo }, 'Error loading documentation');
} finally {
loading = false; loading = false;
} finally {
loadingDocs = false;
if (!hasReadme && !indexEvent) {
loading = false;
}
} }
} }
@ -198,31 +184,47 @@
{#snippet leftPane()} {#snippet leftPane()}
<div class="docs-sidebar"> <div class="docs-sidebar">
<h3>Documentation</h3> <h3>Documentation</h3>
{#if loading} {#if loadingDocs}
<div class="loading">Loading documentation...</div> <div class="loading">Loading...</div>
{:else if error} {:else if error}
<div class="error">{error}</div> <div class="error">{error}</div>
{:else if docFiles.length > 0} {:else}
<ul class="doc-list"> <ul class="doc-list">
{#each docFiles as file} {#if hasReadme}
<li> <li>
<button <button
class="doc-item {selectedDoc === file.path ? 'selected' : ''}" class="doc-item {selectedDoc === 'README.md' ? 'selected' : ''}"
onclick={() => loadDocFile(file.path)} onclick={() => {
// Reload README if needed
if (!documentationContent) {
loadDocumentation();
} else {
selectedDoc = 'README.md';
}
}}
> >
{file.name} README.md
</button> </button>
</li> </li>
{/each} {/if}
{#if docFiles.length > 0}
{#each docFiles as file}
<li>
<button
class="doc-item {selectedDoc === file.path ? 'selected' : ''}"
onclick={() => loadDocFile(file.path)}
>
{file.name}
</button>
</li>
{/each}
{/if}
{#if !hasReadme && docFiles.length === 0}
<div class="empty-sidebar">
<p>No documentation files found</p>
</div>
{/if}
</ul> </ul>
{:else if documentationContent}
<div class="empty-sidebar">
<p>No custom documentation found. Displaying the ReadMe, instead.</p>
</div>
{:else}
<div class="empty-sidebar">
<p>No documentation files found</p>
</div>
{/if} {/if}
</div> </div>
{/snippet} {/snippet}
@ -260,12 +262,14 @@
<style> <style>
.docs-sidebar { .docs-sidebar {
padding: 1rem; padding: 1rem;
color: var(--text-primary);
} }
.docs-sidebar h3 { .docs-sidebar h3 {
margin: 0 0 1rem 0; margin: 0 0 1rem 0;
font-size: 1rem; font-size: 1rem;
font-weight: 600; font-weight: 600;
color: var(--text-primary);
} }
.doc-list { .doc-list {
@ -284,16 +288,22 @@
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.2s;
color: var(--text-primary);
font-family: inherit;
font-size: inherit;
} }
.doc-item:hover { .doc-item:hover {
background: var(--bg-hover); background: var(--bg-hover);
border-color: var(--accent-color); border-color: var(--accent-color);
color: var(--text-primary);
} }
.doc-item.selected { .doc-item.selected {
background: var(--bg-selected); background: var(--bg-selected);
border-color: var(--accent-color); border-color: var(--accent-color);
color: var(--text-primary);
font-weight: 500;
} }
.empty-docs { .empty-docs {

16
src/routes/repos/[npub]/[repo]/components/HistoryTab.svelte

@ -91,15 +91,19 @@
{#if selectedCommit} {#if selectedCommit}
{@const commit = commits.find(c => c.hash === selectedCommit)} {@const commit = commits.find(c => c.hash === selectedCommit)}
{#if commit} {#if commit}
{@const hasNostrSignature = commit.message && commit.message.includes('Nostr-Signature:')}
{@const hasVerification = commit.verification && commit.verification.hasSignature !== false}
<div class="commit-detail"> <div class="commit-detail">
<div class="commit-detail-header"> <div class="commit-detail-header">
<h2>Commit {commit.hash.slice(0, 7)}</h2> <h2>Commit {commit.hash.slice(0, 7)}</h2>
<button {#if hasNostrSignature || hasVerification}
onclick={() => onVerify(commit.hash)} <button
disabled={verifyingCommits.has(commit.hash)} onclick={() => onVerify(commit.hash)}
> disabled={verifyingCommits.has(commit.hash)}
{verifyingCommits.has(commit.hash) ? 'Verifying...' : 'Verify Signature'} >
</button> {verifyingCommits.has(commit.hash) ? 'Verifying...' : 'Verify Signature'}
</button>
{/if}
</div> </div>
<div class="commit-info"> <div class="commit-info">

8
src/routes/repos/[npub]/[repo]/components/IssuesTab.svelte

@ -27,6 +27,8 @@
activeTab?: string; activeTab?: string;
tabs?: Array<{ id: string; label: string; icon?: string }>; tabs?: Array<{ id: string; label: string; icon?: string }>;
onTabChange?: (tab: string) => void; onTabChange?: (tab: string) => void;
onCreate?: () => void;
userPubkey?: string | null;
} }
let { let {
@ -40,7 +42,9 @@
loadingReplies = false, loadingReplies = false,
activeTab = '', activeTab = '',
tabs = [], tabs = [],
onTabChange = () => {} onTabChange = () => {},
onCreate,
userPubkey = null
}: Props = $props(); }: Props = $props();
const items = $derived(issues.map(issue => ({ const items = $derived(issues.map(issue => ({
@ -148,6 +152,8 @@
{tabs} {tabs}
{onTabChange} {onTabChange}
title="Issues" title="Issues"
{onCreate}
showCreateButton={!!userPubkey && !!onCreate}
/> />
<style> <style>

8
src/routes/repos/[npub]/[repo]/components/PRsTab.svelte

@ -26,6 +26,8 @@
activeTab?: string; activeTab?: string;
tabs?: Array<{ id: string; label: string; icon?: string }>; tabs?: Array<{ id: string; label: string; icon?: string }>;
onTabChange?: (tab: string) => void; onTabChange?: (tab: string) => void;
onCreate?: () => void;
userPubkey?: string | null;
} }
let { let {
@ -37,7 +39,9 @@
onStatusUpdate = () => {}, onStatusUpdate = () => {},
activeTab = '', activeTab = '',
tabs = [], tabs = [],
onTabChange = () => {} onTabChange = () => {},
onCreate,
userPubkey = null
}: Props = $props(); }: Props = $props();
const items = $derived(prs.map(pr => ({ const items = $derived(prs.map(pr => ({
@ -130,6 +134,8 @@
{tabs} {tabs}
{onTabChange} {onTabChange}
title="Pull Requests" title="Pull Requests"
{onCreate}
showCreateButton={!!userPubkey && !!onCreate}
/> />
<style> <style>

8
src/routes/repos/[npub]/[repo]/components/PatchesTab.svelte

@ -27,6 +27,8 @@
activeTab?: string; activeTab?: string;
tabs?: Array<{ id: string; label: string; icon?: string }>; tabs?: Array<{ id: string; label: string; icon?: string }>;
onTabChange?: (tab: string) => void; onTabChange?: (tab: string) => void;
onCreate?: () => void;
userPubkey?: string | null;
} }
let { let {
@ -40,7 +42,9 @@
applying = {}, applying = {},
activeTab = '', activeTab = '',
tabs = [], tabs = [],
onTabChange = () => {} onTabChange = () => {},
onCreate,
userPubkey = null
}: Props = $props(); }: Props = $props();
const items = $derived(patches.map(patch => ({ const items = $derived(patches.map(patch => ({
@ -134,6 +138,8 @@
{tabs} {tabs}
{onTabChange} {onTabChange}
title="Patches" title="Patches"
{onCreate}
showCreateButton={!!userPubkey && !!onCreate}
/> />
<style> <style>

53
src/routes/repos/[npub]/[repo]/components/StatusTabLayout.svelte

@ -24,6 +24,8 @@
tabs?: Array<{ id: string; label: string; icon?: string }>; tabs?: Array<{ id: string; label: string; icon?: string }>;
onTabChange?: (tab: string) => void; onTabChange?: (tab: string) => void;
title?: string; title?: string;
onCreate?: () => void;
showCreateButton?: boolean;
} }
let { let {
@ -41,7 +43,9 @@
activeTab = '', activeTab = '',
tabs = [], tabs = [],
onTabChange = () => {}, onTabChange = () => {},
title = '' title = '',
onCreate,
showCreateButton = false
}: Props = $props(); }: Props = $props();
let selectedItem = $derived(items.find(item => item.id === selectedId) || null); let selectedItem = $derived(items.find(item => item.id === selectedId) || null);
@ -76,6 +80,18 @@
> >
{#snippet leftPane()} {#snippet leftPane()}
<div class="status-groups"> <div class="status-groups">
{#if showCreateButton && onCreate}
<div class="status-header-wrapper">
<h2 class="status-title">{title || 'Items'}</h2>
<button
onclick={onCreate}
class="create-button"
title="Create New"
>
<img src="/icons/plus.svg" alt="New" class="icon" />
</button>
</div>
{/if}
{#each statusGroups as { label, value }} {#each statusGroups as { label, value }}
{#if grouped[value] && grouped[value].length > 0} {#if grouped[value] && grouped[value].length > 0}
<div class="status-group"> <div class="status-group">
@ -134,6 +150,41 @@
gap: 1.5rem; gap: 1.5rem;
} }
.status-header-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-color);
}
.status-title {
margin: 0;
font-size: 1.25rem;
color: var(--text-primary);
}
.create-button {
background: none;
border: none;
cursor: pointer;
padding: 0.25rem;
display: flex;
align-items: center;
transition: opacity 0.2s;
}
.create-button:hover {
opacity: 0.7;
}
.create-button .icon {
width: 20px;
height: 20px;
filter: var(--icon-filter, none);
}
.status-group { .status-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

19
src/routes/repos/[npub]/[repo]/components/TabLayout.svelte

@ -73,6 +73,10 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
width: 100%;
max-width: 100%;
min-width: 0;
box-sizing: border-box;
} }
.tab-header { .tab-header {
@ -83,6 +87,8 @@
gap: 0.5rem; gap: 0.5rem;
background: var(--bg-primary); background: var(--bg-primary);
flex-shrink: 0; flex-shrink: 0;
width: 100%;
box-sizing: border-box;
} }
.tab-title { .tab-title {
@ -90,26 +96,35 @@
margin: 0; margin: 0;
font-size: 1.2rem; font-size: 1.2rem;
color: var(--text-primary); color: var(--text-primary);
min-width: 0;
} }
.tab-layout { .tab-layout {
display: flex; display: flex;
flex: 1; flex: 1;
min-height: 0; min-height: 0;
min-width: 0;
width: 100%;
max-width: 100%;
gap: 1rem; gap: 1rem;
box-sizing: border-box;
} }
.left-pane { .left-pane {
flex: 0 0 300px; flex: 0 0 300px;
min-width: 300px;
max-width: 300px;
border-right: 1px solid var(--border-color); border-right: 1px solid var(--border-color);
overflow-y: auto; overflow-y: auto;
padding: 1rem; padding: 1rem;
box-sizing: border-box;
} }
.right-panel { .right-panel {
flex: 1; flex: 1 1 auto;
min-width: 0; min-width: 0;
width: 100%; width: auto;
max-width: none;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
padding: 1rem; padding: 1rem;

27
src/routes/repos/[npub]/[repo]/components/dialogs/CreateIssueDialog.svelte

@ -39,13 +39,24 @@
margin-bottom: 1rem; margin-bottom: 1rem;
} }
label {
color: var(--text-primary, #e0e0e0);
}
label input, label input,
label textarea { label textarea {
width: 100%; width: 100%;
padding: 0.5rem; padding: 0.5rem;
margin-top: 0.25rem; margin-top: 0.25rem;
border: 1px solid var(--border-color, #e0e0e0); border: 1px solid var(--border-color, #333);
border-radius: 4px; border-radius: 4px;
background: var(--bg-secondary, #2a2a2a);
color: var(--text-primary, #e0e0e0);
}
label input::placeholder,
label textarea::placeholder {
color: var(--text-secondary, #888);
} }
.modal-actions { .modal-actions {
@ -64,14 +75,24 @@
} }
.cancel-button { .cancel-button {
background: var(--cancel-bg, #e0e0e0); background: var(--cancel-bg, var(--bg-secondary, #2a2a2a));
color: var(--text-primary, #e0e0e0);
border: 1px solid var(--border-color, #333);
}
.cancel-button:hover {
background: var(--bg-hover, #3a3a3a);
} }
.save-button { .save-button {
background: var(--primary-color, #2196f3); background: var(--primary-color, var(--accent-color, #2196f3));
color: white; color: white;
} }
.save-button:hover {
opacity: 0.9;
}
.save-button:disabled { .save-button:disabled {
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;

27
src/routes/repos/[npub]/[repo]/components/dialogs/CreatePRDialog.svelte

@ -47,13 +47,24 @@
margin-bottom: 1rem; margin-bottom: 1rem;
} }
label {
color: var(--text-primary, #e0e0e0);
}
label input, label input,
label textarea { label textarea {
width: 100%; width: 100%;
padding: 0.5rem; padding: 0.5rem;
margin-top: 0.25rem; margin-top: 0.25rem;
border: 1px solid var(--border-color, #e0e0e0); border: 1px solid var(--border-color, #333);
border-radius: 4px; border-radius: 4px;
background: var(--bg-secondary, #2a2a2a);
color: var(--text-primary, #e0e0e0);
}
label input::placeholder,
label textarea::placeholder {
color: var(--text-secondary, #888);
} }
.modal-actions { .modal-actions {
@ -72,14 +83,24 @@
} }
.cancel-button { .cancel-button {
background: var(--cancel-bg, #e0e0e0); background: var(--cancel-bg, var(--bg-secondary, #2a2a2a));
color: var(--text-primary, #e0e0e0);
border: 1px solid var(--border-color, #333);
}
.cancel-button:hover {
background: var(--bg-hover, #3a3a3a);
} }
.save-button { .save-button {
background: var(--primary-color, #2196f3); background: var(--primary-color, var(--accent-color, #2196f3));
color: white; color: white;
} }
.save-button:hover {
opacity: 0.9;
}
.save-button:disabled { .save-button:disabled {
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;

26
src/routes/repos/[npub]/[repo]/components/dialogs/CreatePatchDialog.svelte

@ -37,13 +37,14 @@
<style> <style>
.help-text { .help-text {
margin-bottom: 1rem; margin-bottom: 1rem;
color: var(--text-secondary, #666); color: var(--text-secondary, #888);
font-size: 0.9rem; font-size: 0.9rem;
} }
label { label {
display: block; display: block;
margin-bottom: 1rem; margin-bottom: 1rem;
color: var(--text-primary, #e0e0e0);
} }
label input, label input,
@ -51,8 +52,15 @@
width: 100%; width: 100%;
padding: 0.5rem; padding: 0.5rem;
margin-top: 0.25rem; margin-top: 0.25rem;
border: 1px solid var(--border-color, #e0e0e0); border: 1px solid var(--border-color, #333);
border-radius: 4px; border-radius: 4px;
background: var(--bg-secondary, #2a2a2a);
color: var(--text-primary, #e0e0e0);
}
label input::placeholder,
label textarea::placeholder {
color: var(--text-secondary, #888);
} }
.modal-actions { .modal-actions {
@ -71,14 +79,24 @@
} }
.cancel-button { .cancel-button {
background: var(--cancel-bg, #e0e0e0); background: var(--cancel-bg, var(--bg-secondary, #2a2a2a));
color: var(--text-primary, #e0e0e0);
border: 1px solid var(--border-color, #333);
}
.cancel-button:hover {
background: var(--bg-hover, #3a3a3a);
} }
.save-button { .save-button {
background: var(--primary-color, #2196f3); background: var(--primary-color, var(--accent-color, #2196f3));
color: white; color: white;
} }
.save-button:hover {
opacity: 0.9;
}
.save-button:disabled { .save-button:disabled {
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;

5
src/routes/repos/[npub]/[repo]/components/dialogs/Modal.svelte

@ -52,16 +52,19 @@
} }
.modal { .modal {
background: var(--modal-bg, #fff); background: var(--modal-bg, var(--bg-primary, #1a1a1a));
color: var(--text-primary, #e0e0e0);
border-radius: 8px; border-radius: 8px;
padding: 1.5rem; padding: 1.5rem;
max-width: 500px; max-width: 500px;
width: 90%; width: 90%;
max-height: 90vh; max-height: 90vh;
overflow-y: auto; overflow-y: auto;
border: 1px solid var(--border-color, #333);
} }
.modal h3 { .modal h3 {
margin: 0 0 1rem 0; margin: 0 0 1rem 0;
color: var(--text-primary, #e0e0e0);
} }
</style> </style>

Loading…
Cancel
Save