Skip to content

Commit

Permalink
fix: support ai tag & improve article ui
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinko committed Nov 26, 2024
1 parent 786c99e commit c4b0bed
Show file tree
Hide file tree
Showing 22 changed files with 394 additions and 111 deletions.
4 changes: 3 additions & 1 deletion public/locales/ar/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,5 +165,7 @@
"chars": "الأحرف",
"text-fold-length": "طول طية النص",
"title-first-line-of-the-text": "العنوان (السطر الأول من النص)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "المحتوى(بقية النص، إذا كان النص أطول من الطول)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "المحتوى(بقية النص، إذا كان النص أطول من الطول)",
"ai-tag": "علامة الذكاء الاصطناعي",
"article": "المادة"
}
4 changes: 3 additions & 1 deletion public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,7 @@
"chars": "Zeichen",
"text-fold-length": "Text Falzlänge",
"title-first-line-of-the-text": "Titel (erste Zeile des Textes)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Inhalt (Rest des Textes, wenn der Text länger als die Länge ist)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Inhalt (Rest des Textes, wenn der Text länger als die Länge ist)",
"ai-tag": "AI-Tag",
"article": "Artikel"
}
4 changes: 3 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,7 @@
"chars": "Chars",
"text-fold-length": "Text Fold Length",
"title-first-line-of-the-text": "Title(first line of the text)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Content(rest of the text,if the text is longer than the length)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Content(rest of the text,if the text is longer than the length)",
"ai-tag": "AI Tag",
"article": "Article"
}
4 changes: 3 additions & 1 deletion public/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,5 +156,7 @@
"chars": "Caracteres",
"text-fold-length": "Longitud del pliegue del texto",
"title-first-line-of-the-text": "Título(primera línea del texto)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Contenido(resto del texto,si el texto supera la longitud)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Contenido(resto del texto,si el texto supera la longitud)",
"ai-tag": "Etiqueta AI",
"article": "Artículo"
}
4 changes: 3 additions & 1 deletion public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,7 @@
"chars": "Chars",
"text-fold-length": "Longueur du pli du texte",
"title-first-line-of-the-text": "Titre (première ligne du texte)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Contenu (reste du texte, si le texte est plus long que la longueur)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Contenu (reste du texte, si le texte est plus long que la longueur)",
"ai-tag": "Étiquette AI",
"article": "Article"
}
4 changes: 3 additions & 1 deletion public/locales/ja/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,7 @@
"chars": "文字",
"text-fold-length": "テキストの折りの長さ",
"title-first-line-of-the-text": "タイトル(本文の1行目)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "コンテンツ(テキストが長さを超える場合、残りの部分)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "コンテンツ(テキストが長さを超える場合、残りの部分)",
"ai-tag": "AIタグ",
"article": "記事"
}
4 changes: 3 additions & 1 deletion public/locales/ko/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,7 @@
"chars": "문자",
"text-fold-length": "텍스트 접기 길이",
"title-first-line-of-the-text": "제목(텍스트의 첫 줄)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "콘텐츠(텍스트가 길이보다 긴 경우 나머지 텍스트)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "콘텐츠(텍스트가 길이보다 긴 경우 나머지 텍스트)",
"ai-tag": "AI 태그",
"article": "기사"
}
4 changes: 3 additions & 1 deletion public/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,5 +156,7 @@
"chars": "Caracteres",
"text-fold-length": "Comprimento da dobra do texto",
"title-first-line-of-the-text": "Título (primeira linha do texto)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Conteúdo (resto do texto, se o texto for mais longo do que o comprimento)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Conteúdo (resto do texto, se o texto for mais longo do que o comprimento)",
"ai-tag": "Etiqueta AI",
"article": "Artigo"
}
4 changes: 3 additions & 1 deletion public/locales/ru/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,5 +158,7 @@
"chars": "Chars",
"text-fold-length": "Длина текстового сгиба",
"title-first-line-of-the-text": "Заголовок (первая строка текста)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Содержание (остальная часть текста, если текст длиннее указанной длины)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "Содержание (остальная часть текста, если текст длиннее указанной длины)",
"ai-tag": "Метка AI",
"article": "Статья"
}
4 changes: 3 additions & 1 deletion public/locales/zh-TW/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,7 @@
"chars": "字符数",
"text-fold-length": "文本折叠长度",
"title-first-line-of-the-text": "标题(文本第一行)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "内容(文本的其余部分,如果文本长度超过规定长度)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "内容(文本的其余部分,如果文本长度超过规定长度)",
"ai-tag": "AI标签",
"article": "文章"
}
4 changes: 3 additions & 1 deletion public/locales/zh/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,5 +158,7 @@
"chars": "字符数",
"text-fold-length": "文本折叠长度",
"title-first-line-of-the-text": "标题(文本第一行)",
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "内容(文本的其余部分,如果文本长度超过规定长度)"
"content-rest-of-the-text-if-the-text-is-longer-than-the-length": "内容(文本的其余部分,如果文本长度超过规定长度)",
"ai-tag": "AI标签",
"article": "文章"
}
50 changes: 50 additions & 0 deletions src/components/BlinkoAi/aiTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { CheckboxGroup, Checkbox, Button } from "@nextui-org/react";
import { CustomCheckbox } from '../Common/CustomCheckbox';

interface AiTagProps {
tags: string[];
defaultSelected?: string[];
onSelect: (selected: string[]) => void;
confirmText?: string;
label?: string;
}

export const AiTag: React.FC<AiTagProps> = ({
tags,
defaultSelected = [],
onSelect,
confirmText = "Confirm",
}) => {
const [selected, setSelected] = React.useState<string[]>(defaultSelected);

const handleConfirm = () => {
onSelect(selected);
};

return (
<div className="flex flex-col gap-4">
<CheckboxGroup
className="gap-1"
orientation="horizontal"
value={selected}
onChange={setSelected}
>
{tags.map((tag) => (
<CustomCheckbox key={tag} value={tag}>
{tag}
</CustomCheckbox>
))}
</CheckboxGroup>
<div className='flex justify-end mt-2'>
<Button
color="primary"
onClick={handleConfirm}
className="w-fit"
>
{confirmText}
</Button>
</div>
</div>
);
};
18 changes: 14 additions & 4 deletions src/components/BlinkoCard/blogContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,29 @@ export const BlogContent = ({ blinkoItem, isExpanded }: BlogContentProps) => {
return (
<div className={`flex items-center justify-between gap-2 w-full ${isExpanded ? 'mb-4' : 'mb-1'}`}>
{blinkoItem.blogCover && (
<Image
src={blinkoItem.blogCover}
alt='blog cover'
<Image
src={blinkoItem.blogCover}
alt='blog cover'
className={`object-cover aspect-square rounded-lg w-fit max-w-[100px] max-h-[100px]`}
/>
)}
<div className='flex-1 flex flex-col min-w-[70%] pr-2'>
<div className={`font-bold line-clamp-1 ${isExpanded ? 'text-xl' : 'text-lg'}`}>
{blinkoItem.title?.replace(/#/g, '').replace(/\*/g, '')}
</div>
<div className={`text-desc line-clamp-5 flex-1 ${isExpanded ? 'text-sm' : 'text-xs'}`}>
<div className={`text-desc ${(!!blinkoItem?.tags?.length && blinkoItem?.tags?.length > 0) ? 'line-clamp-3' : 'line-clamp-5'} flex-1 ${isExpanded ? 'text-sm' : 'text-xs'}`}>
{blinkoItem.content?.replace(blinkoItem.title ?? '', '').replace(/#/g, '').replace(/\*/g, '')}
</div>
{
!!blinkoItem?.tags?.length && blinkoItem?.tags?.length > 0 && (
<div className='flex flex-nowrap gap-1 overflow-x-scroll mt-1 hide-scrollbar'>
{blinkoItem?.tags?.map((tag) => (
<div key={tag.tagId} className='text-desc text-xs blinko-tag whitespace-nowrap'>
#{tag.tag.name}
</div>
))}
</div>
)}
</div>
</div>
);
Expand Down
25 changes: 15 additions & 10 deletions src/components/BlinkoCard/cardFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ import dayjs from '@/lib/dayjs';
import { _ } from '@/lib/lodash';

interface CardFooterProps {
blinkoItem: Note;
blinkoItem: Note & {
isBlog?: boolean;
blogCover?: string;
title?: string;
};
blinko: BlinkoStore;
}

export const CardFooter = ({ blinkoItem, blinko }: CardFooterProps) => {
const { t } = useTranslation();

return (
<div className="flex items-center">
<div className="flex items-center mt-2">
<ConvertTypeButton blinkoItem={blinkoItem} blinko={blinko} t={t} />
<CreatedTimeInfo blinkoItem={blinkoItem} t={t} />
</div>
Expand All @@ -33,32 +37,33 @@ const ConvertTypeButton = ({ blinkoItem, blinko, t }) => {
if (blinkoItem.type === NoteType.BLINKO) {
return (
<Tooltip content={t('convert-to') + ' Note'} delay={1000}>
<div className='flex items-center justify-start mt-2 cursor-pointer' onClick={handleClick}>
<div className='flex items-center justify-start cursor-pointer' onClick={handleClick}>
<Icon className='text-yellow-500' icon="basil:lightning-solid" width="12" height="12" />
<div className='text-desc text-xs font-bold ml-1 select-none'>{t('blinko')}</div>
<div className='text-desc text-xs font-bold ml-1 select-none'>{t('blinko')} {blinkoItem.isBlog ? ` · ${t('article')}` : ''}</div>
</div>
</Tooltip>
);
}

return (
<Tooltip content={t('convert-to') + ' Blinko'} delay={1000}>
<div className='flex items-center justify-start mt-2 cursor-pointer' onClick={handleClick}>
<div className='flex items-center justify-start cursor-pointer' onClick={handleClick}>
<Icon className='text-blue-500' icon="solar:notes-minimalistic-bold-duotone" width="12" height="12" />
<div className='text-desc text-xs font-bold ml-1 select-none'>{t('note')}</div>
<div className='text-desc text-xs font-bold ml-1 select-none'>{t('note')} {blinkoItem.isBlog ? ` · ${t('article')}` : ''}</div>
</div>
</Tooltip>
);
};

const CreatedTimeInfo = ({ blinkoItem, t }) => {
if (dayjs(blinkoItem.createdAt).fromNow() === dayjs(blinkoItem.updatedAt).fromNow()) {
if (!blinkoItem?.metadata?.isIndexed) {
return null;
}

return (
<div className='ml-auto text-xs text-desc'>
{t('created-in')} {dayjs(blinkoItem.createdAt).fromNow()}
<div className='ml-auto flex items-center'>
<Tooltip content={"Indexed"} delay={1000}>
<Icon className='text-ignore opacity-50' icon="mingcute:ai-line" width="16" height="16" />
</Tooltip>
</div>
);
};
31 changes: 31 additions & 0 deletions src/components/BlinkoRightClickMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BlinkoEditor } from "../BlinkoEditor";
import { useEffect, useState } from "react";
import { NoteType } from "@/server/types";
import { useRouter } from "next/router";
import { AiStore } from "@/store/aiStore";

export const ShowEditBlinkoModel = (size: string = '2xl') => {
const blinko = RootStore.Get(BlinkoStore)
Expand Down Expand Up @@ -110,6 +111,19 @@ export const ArchivedItem = observer(() => {
</div>
})

export const AITagItem = observer(() => {
const { t } = useTranslation();
const blinko = RootStore.Get(BlinkoStore)
const aiStore = RootStore.Get(AiStore)
return (
<div className="flex items-start gap-2" onClick={e => {
aiStore.autoTag.call(blinko.curSelectedNote?.id!, blinko.curSelectedNote?.content!)
}}>
<Icon icon="carbon:ai-status" width="20" height="20" />
<div>{t('ai-tag')}</div>
</div>
);
});

export const DeleteItem = observer(() => {
const { t } = useTranslation();
Expand All @@ -126,9 +140,12 @@ export const DeleteItem = observer(() => {
export const BlinkoRightClickMenu = observer(() => {
const [isDetailPage, setIsDetailPage] = useState(false)
const router = useRouter()
const blinko = RootStore.Get(BlinkoStore)

useEffect(() => {
setIsDetailPage(router.pathname.includes('/detail'))
}, [router.pathname])

return <ContextMenu className='font-bold' id="blink-item-context-menu" hideOnLeave={false} animation="zoom">
<ContextMenuItem >
<EditItem />
Expand All @@ -154,6 +171,11 @@ export const BlinkoRightClickMenu = observer(() => {
<ArchivedItem />
</ContextMenuItem>

{blinko.config.value?.isUseAI ? (
<ContextMenuItem>
<AITagItem />
</ContextMenuItem>
) : <></>}

<ContextMenuItem className='select-none divider hover:!bg-none'>
<Divider orientation="horizontal" />
Expand All @@ -168,6 +190,8 @@ export const BlinkoRightClickMenu = observer(() => {
export const LeftCickMenu = observer(({ onTrigger, className }: { onTrigger: () => void, className: string }) => {
const [isDetailPage, setIsDetailPage] = useState(false)
const router = useRouter()
const blinko = RootStore.Get(BlinkoStore)

useEffect(() => {
setIsDetailPage(router.pathname.includes('/detail'))
}, [router.pathname])
Expand All @@ -185,6 +209,13 @@ export const LeftCickMenu = observer(({ onTrigger, className }: { onTrigger: ()
<DropdownItem key="ArchivedItem" >
<ArchivedItem />
</DropdownItem>

{blinko.config.value?.isUseAI ? (
<DropdownItem key="AITagItem">
<AITagItem />
</DropdownItem>
) : <></>}

<DropdownItem key="DeleteItem" className="text-danger" >
<DeleteItem />
</DropdownItem>
Expand Down
56 changes: 56 additions & 0 deletions src/components/Common/CustomCheckbox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Icon } from "@iconify/react";
import {useCheckbox, Chip, VisuallyHidden, tv} from "@nextui-org/react";

const checkbox = tv({
slots: {
base: "border-default hover:bg-primary hover:bg-opacity-20",
content: "text-foreground pl-1"
},
variants: {
isSelected: {
true: {
base: "border-primary bg-primary hover:bg-primary hover:border-primary",
content: "text-primary-foreground"
}
},
isFocusVisible: {
true: {
base: "",
}
}
}
})

export const CustomCheckbox = (props) => {
const {
children,
isSelected,
isFocusVisible,
getBaseProps,
getLabelProps,
getInputProps,
} = useCheckbox({
...props
})

const styles = checkbox({ isSelected, isFocusVisible })

return (
<label {...getBaseProps()}>
<VisuallyHidden>
<input {...getInputProps()} />
</VisuallyHidden>
<Chip
classNames={{
base: styles.base(),
content: styles.content(),
}}
color="primary"
variant="faded"
{...getLabelProps()}
>
{children ? children : isSelected ? "Enabled" : "Disabled"}
</Chip>
</label>
);
}
Loading

0 comments on commit c4b0bed

Please sign in to comment.