201 lines
4.5 KiB
Svelte
201 lines
4.5 KiB
Svelte
<script lang="ts">
|
|
import { goto } from '$app/navigation'
|
|
import UniverseComposer from './UniverseComposer.svelte'
|
|
import Button from './Button.svelte'
|
|
|
|
let isOpen = $state(false)
|
|
let buttonRef: HTMLElement
|
|
let showComposer = $state(false)
|
|
let selectedType = $state<'post' | 'essay'>('post')
|
|
|
|
const postTypes = [
|
|
{ value: 'essay', label: 'Essay' },
|
|
{ value: 'post', label: 'Post' }
|
|
]
|
|
|
|
function handleSelection(type: string) {
|
|
isOpen = false
|
|
|
|
if (type === 'essay') {
|
|
// Essays go straight to the full page
|
|
goto('/admin/universe/compose?type=essay')
|
|
} else if (type === 'post') {
|
|
// Posts open in modal
|
|
selectedType = 'post'
|
|
showComposer = true
|
|
}
|
|
}
|
|
|
|
function handleComposerClose() {
|
|
showComposer = false
|
|
}
|
|
|
|
function handleComposerSaved() {
|
|
showComposer = false
|
|
// Reload posts - in a real app, you'd emit an event to parent
|
|
window.location.reload()
|
|
}
|
|
|
|
function handleClickOutside(event: MouseEvent) {
|
|
if (!buttonRef?.contains(event.target as Node)) {
|
|
isOpen = false
|
|
}
|
|
}
|
|
|
|
$effect(() => {
|
|
if (isOpen) {
|
|
document.addEventListener('click', handleClickOutside)
|
|
return () => document.removeEventListener('click', handleClickOutside)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<div class="dropdown-container">
|
|
<Button
|
|
bind:this={buttonRef}
|
|
variant="primary"
|
|
onclick={(e) => {
|
|
e.stopPropagation()
|
|
isOpen = !isOpen
|
|
}}
|
|
iconPosition="right"
|
|
>
|
|
New Post
|
|
{#snippet icon()}
|
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="chevron">
|
|
<path
|
|
d="M3 4.5L6 7.5L9 4.5"
|
|
stroke="currentColor"
|
|
stroke-width="1.5"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
/>
|
|
</svg>
|
|
{/snippet}
|
|
</Button>
|
|
|
|
{#if isOpen}
|
|
<div class="dropdown-menu">
|
|
{#each postTypes as type}
|
|
<Button
|
|
variant="ghost"
|
|
onclick={() => handleSelection(type.value)}
|
|
class="dropdown-item"
|
|
fullWidth
|
|
pill={false}
|
|
>
|
|
{#snippet icon()}
|
|
<div class="dropdown-icon">
|
|
{#if type.value === 'essay'}
|
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
|
<path
|
|
d="M3 5C3 3.89543 3.89543 3 5 3H11L17 9V15C17 16.1046 16.1046 17 15 17H5C3.89543 17 3 16.1046 3 15V5Z"
|
|
stroke="currentColor"
|
|
stroke-width="1.5"
|
|
/>
|
|
<path d="M11 3V9H17" stroke="currentColor" stroke-width="1.5" />
|
|
<path
|
|
d="M7 13H13"
|
|
stroke="currentColor"
|
|
stroke-width="1.5"
|
|
stroke-linecap="round"
|
|
/>
|
|
<path
|
|
d="M7 10H13"
|
|
stroke="currentColor"
|
|
stroke-width="1.5"
|
|
stroke-linecap="round"
|
|
/>
|
|
</svg>
|
|
{:else if type.value === 'post'}
|
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
|
<path
|
|
d="M4 3C2.89543 3 2 3.89543 2 5V11C2 12.1046 2.89543 13 4 13H6L8 16V13H13C14.1046 13 15 12.1046 15 11V5C15 3.89543 14.1046 3 13 3H4Z"
|
|
stroke="currentColor"
|
|
stroke-width="1.5"
|
|
/>
|
|
<path d="M5 7H12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
|
<path d="M5 9H10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
|
</svg>
|
|
{/if}
|
|
</div>
|
|
{/snippet}
|
|
<span class="dropdown-label">{type.label}</span>
|
|
</Button>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<UniverseComposer
|
|
bind:isOpen={showComposer}
|
|
initialPostType={selectedType}
|
|
on:close={handleComposerClose}
|
|
on:saved={handleComposerSaved}
|
|
on:switch-to-essay
|
|
/>
|
|
|
|
<style lang="scss">
|
|
@import '$styles/variables.scss';
|
|
|
|
.dropdown-container {
|
|
position: relative;
|
|
}
|
|
|
|
// Button styles are now handled by the Button component
|
|
// Override primary button color to match original design
|
|
:global(.dropdown-container .btn-primary) {
|
|
background-color: $grey-10;
|
|
|
|
&:hover:not(:disabled) {
|
|
background-color: $grey-20;
|
|
}
|
|
|
|
&:active:not(:disabled) {
|
|
background-color: $grey-30;
|
|
}
|
|
}
|
|
|
|
.chevron {
|
|
transition: transform 0.2s ease;
|
|
}
|
|
|
|
.dropdown-menu {
|
|
position: absolute;
|
|
top: calc(100% + $unit);
|
|
right: 0;
|
|
background: white;
|
|
border: 1px solid $grey-85;
|
|
border-radius: $unit-2x;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
min-width: 220px;
|
|
z-index: 100;
|
|
overflow: hidden;
|
|
}
|
|
|
|
// Override Button component styles for dropdown items
|
|
:global(.dropdown-item) {
|
|
justify-content: flex-start;
|
|
text-align: left;
|
|
padding: $unit-2x $unit-3x;
|
|
border-radius: 0;
|
|
}
|
|
|
|
.dropdown-icon {
|
|
color: $grey-40;
|
|
display: flex;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
|
|
svg {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
}
|
|
|
|
.dropdown-label {
|
|
font-size: 0.925rem;
|
|
font-weight: 500;
|
|
color: $grey-10;
|
|
}
|
|
</style>
|