Add QuillSense support with settings and integration
- Introduced new "QuillSense" feature for AI-assisted book creation. - Added QuillSense settings panel with advanced options and disable/enable functionality. - Updated GhostWriter and TextEditor components to respect QuillSense settings. - Extended models and repositories to track and manage QuillSense state per book. - Localized new strings for English and French.
This commit is contained in:
@@ -77,6 +77,7 @@ export default function ScribeControllerBar() {
|
||||
publicationDate: response.desiredReleaseDate,
|
||||
desiredWordCount: response.desiredWordCount,
|
||||
totalWordCount: response.desiredWordCount,
|
||||
quillsenseEnabled: response.quillsenseEnabled,
|
||||
});
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
@@ -141,7 +142,7 @@ export default function ScribeControllerBar() {
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
{
|
||||
hasAccess &&
|
||||
hasAccess && book?.quillsenseEnabled !== false &&
|
||||
<CreditCounter isCredit={isSubTierTwo}/>
|
||||
}
|
||||
<div
|
||||
|
||||
@@ -266,6 +266,7 @@ export default function BookList() {
|
||||
totalWordCount: 0,
|
||||
localBook: localBookOnly,
|
||||
coverImage: bookResponse?.coverImage ? 'data:image/jpeg;base64,' + bookResponse.coverImage : '',
|
||||
quillsenseEnabled: bookResponse?.quillsenseEnabled,
|
||||
});
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {RefObject, useRef} from "react";
|
||||
import PanelHeader from "@/components/PanelHeader";
|
||||
import LocationComponent from "@/components/book/settings/locations/LocationComponent";
|
||||
import CharacterComponent from "@/components/book/settings/characters/CharacterComponent";
|
||||
import QuillSenseSetting from "@/components/book/settings/quillsense/QuillSenseSetting";
|
||||
import {useTranslations} from "next-intl"; // Ajouté pour la traduction
|
||||
|
||||
export default function BookSettingOption(
|
||||
@@ -35,7 +36,10 @@ export default function BookSettingOption(
|
||||
const characterRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{
|
||||
handleSave: () => Promise<void>
|
||||
}>(null);
|
||||
|
||||
const quillSenseRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{
|
||||
handleSave: () => Promise<void>
|
||||
}>(null);
|
||||
|
||||
function renderTitle(): string {
|
||||
switch (setting) {
|
||||
case 'basic-information':
|
||||
@@ -54,6 +58,8 @@ export default function BookSettingOption(
|
||||
return t("bookSettingOption.objectsList");
|
||||
case 'goals':
|
||||
return t("bookSettingOption.bookGoals");
|
||||
case 'quillsense':
|
||||
return t("bookSettingOption.quillsense");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@@ -79,6 +85,9 @@ export default function BookSettingOption(
|
||||
case 'characters':
|
||||
characterRef.current?.handleSave();
|
||||
break;
|
||||
case 'quillsense':
|
||||
quillSenseRef.current?.handleSave();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -109,6 +118,8 @@ export default function BookSettingOption(
|
||||
<LocationComponent ref={locationRef}/>
|
||||
) : setting === 'characters' ? (
|
||||
<CharacterComponent ref={characterRef}/>
|
||||
) : setting === 'quillsense' ? (
|
||||
<QuillSenseSetting ref={quillSenseRef}/>
|
||||
) : <div
|
||||
className="text-text-secondary py-4 text-center">{t("bookSettingOption.notAvailable")}</div>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
// Removed Next.js Link import for Electron
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import {faBook, faGlobe, faListAlt, faMapMarkedAlt, faPencilAlt, faUser} from "@fortawesome/free-solid-svg-icons";
|
||||
import {faBook, faFeather, faGlobe, faListAlt, faMapMarkedAlt, faPencilAlt, faUser} from "@fortawesome/free-solid-svg-icons";
|
||||
import {Dispatch, SetStateAction} from "react";
|
||||
import {IconDefinition} from "@fortawesome/fontawesome-svg-core";
|
||||
import {useTranslations} from "next-intl";
|
||||
@@ -53,6 +53,11 @@ export default function BookSettingSidebar(
|
||||
name: 'bookSetting.characters',
|
||||
icon: faUser
|
||||
},
|
||||
{
|
||||
id: 'quillsense',
|
||||
name: 'bookSetting.quillsense',
|
||||
icon: faFeather
|
||||
},
|
||||
// {
|
||||
// id: 'objects',
|
||||
// name: t('bookSetting.objects'),
|
||||
|
||||
@@ -483,7 +483,7 @@ export default function TextEditor() {
|
||||
onClick={handleShowUserSettings}
|
||||
icon={faCog}
|
||||
/>
|
||||
{chapter?.chapterContent.version === 2 && !isCurrentlyOffline() && !book?.localBook && (
|
||||
{chapter?.chapterContent.version === 2 && !isCurrentlyOffline() && !book?.localBook && book?.quillsenseEnabled !== false && (
|
||||
<CollapsableButton
|
||||
showCollapsable={showGhostWriter}
|
||||
text={t("textEditor.ghostWriter")}
|
||||
|
||||
@@ -260,19 +260,25 @@ export default function GhostWriter() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasAccess) {
|
||||
if (!hasAccess || !book?.quillsenseEnabled) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div
|
||||
className="bg-tertiary/90 backdrop-blur-sm p-10 rounded-2xl shadow-2xl text-center border border-secondary/50 max-w-md">
|
||||
<h2 className="text-2xl font-['ADLaM_Display'] text-text-primary mb-4">{t("ghostWriter.title")}</h2>
|
||||
<p className="text-muted mb-6 text-lg leading-relaxed">{t("ghostWriter.subscriptionRequired")}</p>
|
||||
<button
|
||||
onClick={(): string => window.location.href = '/pricing'}
|
||||
className="px-6 py-3 bg-primary text-text-primary rounded-xl hover:bg-primary-dark transition-all duration-200 hover:scale-105 shadow-md hover:shadow-lg font-semibold"
|
||||
>
|
||||
{t("ghostWriter.subscribe")}
|
||||
</button>
|
||||
<p className="text-muted mb-6 text-lg leading-relaxed">
|
||||
{!book?.quillsenseEnabled
|
||||
? t("ghostWriter.quillsenseDisabled")
|
||||
: t("ghostWriter.subscriptionRequired")}
|
||||
</p>
|
||||
{hasAccess && !book?.quillsenseEnabled ? null : (
|
||||
<button
|
||||
onClick={(): string => window.location.href = '/pricing'}
|
||||
className="px-6 py-3 bg-primary text-text-primary rounded-xl hover:bg-primary-dark transition-all duration-200 hover:scale-105 shadow-md hover:shadow-lg font-semibold"
|
||||
>
|
||||
{t("ghostWriter.subscribe")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -171,7 +171,16 @@ export default function ComposerRightBar() {
|
||||
<div className="bg-tertiary border-l border-secondary/50 p-3 flex flex-col space-y-3 shadow-xl">
|
||||
{book ? editorComponents
|
||||
.filter((component: PanelComponent):boolean => {
|
||||
return !((isCurrentlyOffline() || book?.localBook) && component.id === 1);
|
||||
// Filter QuillSense if offline, local book, or quillsenseEnabled is false
|
||||
if (component.id === 1) {
|
||||
if (isCurrentlyOffline() || book?.localBook) {
|
||||
return false;
|
||||
}
|
||||
if (book?.quillsenseEnabled === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((component: PanelComponent) => (
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user