Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions packages/akiradocs/src/components/blocks/ButtonBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { cn } from "@/lib/utils"
import { Button, buttonVariants } from "@/components/ui/button"
import { useState } from "react"

interface ButtonBlockProps {
content: string
metadata?: {
buttonUrl?: string
buttonStyle?: {
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
size?: 'default' | 'sm' | 'lg'
radius?: 'none' | 'sm' | 'md' | 'lg' | 'full'
}
}
isEditing?: boolean
onUpdate?: (content: string) => void
align?: 'left' | 'center' | 'right'
}

export function ButtonBlock({
content,
metadata,
isEditing,
onUpdate,
align = 'left'
}: ButtonBlockProps) {
const [isFocused, setIsFocused] = useState(false);
const buttonStyle = metadata?.buttonStyle || {}
const url = metadata?.buttonUrl || '#'

const buttonClasses = cn(
"relative",
{
'rounded-none': buttonStyle.radius === 'none',
'rounded-sm': buttonStyle.radius === 'sm',
'rounded-md': buttonStyle.radius === 'md',
'rounded-lg': buttonStyle.radius === 'lg',
'rounded-full': buttonStyle.radius === 'full',
'w-full': buttonStyle.size === 'lg',
'w-24': buttonStyle.size === 'sm',
'w-auto': buttonStyle.size === 'default'
}
)

const wrapperClasses = cn(
'w-full',
{
'text-left': align === 'left',
'text-center': align === 'center',
'text-right': align === 'right'
}
)

if (isEditing) {
return (
<div className={wrapperClasses}>
<div className="relative inline-block">
<Button
variant={buttonStyle.variant || 'default'}
size={buttonStyle.size || 'default'}
className={cn(buttonClasses, isFocused && "invisible")}
type="button"
>
{content || 'Button text...'}
</Button>
<input
value={content}
onChange={(e) => onUpdate?.(e.target.value)}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
className={cn(
buttonVariants({
variant: buttonStyle.variant || 'default',
size: buttonStyle.size || 'default'
}),
buttonClasses,
"absolute inset-0 border-0 outline-none",
!isFocused && "opacity-0"
)}
placeholder="Button text..."
/>
</div>
</div>
)
}

return (
<div className={wrapperClasses}>
<div className="relative inline-block">
<Button
variant={buttonStyle.variant || 'default'}
size={buttonStyle.size || 'default'}
className={buttonClasses}
asChild
>
<a href={url} target="_blank" rel="noopener noreferrer">
{content}
</a>
</Button>
</div>
</div>
)
}
21 changes: 21 additions & 0 deletions packages/akiradocs/src/components/blocks/SortableBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ interface SortableBlockProps {
align?: 'left' | 'center' | 'right'
type?: 'info' | 'warning' | 'success' | 'error'
title?: string
buttonUrl?: string
buttonStyle?: {
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
size?: 'default' | 'sm' | 'lg'
radius?: 'none' | 'sm' | 'md' | 'lg' | 'full'
}
}
}
updateBlock: (id: string, content: string) => void
Expand Down Expand Up @@ -514,6 +520,21 @@ export function SortableBlock({
updateBlock(block.id, JSON.stringify(updatedContent));
}
}}
showButtonControls={block.type === 'button'}
buttonMetadata={{
url: block.metadata?.buttonUrl,
style: block.metadata?.buttonStyle
}}
onButtonMetadataChange={(metadata) => {
updateBlockMetadata(block.id, {
...block.metadata,
buttonUrl: metadata.buttonUrl,
buttonStyle: {
...block.metadata?.buttonStyle,
...metadata.buttonStyle
}
})
}}
/>
)}
<BlockRenderer
Expand Down
59 changes: 59 additions & 0 deletions packages/akiradocs/src/components/blocks/SpacerBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { cn } from '@/lib/utils'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { useState } from 'react'

interface SpacerBlockProps {
size?: 'small' | 'medium' | 'large' | 'xlarge'
isEditing?: boolean
onUpdate?: (size: string) => void
}

const spacingSizes = {
small: 'h-4',
medium: 'h-8',
large: 'h-16',
xlarge: 'h-24'
}

export function SpacerBlock({ size = 'medium', isEditing, onUpdate }: SpacerBlockProps) {
const [isFocused, setIsFocused] = useState(false)

if (!isEditing) {
return <div className={cn('w-full', spacingSizes[size])} />
}

return (
<div
className="flex items-center gap-2 py-2"
tabIndex={0}
onFocus={() => setIsFocused(true)}
onBlur={(e) => {
if (!e.currentTarget.contains(e.relatedTarget)) {
setIsFocused(false)
}
}}
>
<div className={cn(
'flex-grow border-2 border-dashed rounded transition-colors duration-200',
spacingSizes[size],
isFocused ? 'border-muted-foreground/20' : 'border-transparent'
)} />
{isFocused && (
<Select
value={size}
onValueChange={(value) => onUpdate?.(value)}
>
<SelectTrigger className="w-[120px]">
<SelectValue placeholder="Select size" />
</SelectTrigger>
<SelectContent>
<SelectItem value="small">Small</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="large">Large</SelectItem>
<SelectItem value="xlarge">Extra Large</SelectItem>
</SelectContent>
</Select>
)}
</div>
)
}
27 changes: 27 additions & 0 deletions packages/akiradocs/src/components/editor/AIRewriteButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,25 @@ const blockStyles = {
label: 'Descriptive',
prompt: 'Rewrite the API reference to be more descriptive and engaging.'
}
],
button: [
{
value: 'descriptive',
label: 'Descriptive',
prompt: 'Rewrite the button text to be more descriptive and engaging.'
},
{
value: 'concise',
label: 'Concise',
prompt: 'Rewrite the button text to be more concise and clear.'
}
],
spacer: [
{
value: 'default',
label: 'Default',
prompt: 'No rewriting options available for spacer'
}
]
} as const;

Expand All @@ -213,6 +232,10 @@ export function AIRewriteButton({ onRewrite, blockType, isRewriting }: AIRewrite
};

const handleRewrite = async () => {
if (blockType === 'spacer') {
return;
}

try {
await onRewrite(style)
} catch (error) {
Expand All @@ -224,6 +247,10 @@ export function AIRewriteButton({ onRewrite, blockType, isRewriting }: AIRewrite
}
}

if (blockType === 'spacer') {
return null;
}

return (
<Popover>
<PopoverTrigger asChild>
Expand Down
11 changes: 4 additions & 7 deletions packages/akiradocs/src/components/editor/AddBlockButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,14 @@ import {
Minus,
Table,
Quote,
// ToggleLeft,
// CheckSquare,
// Video,
// Music,
// File,
// Smile,
AlertCircle,
Plus,
// Search,
Video,
Music,
File,
CheckSquare,
ArrowUpDown,
Link2,
} from 'lucide-react'

interface AddBlockButtonProps {
Expand Down Expand Up @@ -83,6 +78,8 @@ export const AddBlockButton = forwardRef<
{ type: 'audio', icon: <Music size={18} />, label: 'Audio', description: 'Embed audio content.', group: 'Media' },
{ type: 'file', icon: <File size={18} />, label: 'File', description: 'Upload or link to a file.', group: 'Media' },
{ type: 'checkList', icon: <CheckSquare size={18} />, label: 'To-do list', description: 'Track tasks with a to-do list.', group: 'Basic' },
{ type: 'spacer', icon: <ArrowUpDown size={18} />, label: 'Spacing', description: 'Add vertical space between blocks.', group: 'Basic' },
{ type: 'button', icon: <Link2 size={18} />, label: 'Button', description: 'Add a clickable button with link.', group: 'Basic' },
]

const filteredOptions = blockOptions.filter((option) =>
Expand Down
Loading
Loading