Better animation for sidebar transitions (#133)
* Add transition for BooknoteItem * Add Tab switch animations and tooltip 'Toc' translations. * Use 'Table of Contents' instead of 'Toc' as key.
This commit is contained in:
@@ -114,6 +114,7 @@
|
||||
"Speak": "Sprechen",
|
||||
"Subjects:": "Themen:",
|
||||
"System Fonts": "System-Schriftarten",
|
||||
"Table of Contents": "Inhaltsverzeichnis",
|
||||
"TTS not supported in this device": "TTS wird auf diesem Gerät nicht unterstützt",
|
||||
"Theme Color": "Themenfarbe",
|
||||
"Theme Mode": "Themenmodus",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Leer",
|
||||
"Subjects:": "Temas:",
|
||||
"System Fonts": "Fuentes del sistema",
|
||||
"Table of Contents": "Tabla de contenidos",
|
||||
"TTS not supported in this device": "TTS no es compatible con este dispositivo",
|
||||
"Theme Color": "Color del tema",
|
||||
"Theme Mode": "Modo del tema",
|
||||
@@ -129,4 +130,4 @@
|
||||
"Wikipedia": "Wikipedia",
|
||||
"Writing Mode": "Modo de escritura",
|
||||
"Your Library": "Tu biblioteca"
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Lire",
|
||||
"Subjects:": "Sujets :",
|
||||
"System Fonts": "Polices système",
|
||||
"Table of Contents": "Table des matières",
|
||||
"TTS not supported in this device": "La synthèse vocale n'est pas prise en charge sur cet appareil",
|
||||
"Theme Color": "Couleur du thème",
|
||||
"Theme Mode": "Mode du thème",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Bicara",
|
||||
"Subjects:": "Subjek:",
|
||||
"System Fonts": "Font Sistem",
|
||||
"Table of Contents": "Daftar Isi",
|
||||
"TTS not supported in this device": "TTS tidak didukung di perangkat ini",
|
||||
"Theme Color": "Warna Tema",
|
||||
"Theme Mode": "Mode Tema",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Leggi",
|
||||
"Subjects:": "Argomenti:",
|
||||
"System Fonts": "Font di sistema",
|
||||
"Table of Contents": "Indice",
|
||||
"TTS not supported in this device": "TTS non supportato su questo dispositivo",
|
||||
"Theme Color": "Colore tema",
|
||||
"Theme Mode": "Modalità tema",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "読み上げ",
|
||||
"Subjects:": "主題:",
|
||||
"System Fonts": "システムフォント",
|
||||
"Table of Contents": "目次",
|
||||
"TTS not supported in this device": "このデバイスではTTSがサポートされていません",
|
||||
"Theme Color": "テーマカラー",
|
||||
"Theme Mode": "テーマモード",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "말하기",
|
||||
"Subjects:": "주제:",
|
||||
"System Fonts": "시스템 글꼴",
|
||||
"Table of Contents": "목차",
|
||||
"TTS not supported in this device": "이 장치에서 TTS가 지원되지 않음",
|
||||
"Theme Color": "테마 색상",
|
||||
"Theme Mode": "테마 모드",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Falar",
|
||||
"Subjects:": "Assuntos:",
|
||||
"System Fonts": "Fontes do Sistema",
|
||||
"Table of Contents": "Índice",
|
||||
"TTS not supported in this device": "TTS não suportado neste dispositivo",
|
||||
"Theme Color": "Cor do Tema",
|
||||
"Theme Mode": "Modo do Tema",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Произнести",
|
||||
"Subjects:": "Темы:",
|
||||
"System Fonts": "Системные шрифты",
|
||||
"Table of Contents": "Содержание",
|
||||
"TTS not supported in this device": "TTS не поддерживается на этом устройстве",
|
||||
"Theme Color": "Цвет темы",
|
||||
"Theme Mode": "Режим темы",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Konuş",
|
||||
"Subjects:": "Konular:",
|
||||
"System Fonts": "Sistem Yazı Tipleri",
|
||||
"Table of Contents": "İçindekiler",
|
||||
"TTS not supported in this device": "Bu cihazda TTS desteklenmiyor",
|
||||
"Theme Color": "Tema Rengi",
|
||||
"Theme Mode": "Tema Modu",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "Đọc",
|
||||
"Subjects:": "Chủ đề:",
|
||||
"System Fonts": "Phông chữ hệ thống",
|
||||
"Table of Contents": "Mục lục",
|
||||
"TTS not supported in this device": "TTS không được hỗ trợ trên thiết bị này",
|
||||
"Theme Color": "Màu chủ đề",
|
||||
"Theme Mode": "Chế độ chủ đề",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "朗读",
|
||||
"Subjects:": "主题",
|
||||
"System Fonts": "系统字体",
|
||||
"Table of Contents": "目录",
|
||||
"TTS not supported in this device": "此设备不支持 TTS",
|
||||
"Theme Color": "主题颜色",
|
||||
"Theme Mode": "主题模式",
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
"Speak": "朗讀",
|
||||
"Subjects:": "主題",
|
||||
"System Fonts": "系統字體",
|
||||
"Table of Contents": "目錄",
|
||||
"TTS not supported in this device": "此設備不支持 TTS",
|
||||
"Theme Color": "主題顏色",
|
||||
"Theme Mode": "主題模式",
|
||||
|
||||
@@ -122,7 +122,12 @@ const BooknoteItem: React.FC<BooknoteItemProps> = ({ bookKey, item }) => {
|
||||
)}
|
||||
onClick={editNote.bind(null, item)}
|
||||
>
|
||||
<div className='align-bottom text-blue-400'>{_('Edit')}</div>
|
||||
<div className={clsx(
|
||||
'align-bottom text-blue-400',
|
||||
'transition duration-300 ease-in-out',
|
||||
'group-hover:opacity-100 opacity-0',
|
||||
'hover:text-blue-600',
|
||||
)}>{_('Edit')}</div>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
@@ -132,7 +137,12 @@ const BooknoteItem: React.FC<BooknoteItemProps> = ({ bookKey, item }) => {
|
||||
)}
|
||||
onClick={deleteNote.bind(null, item)}
|
||||
>
|
||||
<div className='align-bottom text-red-400'>{_('Delete')}</div>
|
||||
<div className={clsx(
|
||||
'align-bottom text-red-400',
|
||||
'transition duration-300 ease-in-out',
|
||||
'group-hover:opacity-100 opacity-0',
|
||||
'hover:text-red-600',
|
||||
)}>{_('Delete')}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,8 @@ const SidebarContent: React.FC<{
|
||||
const { getConfig, setConfig } = useBookDataStore();
|
||||
const config = getConfig(sideBarBookKey);
|
||||
const [activeTab, setActiveTab] = useState(config?.viewSettings?.sideBarTab || 'toc');
|
||||
const [fade, setFade] = useState(false);
|
||||
const [targetTab, setTargetTab] = useState(activeTab);
|
||||
|
||||
useEffect(() => {
|
||||
const container = scrollContainerRef.current;
|
||||
@@ -49,10 +51,17 @@ const SidebarContent: React.FC<{
|
||||
}, [sideBarBookKey]);
|
||||
|
||||
const handleTabChange = (tab: string) => {
|
||||
setFade(true);
|
||||
const timeout = setTimeout(() => {
|
||||
setFade(false)
|
||||
setTargetTab(tab);
|
||||
setConfig(sideBarBookKey!, config);
|
||||
clearTimeout(timeout);
|
||||
}, 300);
|
||||
|
||||
setActiveTab(tab);
|
||||
const config = getConfig(sideBarBookKey!)!;
|
||||
config.viewSettings!.sideBarTab = tab;
|
||||
setConfig(sideBarBookKey!, config);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -63,14 +72,20 @@ const SidebarContent: React.FC<{
|
||||
'font-sans text-sm font-normal shadow-inner',
|
||||
)}
|
||||
>
|
||||
<div ref={scrollContainerRef} className='scroll-container overflow-y-auto'>
|
||||
{activeTab === 'toc' && bookDoc.toc && (
|
||||
<div
|
||||
ref={scrollContainerRef}
|
||||
className={clsx(
|
||||
'scroll-container overflow-y-auto transition-opacity duration-300 ease-in-out',
|
||||
{ 'opacity-0': fade, 'opacity-100': !fade }
|
||||
)}
|
||||
>
|
||||
{targetTab === 'toc' && bookDoc.toc && (
|
||||
<TOCView toc={bookDoc.toc} bookKey={sideBarBookKey} />
|
||||
)}
|
||||
{activeTab === 'annotations' && (
|
||||
{targetTab === 'annotations' && (
|
||||
<BooknoteView type='annotation' toc={bookDoc.toc ?? []} bookKey={sideBarBookKey} />
|
||||
)}
|
||||
{activeTab === 'bookmarks' && (
|
||||
{targetTab === 'bookmarks' && (
|
||||
<BooknoteView type='bookmark' toc={bookDoc.toc ?? []} bookKey={sideBarBookKey} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -126,7 +126,7 @@ const TOCView: React.FC<{
|
||||
const rect = currentItem.getBoundingClientRect();
|
||||
const isVisible = rect.top >= 0 && rect.bottom <= window.innerHeight;
|
||||
if (!isVisible) {
|
||||
(currentItem as HTMLElement).scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
(currentItem as HTMLElement).scrollIntoView({ behavior: 'instant', block: 'center' });
|
||||
}
|
||||
(currentItem as HTMLElement).setAttribute('aria-current', 'page');
|
||||
}
|
||||
|
||||
@@ -1,23 +1,54 @@
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import { MdToc, MdEditNote, MdBookmarkBorder } from 'react-icons/md';
|
||||
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
|
||||
const TabNavigation: React.FC<{
|
||||
activeTab: string;
|
||||
onTabChange: (tab: string) => void;
|
||||
}> = ({ activeTab, onTabChange }) => (
|
||||
<div className='bottom-tab border-base-300/50 flex w-full border-t'>
|
||||
{['toc', 'annotations', 'bookmarks'].map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
className={`m-1.5 flex-1 rounded-md p-2 ${activeTab === tab ? 'bg-base-300' : ''}`}
|
||||
onClick={() => onTabChange(tab)}
|
||||
>
|
||||
{tab === 'toc' && <MdToc size={20} className='mx-auto' />}
|
||||
{tab === 'annotations' && <MdEditNote size={20} className='mx-auto' />}
|
||||
{tab === 'bookmarks' && <MdBookmarkBorder size={20} className='mx-auto' />}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}> = ({ activeTab, onTabChange }) => {
|
||||
const _ = useTranslation();
|
||||
|
||||
const tabs = ['toc', 'annotations', 'bookmarks'];
|
||||
|
||||
return (
|
||||
<div className="bottom-tab border-base-300/50 flex w-full border-t relative">
|
||||
<div
|
||||
className={clsx(
|
||||
'absolute bottom-0 left-0 h-full w-1/3 bg-base-300 -z-10',
|
||||
'transition-transform duration-300 transform',
|
||||
activeTab === 'toc' && 'translate-x-0',
|
||||
activeTab === 'annotations' && 'translate-x-full',
|
||||
activeTab === 'bookmarks' && 'translate-x-[200%]',
|
||||
)}
|
||||
/>
|
||||
{tabs.map((tab) => (
|
||||
<div
|
||||
key={tab}
|
||||
className='tooltip z-50 tooltip-top m-1.5 flex-1 rounded-md p-2 cursor-pointer'
|
||||
data-tip={tab === 'toc' ? _('Table of Contents') : tab === 'annotations' ? _('Annotate') : _('Bookmark')}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
'',
|
||||
)}
|
||||
onClick={() => onTabChange(tab)}
|
||||
>
|
||||
{
|
||||
tab === 'toc' ? (
|
||||
<MdToc size={20} className='mx-auto' />
|
||||
) : tab === 'annotations' ? (
|
||||
<MdEditNote size={20} className='mx-auto' />
|
||||
) : (
|
||||
<MdBookmarkBorder size={20} className='mx-auto' />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default TabNavigation;
|
||||
|
||||
Reference in New Issue
Block a user