chore(ci): correct Gitea runner to runs-on ubuntu-24.04 and feat(billing): implement US-3.7 billing/subscription UX
This commit is contained in:
@@ -8,6 +8,7 @@ import { useAiConsent } from '@/components/legal/ai-consent-provider'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { toast } from 'sonner'
|
||||
import { resolveTitleDirection, resolveTitleLang } from '@/lib/clip/rtl-content'
|
||||
import { InlinePaywall } from '@/components/settings/inline-paywall'
|
||||
|
||||
export function NoteTitleBlock() {
|
||||
const { note, state, actions, readOnly, fullPage } = useNoteEditorContext()
|
||||
@@ -30,6 +31,12 @@ export function NoteTitleBlock() {
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{state.quotaExceededFeature === 'auto_title' && (
|
||||
<InlinePaywall
|
||||
feature="auto_title"
|
||||
onDismiss={() => actions.setQuotaExceededFeature(null)}
|
||||
/>
|
||||
)}
|
||||
{/* Title — auto-resizing textarea, adaptive size */}
|
||||
<div className="group relative">
|
||||
<textarea
|
||||
@@ -84,6 +91,10 @@ export function NoteTitleBlock() {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ content: plain }),
|
||||
})
|
||||
if (res.status === 402) {
|
||||
actions.setQuotaExceededFeature('auto_title')
|
||||
return
|
||||
}
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
const s = data.suggestions?.[0]?.title ?? ''
|
||||
@@ -127,32 +138,40 @@ export function NoteTitleBlock() {
|
||||
|
||||
// Dialog mode title block
|
||||
return (
|
||||
<div className="relative">
|
||||
<input
|
||||
dir={titleDir}
|
||||
lang={titleLang}
|
||||
placeholder={t('notes.titlePlaceholder')}
|
||||
value={state.title}
|
||||
onChange={(e) => actions.setTitle(e.target.value)}
|
||||
disabled={readOnly}
|
||||
className={cn(
|
||||
'w-full text-lg font-semibold border-0 focus-visible:ring-0 px-0 bg-transparent',
|
||||
titleIsRtl ? 'text-right font-[family-name:var(--font-sans)] ps-10' : 'text-left pe-10',
|
||||
readOnly && 'cursor-default',
|
||||
)}
|
||||
/>
|
||||
<button
|
||||
onClick={actions.handleGenerateTitles}
|
||||
disabled={state.isGeneratingTitles || readOnly}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 p-1 hover:bg-purple-100 dark:hover:bg-purple-900 rounded transition-colors"
|
||||
title={state.isGeneratingTitles ? t('ai.titleGenerating') : t('ai.titleGenerateWithAI')}
|
||||
>
|
||||
{state.isGeneratingTitles ? (
|
||||
<div className="w-4 h-4 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" />
|
||||
) : (
|
||||
<Sparkles className="w-4 h-4 text-purple-600 hover:text-purple-700 dark:text-purple-400" />
|
||||
)}
|
||||
</button>
|
||||
<div className="space-y-2">
|
||||
<div className="relative">
|
||||
<input
|
||||
dir={titleDir}
|
||||
lang={titleLang}
|
||||
placeholder={t('notes.titlePlaceholder')}
|
||||
value={state.title}
|
||||
onChange={(e) => actions.setTitle(e.target.value)}
|
||||
disabled={readOnly}
|
||||
className={cn(
|
||||
'w-full text-lg font-semibold border-0 focus-visible:ring-0 px-0 bg-transparent',
|
||||
titleIsRtl ? 'text-right font-[family-name:var(--font-sans)] ps-10' : 'text-left pe-10',
|
||||
readOnly && 'cursor-default',
|
||||
)}
|
||||
/>
|
||||
<button
|
||||
onClick={actions.handleGenerateTitles}
|
||||
disabled={state.isGeneratingTitles || readOnly}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 p-1 hover:bg-purple-100 dark:hover:bg-purple-900 rounded transition-colors"
|
||||
title={state.isGeneratingTitles ? t('ai.titleGenerating') : t('ai.titleGenerateWithAI')}
|
||||
>
|
||||
{state.isGeneratingTitles ? (
|
||||
<div className="w-4 h-4 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" />
|
||||
) : (
|
||||
<Sparkles className="w-4 h-4 text-purple-600 hover:text-purple-700 dark:text-purple-400" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
{state.quotaExceededFeature === 'auto_title' && (
|
||||
<InlinePaywall
|
||||
feature="auto_title"
|
||||
onDismiss={() => actions.setQuotaExceededFeature(null)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user