Skip to content

Commit c9f9f8f

Browse files
committed
feat: add Push to Community button in Dashboard
- Add canPushToCommunity() to check quality requirements - Show Push to Community button for non-public configs - Button enabled if config meets criteria (5+ packages, custom name, description) - Button disabled with tooltip if quality threshold not met - One-click promotion to Explore page - Success toast notification after pushing - Helps users discover and share high-quality configs
1 parent 649d8d5 commit c9f9f8f

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

src/routes/dashboard/+page.svelte

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,45 @@
512512
window.open(tweetUrl, '_blank', 'width=550,height=420');
513513
}
514514
515+
function canPushToCommunity(config: Config): boolean {
516+
const packages = Array.isArray(config.packages) ? config.packages : [];
517+
const packageCount = packages.length;
518+
const hasValidName = config.name !== 'Default';
519+
const hasValidDescription = !!config.description && config.description !== '' && config.description !== 'My default configuration';
520+
521+
return packageCount >= 5 && hasValidName && hasValidDescription;
522+
}
523+
524+
async function pushToCommunity(config: Config) {
525+
if (!canPushToCommunity(config)) {
526+
alert('Your configuration needs at least 5 packages, a custom name, and a description to be shared with the community.');
527+
return;
528+
}
529+
530+
try {
531+
const response = await fetch(`/api/configs/${config.slug}`, {
532+
method: 'PUT',
533+
headers: { 'Content-Type': 'application/json' },
534+
body: JSON.stringify({
535+
...config,
536+
visibility: 'public'
537+
})
538+
});
539+
540+
if (!response.ok) {
541+
const data = await response.json();
542+
alert(data.error || 'Failed to push to community');
543+
return;
544+
}
545+
546+
toast = `${config.name} is now live on Explore page!`;
547+
setTimeout(() => toast = '', 3000);
548+
await loadConfigs();
549+
} catch (e) {
550+
alert('Failed to push to community');
551+
}
552+
}
553+
515554
</script>
516555

517556
<svelte:head>
@@ -573,6 +612,27 @@
573612
<div class="config-actions" onclick={(e) => e.stopPropagation()} onkeydown={(e) => e.stopPropagation()} role="presentation">
574613
<Button variant="secondary" onclick={() => editConfig(config.slug)}>Edit</Button>
575614
<Button variant="secondary" onclick={() => duplicateConfig(config.slug)}>Duplicate</Button>
615+
{#if config.visibility !== 'public'}
616+
{#if canPushToCommunity(config)}
617+
<Button variant="primary" onclick={() => pushToCommunity(config)}>
618+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
619+
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>
620+
</svg>
621+
Push to Community
622+
</Button>
623+
{:else}
624+
<button
625+
class="push-to-community-disabled"
626+
title="Add at least 5 packages, a custom name, and a description to share with the community"
627+
disabled
628+
>
629+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
630+
<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
631+
</svg>
632+
Push to Community
633+
</button>
634+
{/if}
635+
{/if}
576636
<Button variant="secondary" onclick={() => shareConfig(config)}>Share</Button>
577637
<Button variant="secondary" onclick={() => exportConfig(config.slug)}>Export</Button>
578638
<Button variant="danger" onclick={() => deleteConfig(config.slug)}>Delete</Button>
@@ -1046,6 +1106,26 @@
10461106
color: var(--danger);
10471107
}
10481108
1109+
.push-to-community-disabled {
1110+
display: inline-flex;
1111+
align-items: center;
1112+
gap: 8px;
1113+
padding: 10px 16px;
1114+
background: var(--bg-tertiary);
1115+
border: 1px solid var(--border);
1116+
border-radius: 8px;
1117+
color: var(--text-muted);
1118+
font-size: 0.85rem;
1119+
font-weight: 500;
1120+
cursor: not-allowed;
1121+
opacity: 0.6;
1122+
font-family: inherit;
1123+
}
1124+
1125+
.push-to-community-disabled svg {
1126+
flex-shrink: 0;
1127+
}
1128+
10491129
.modal-overlay {
10501130
position: fixed;
10511131
inset: 0;

0 commit comments

Comments
 (0)