first commit

This commit is contained in:
Ichitux
2026-04-05 03:08:53 +02:00
commit 1082d36c12
28015 changed files with 3767672 additions and 0 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+14
View File
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/book-icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CreaBook - AI Book Generator</title>
<script type="module" crossorigin src="/assets/index-C5xBjB0t.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CVQt-qUM.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/book-icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CreaBook - AI Book Generator</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Montserrat:ital,wght@0,100..900;1,100..900&family=Pacifico&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+115
View File
@@ -0,0 +1,115 @@
{
"hash": "deb88d1e",
"configHash": "e64eb32e",
"lockfileHash": "fe4eb8a2",
"browserHash": "c9f0ad5b",
"optimized": {
"react": {
"src": "../../../../node_modules/react/index.js",
"file": "react.js",
"fileHash": "80d72dea",
"needsInterop": true
},
"react-dom": {
"src": "../../../../node_modules/react-dom/index.js",
"file": "react-dom.js",
"fileHash": "3f8ff889",
"needsInterop": true
},
"react/jsx-dev-runtime": {
"src": "../../../../node_modules/react/jsx-dev-runtime.js",
"file": "react_jsx-dev-runtime.js",
"fileHash": "05119472",
"needsInterop": true
},
"react/jsx-runtime": {
"src": "../../../../node_modules/react/jsx-runtime.js",
"file": "react_jsx-runtime.js",
"fileHash": "e0024c91",
"needsInterop": true
},
"@tanstack/react-query": {
"src": "../../../../node_modules/@tanstack/react-query/build/modern/index.js",
"file": "@tanstack_react-query.js",
"fileHash": "4d070117",
"needsInterop": false
},
"axios": {
"src": "../../../../node_modules/axios/index.js",
"file": "axios.js",
"fileHash": "a4419c2e",
"needsInterop": false
},
"lucide-react": {
"src": "../../../../node_modules/lucide-react/dist/esm/lucide-react.js",
"file": "lucide-react.js",
"fileHash": "92a1456b",
"needsInterop": false
},
"react-dom/client": {
"src": "../../../../node_modules/react-dom/client.js",
"file": "react-dom_client.js",
"fileHash": "86bf4335",
"needsInterop": true
},
"react-konva": {
"src": "../../../../node_modules/react-konva/es/ReactKonva.js",
"file": "react-konva.js",
"fileHash": "56221f90",
"needsInterop": false
},
"react-router-dom": {
"src": "../../../../node_modules/react-router-dom/dist/index.js",
"file": "react-router-dom.js",
"fileHash": "457f2587",
"needsInterop": false
},
"zustand": {
"src": "../../../../node_modules/zustand/esm/index.mjs",
"file": "zustand.js",
"fileHash": "848a6c38",
"needsInterop": false
},
"i18next": {
"src": "../../../../node_modules/i18next/dist/esm/i18next.js",
"file": "i18next.js",
"fileHash": "3d2d9026",
"needsInterop": false
},
"react-i18next": {
"src": "../../../../node_modules/react-i18next/dist/es/index.js",
"file": "react-i18next.js",
"fileHash": "78d9a217",
"needsInterop": false
},
"i18next-browser-languagedetector": {
"src": "../../../../node_modules/i18next-browser-languagedetector/dist/esm/i18nextBrowserLanguageDetector.js",
"file": "i18next-browser-languagedetector.js",
"fileHash": "09be5c13",
"needsInterop": false
}
},
"chunks": {
"chunk-CITXGXPZ": {
"file": "chunk-CITXGXPZ.js"
},
"chunk-DRQXKEUS": {
"file": "chunk-DRQXKEUS.js"
},
"chunk-TJ6I66L4": {
"file": "chunk-TJ6I66L4.js"
},
"chunk-RMSUKPN2": {
"file": "chunk-RMSUKPN2.js"
},
"chunk-JYSI5OBP": {
"file": "chunk-JYSI5OBP.js"
},
"chunk-7URR3GLA": {
"file": "chunk-7URR3GLA.js"
},
"chunk-4MBMRILA": {
"file": "chunk-4MBMRILA.js"
}
}
}
+2753
View File
File diff suppressed because it is too large Load Diff
+7
View File
File diff suppressed because one or more lines are too long
+57
View File
@@ -0,0 +1,57 @@
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __typeError = (msg) => {
throw TypeError(msg);
};
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
var __privateWrapper = (obj, member, setter, getter) => ({
set _(value) {
__privateSet(obj, member, value, setter);
},
get _() {
return __privateGet(obj, member, getter);
}
});
export {
__commonJS,
__export,
__toESM,
__privateGet,
__privateAdd,
__privateSet,
__privateMethod,
__privateWrapper
};
//# sourceMappingURL=chunk-4MBMRILA.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+1906
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+100
View File
@@ -0,0 +1,100 @@
import {
require_react
} from "./chunk-7URR3GLA.js";
import {
__commonJS
} from "./chunk-4MBMRILA.js";
// ../node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js
var require_use_sync_external_store_shim_development = __commonJS({
"../node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js"(exports) {
"use strict";
(function() {
function is(x, y) {
return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
}
function useSyncExternalStore$2(subscribe, getSnapshot) {
didWarnOld18Alpha || void 0 === React.startTransition || (didWarnOld18Alpha = true, console.error(
"You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
));
var value = getSnapshot();
if (!didWarnUncachedGetSnapshot) {
var cachedValue = getSnapshot();
objectIs(value, cachedValue) || (console.error(
"The result of getSnapshot should be cached to avoid an infinite loop"
), didWarnUncachedGetSnapshot = true);
}
cachedValue = useState({
inst: { value, getSnapshot }
});
var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
useLayoutEffect(
function() {
inst.value = value;
inst.getSnapshot = getSnapshot;
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
},
[subscribe, value, getSnapshot]
);
useEffect(
function() {
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
return subscribe(function() {
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
});
},
[subscribe]
);
useDebugValue(value);
return value;
}
function checkIfSnapshotChanged(inst) {
var latestGetSnapshot = inst.getSnapshot;
inst = inst.value;
try {
var nextValue = latestGetSnapshot();
return !objectIs(inst, nextValue);
} catch (error) {
return true;
}
}
function useSyncExternalStore$1(subscribe, getSnapshot) {
return getSnapshot();
}
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
var React = require_react(), objectIs = "function" === typeof Object.is ? Object.is : is, useState = React.useState, useEffect = React.useEffect, useLayoutEffect = React.useLayoutEffect, useDebugValue = React.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
exports.useSyncExternalStore = void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim;
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
})();
}
});
// ../node_modules/use-sync-external-store/shim/index.js
var require_shim = __commonJS({
"../node_modules/use-sync-external-store/shim/index.js"(exports, module) {
"use strict";
if (false) {
module.exports = null;
} else {
module.exports = require_use_sync_external_store_shim_development();
}
}
});
export {
require_shim
};
/*! Bundled license information:
use-sync-external-store/cjs/use-sync-external-store-shim.development.js:
(**
* @license React
* use-sync-external-store-shim.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
*/
//# sourceMappingURL=chunk-CITXGXPZ.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../../../node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js", "../../../../node_modules/use-sync-external-store/shim/index.js"],
"sourcesContent": ["/**\n * @license React\n * use-sync-external-store-shim.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function is(x, y) {\n return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);\n }\n function useSyncExternalStore$2(subscribe, getSnapshot) {\n didWarnOld18Alpha ||\n void 0 === React.startTransition ||\n ((didWarnOld18Alpha = !0),\n console.error(\n \"You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release.\"\n ));\n var value = getSnapshot();\n if (!didWarnUncachedGetSnapshot) {\n var cachedValue = getSnapshot();\n objectIs(value, cachedValue) ||\n (console.error(\n \"The result of getSnapshot should be cached to avoid an infinite loop\"\n ),\n (didWarnUncachedGetSnapshot = !0));\n }\n cachedValue = useState({\n inst: { value: value, getSnapshot: getSnapshot }\n });\n var inst = cachedValue[0].inst,\n forceUpdate = cachedValue[1];\n useLayoutEffect(\n function () {\n inst.value = value;\n inst.getSnapshot = getSnapshot;\n checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });\n },\n [subscribe, value, getSnapshot]\n );\n useEffect(\n function () {\n checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });\n return subscribe(function () {\n checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });\n });\n },\n [subscribe]\n );\n useDebugValue(value);\n return value;\n }\n function checkIfSnapshotChanged(inst) {\n var latestGetSnapshot = inst.getSnapshot;\n inst = inst.value;\n try {\n var nextValue = latestGetSnapshot();\n return !objectIs(inst, nextValue);\n } catch (error) {\n return !0;\n }\n }\n function useSyncExternalStore$1(subscribe, getSnapshot) {\n return getSnapshot();\n }\n \"undefined\" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&\n \"function\" ===\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&\n __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());\n var React = require(\"react\"),\n objectIs = \"function\" === typeof Object.is ? Object.is : is,\n useState = React.useState,\n useEffect = React.useEffect,\n useLayoutEffect = React.useLayoutEffect,\n useDebugValue = React.useDebugValue,\n didWarnOld18Alpha = !1,\n didWarnUncachedGetSnapshot = !1,\n shim =\n \"undefined\" === typeof window ||\n \"undefined\" === typeof window.document ||\n \"undefined\" === typeof window.document.createElement\n ? useSyncExternalStore$1\n : useSyncExternalStore$2;\n exports.useSyncExternalStore =\n void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim;\n \"undefined\" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&\n \"function\" ===\n typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&\n __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());\n })();\n", "'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('../cjs/use-sync-external-store-shim.production.js');\n} else {\n module.exports = require('../cjs/use-sync-external-store-shim.development.js');\n}\n"],
"mappings": ";;;;;;;;AAAA;AAAA;AAAA;AAWA,KACG,WAAY;AACX,eAAS,GAAG,GAAG,GAAG;AAChB,eAAQ,MAAM,MAAM,MAAM,KAAK,IAAI,MAAM,IAAI,MAAQ,MAAM,KAAK,MAAM;AAAA,MACxE;AACA,eAAS,uBAAuB,WAAW,aAAa;AACtD,6BACE,WAAW,MAAM,oBACf,oBAAoB,MACtB,QAAQ;AAAA,UACN;AAAA,QACF;AACF,YAAI,QAAQ,YAAY;AACxB,YAAI,CAAC,4BAA4B;AAC/B,cAAI,cAAc,YAAY;AAC9B,mBAAS,OAAO,WAAW,MACxB,QAAQ;AAAA,YACP;AAAA,UACF,GACC,6BAA6B;AAAA,QAClC;AACA,sBAAc,SAAS;AAAA,UACrB,MAAM,EAAE,OAAc,YAAyB;AAAA,QACjD,CAAC;AACD,YAAI,OAAO,YAAY,CAAC,EAAE,MACxB,cAAc,YAAY,CAAC;AAC7B;AAAA,UACE,WAAY;AACV,iBAAK,QAAQ;AACb,iBAAK,cAAc;AACnB,mCAAuB,IAAI,KAAK,YAAY,EAAE,KAAW,CAAC;AAAA,UAC5D;AAAA,UACA,CAAC,WAAW,OAAO,WAAW;AAAA,QAChC;AACA;AAAA,UACE,WAAY;AACV,mCAAuB,IAAI,KAAK,YAAY,EAAE,KAAW,CAAC;AAC1D,mBAAO,UAAU,WAAY;AAC3B,qCAAuB,IAAI,KAAK,YAAY,EAAE,KAAW,CAAC;AAAA,YAC5D,CAAC;AAAA,UACH;AAAA,UACA,CAAC,SAAS;AAAA,QACZ;AACA,sBAAc,KAAK;AACnB,eAAO;AAAA,MACT;AACA,eAAS,uBAAuB,MAAM;AACpC,YAAI,oBAAoB,KAAK;AAC7B,eAAO,KAAK;AACZ,YAAI;AACF,cAAI,YAAY,kBAAkB;AAClC,iBAAO,CAAC,SAAS,MAAM,SAAS;AAAA,QAClC,SAAS,OAAO;AACd,iBAAO;AAAA,QACT;AAAA,MACF;AACA,eAAS,uBAAuB,WAAW,aAAa;AACtD,eAAO,YAAY;AAAA,MACrB;AACA,sBAAgB,OAAO,kCACrB,eACE,OAAO,+BAA+B,+BACxC,+BAA+B,4BAA4B,MAAM,CAAC;AACpE,UAAI,QAAQ,iBACV,WAAW,eAAe,OAAO,OAAO,KAAK,OAAO,KAAK,IACzD,WAAW,MAAM,UACjB,YAAY,MAAM,WAClB,kBAAkB,MAAM,iBACxB,gBAAgB,MAAM,eACtB,oBAAoB,OACpB,6BAA6B,OAC7B,OACE,gBAAgB,OAAO,UACvB,gBAAgB,OAAO,OAAO,YAC9B,gBAAgB,OAAO,OAAO,SAAS,gBACnC,yBACA;AACR,cAAQ,uBACN,WAAW,MAAM,uBAAuB,MAAM,uBAAuB;AACvE,sBAAgB,OAAO,kCACrB,eACE,OAAO,+BAA+B,8BACxC,+BAA+B,2BAA2B,MAAM,CAAC;AAAA,IACrE,GAAG;AAAA;AAAA;;;AC9FL;AAAA;AAAA;AAEA,QAAI,OAAuC;AACzC,aAAO,UAAU;AAAA,IACnB,OAAO;AACL,aAAO,UAAU;AAAA,IACnB;AAAA;AAAA;",
"names": []
}
+2266
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+928
View File
@@ -0,0 +1,928 @@
import {
require_react
} from "./chunk-7URR3GLA.js";
import {
__commonJS
} from "./chunk-4MBMRILA.js";
// ../node_modules/react/cjs/react-jsx-runtime.development.js
var require_react_jsx_runtime_development = __commonJS({
"../node_modules/react/cjs/react-jsx-runtime.development.js"(exports) {
"use strict";
if (true) {
(function() {
"use strict";
var React = require_react();
var REACT_ELEMENT_TYPE = Symbol.for("react.element");
var REACT_PORTAL_TYPE = Symbol.for("react.portal");
var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
var REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode");
var REACT_PROFILER_TYPE = Symbol.for("react.profiler");
var REACT_PROVIDER_TYPE = Symbol.for("react.provider");
var REACT_CONTEXT_TYPE = Symbol.for("react.context");
var REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref");
var REACT_SUSPENSE_TYPE = Symbol.for("react.suspense");
var REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list");
var REACT_MEMO_TYPE = Symbol.for("react.memo");
var REACT_LAZY_TYPE = Symbol.for("react.lazy");
var REACT_OFFSCREEN_TYPE = Symbol.for("react.offscreen");
var MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = "@@iterator";
function getIteratorFn(maybeIterable) {
if (maybeIterable === null || typeof maybeIterable !== "object") {
return null;
}
var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
if (typeof maybeIterator === "function") {
return maybeIterator;
}
return null;
}
var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
function error(format) {
{
{
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
printWarning("error", format, args);
}
}
}
function printWarning(level, format, args) {
{
var ReactDebugCurrentFrame2 = ReactSharedInternals.ReactDebugCurrentFrame;
var stack = ReactDebugCurrentFrame2.getStackAddendum();
if (stack !== "") {
format += "%s";
args = args.concat([stack]);
}
var argsWithFormat = args.map(function(item) {
return String(item);
});
argsWithFormat.unshift("Warning: " + format);
Function.prototype.apply.call(console[level], console, argsWithFormat);
}
}
var enableScopeAPI = false;
var enableCacheElement = false;
var enableTransitionTracing = false;
var enableLegacyHidden = false;
var enableDebugTracing = false;
var REACT_MODULE_REFERENCE;
{
REACT_MODULE_REFERENCE = Symbol.for("react.module.reference");
}
function isValidElementType(type) {
if (typeof type === "string" || typeof type === "function") {
return true;
}
if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableCacheElement || enableTransitionTracing) {
return true;
}
if (typeof type === "object" && type !== null) {
if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object
// types supported by any Flight configuration anywhere since
// we don't know which Flight build this will end up being used
// with.
type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== void 0) {
return true;
}
}
return false;
}
function getWrappedName(outerType, innerType, wrapperName) {
var displayName = outerType.displayName;
if (displayName) {
return displayName;
}
var functionName = innerType.displayName || innerType.name || "";
return functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName;
}
function getContextName(type) {
return type.displayName || "Context";
}
function getComponentNameFromType(type) {
if (type == null) {
return null;
}
{
if (typeof type.tag === "number") {
error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.");
}
}
if (typeof type === "function") {
return type.displayName || type.name || null;
}
if (typeof type === "string") {
return type;
}
switch (type) {
case REACT_FRAGMENT_TYPE:
return "Fragment";
case REACT_PORTAL_TYPE:
return "Portal";
case REACT_PROFILER_TYPE:
return "Profiler";
case REACT_STRICT_MODE_TYPE:
return "StrictMode";
case REACT_SUSPENSE_TYPE:
return "Suspense";
case REACT_SUSPENSE_LIST_TYPE:
return "SuspenseList";
}
if (typeof type === "object") {
switch (type.$$typeof) {
case REACT_CONTEXT_TYPE:
var context = type;
return getContextName(context) + ".Consumer";
case REACT_PROVIDER_TYPE:
var provider = type;
return getContextName(provider._context) + ".Provider";
case REACT_FORWARD_REF_TYPE:
return getWrappedName(type, type.render, "ForwardRef");
case REACT_MEMO_TYPE:
var outerName = type.displayName || null;
if (outerName !== null) {
return outerName;
}
return getComponentNameFromType(type.type) || "Memo";
case REACT_LAZY_TYPE: {
var lazyComponent = type;
var payload = lazyComponent._payload;
var init = lazyComponent._init;
try {
return getComponentNameFromType(init(payload));
} catch (x) {
return null;
}
}
}
}
return null;
}
var assign = Object.assign;
var disabledDepth = 0;
var prevLog;
var prevInfo;
var prevWarn;
var prevError;
var prevGroup;
var prevGroupCollapsed;
var prevGroupEnd;
function disabledLog() {
}
disabledLog.__reactDisabledLog = true;
function disableLogs() {
{
if (disabledDepth === 0) {
prevLog = console.log;
prevInfo = console.info;
prevWarn = console.warn;
prevError = console.error;
prevGroup = console.group;
prevGroupCollapsed = console.groupCollapsed;
prevGroupEnd = console.groupEnd;
var props = {
configurable: true,
enumerable: true,
value: disabledLog,
writable: true
};
Object.defineProperties(console, {
info: props,
log: props,
warn: props,
error: props,
group: props,
groupCollapsed: props,
groupEnd: props
});
}
disabledDepth++;
}
}
function reenableLogs() {
{
disabledDepth--;
if (disabledDepth === 0) {
var props = {
configurable: true,
enumerable: true,
writable: true
};
Object.defineProperties(console, {
log: assign({}, props, {
value: prevLog
}),
info: assign({}, props, {
value: prevInfo
}),
warn: assign({}, props, {
value: prevWarn
}),
error: assign({}, props, {
value: prevError
}),
group: assign({}, props, {
value: prevGroup
}),
groupCollapsed: assign({}, props, {
value: prevGroupCollapsed
}),
groupEnd: assign({}, props, {
value: prevGroupEnd
})
});
}
if (disabledDepth < 0) {
error("disabledDepth fell below zero. This is a bug in React. Please file an issue.");
}
}
}
var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var prefix;
function describeBuiltInComponentFrame(name, source, ownerFn) {
{
if (prefix === void 0) {
try {
throw Error();
} catch (x) {
var match = x.stack.trim().match(/\n( *(at )?)/);
prefix = match && match[1] || "";
}
}
return "\n" + prefix + name;
}
}
var reentry = false;
var componentFrameCache;
{
var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map;
componentFrameCache = new PossiblyWeakMap();
}
function describeNativeComponentFrame(fn, construct) {
if (!fn || reentry) {
return "";
}
{
var frame = componentFrameCache.get(fn);
if (frame !== void 0) {
return frame;
}
}
var control;
reentry = true;
var previousPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = void 0;
var previousDispatcher;
{
previousDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = null;
disableLogs();
}
try {
if (construct) {
var Fake = function() {
throw Error();
};
Object.defineProperty(Fake.prototype, "props", {
set: function() {
throw Error();
}
});
if (typeof Reflect === "object" && Reflect.construct) {
try {
Reflect.construct(Fake, []);
} catch (x) {
control = x;
}
Reflect.construct(fn, [], Fake);
} else {
try {
Fake.call();
} catch (x) {
control = x;
}
fn.call(Fake.prototype);
}
} else {
try {
throw Error();
} catch (x) {
control = x;
}
fn();
}
} catch (sample) {
if (sample && control && typeof sample.stack === "string") {
var sampleLines = sample.stack.split("\n");
var controlLines = control.stack.split("\n");
var s = sampleLines.length - 1;
var c = controlLines.length - 1;
while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) {
c--;
}
for (; s >= 1 && c >= 0; s--, c--) {
if (sampleLines[s] !== controlLines[c]) {
if (s !== 1 || c !== 1) {
do {
s--;
c--;
if (c < 0 || sampleLines[s] !== controlLines[c]) {
var _frame = "\n" + sampleLines[s].replace(" at new ", " at ");
if (fn.displayName && _frame.includes("<anonymous>")) {
_frame = _frame.replace("<anonymous>", fn.displayName);
}
{
if (typeof fn === "function") {
componentFrameCache.set(fn, _frame);
}
}
return _frame;
}
} while (s >= 1 && c >= 0);
}
break;
}
}
}
} finally {
reentry = false;
{
ReactCurrentDispatcher.current = previousDispatcher;
reenableLogs();
}
Error.prepareStackTrace = previousPrepareStackTrace;
}
var name = fn ? fn.displayName || fn.name : "";
var syntheticFrame = name ? describeBuiltInComponentFrame(name) : "";
{
if (typeof fn === "function") {
componentFrameCache.set(fn, syntheticFrame);
}
}
return syntheticFrame;
}
function describeFunctionComponentFrame(fn, source, ownerFn) {
{
return describeNativeComponentFrame(fn, false);
}
}
function shouldConstruct(Component) {
var prototype = Component.prototype;
return !!(prototype && prototype.isReactComponent);
}
function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) {
if (type == null) {
return "";
}
if (typeof type === "function") {
{
return describeNativeComponentFrame(type, shouldConstruct(type));
}
}
if (typeof type === "string") {
return describeBuiltInComponentFrame(type);
}
switch (type) {
case REACT_SUSPENSE_TYPE:
return describeBuiltInComponentFrame("Suspense");
case REACT_SUSPENSE_LIST_TYPE:
return describeBuiltInComponentFrame("SuspenseList");
}
if (typeof type === "object") {
switch (type.$$typeof) {
case REACT_FORWARD_REF_TYPE:
return describeFunctionComponentFrame(type.render);
case REACT_MEMO_TYPE:
return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn);
case REACT_LAZY_TYPE: {
var lazyComponent = type;
var payload = lazyComponent._payload;
var init = lazyComponent._init;
try {
return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn);
} catch (x) {
}
}
}
}
return "";
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
var loggedTypeFailures = {};
var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
function setCurrentlyValidatingElement(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);
ReactDebugCurrentFrame.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame.setExtraStackFrame(null);
}
}
}
function checkPropTypes(typeSpecs, values, location, componentName, element) {
{
var has = Function.call.bind(hasOwnProperty);
for (var typeSpecName in typeSpecs) {
if (has(typeSpecs, typeSpecName)) {
var error$1 = void 0;
try {
if (typeof typeSpecs[typeSpecName] !== "function") {
var err = Error((componentName || "React class") + ": " + location + " type `" + typeSpecName + "` is invalid; it must be a function, usually from the `prop-types` package, but received `" + typeof typeSpecs[typeSpecName] + "`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.");
err.name = "Invariant Violation";
throw err;
}
error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED");
} catch (ex) {
error$1 = ex;
}
if (error$1 && !(error$1 instanceof Error)) {
setCurrentlyValidatingElement(element);
error("%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).", componentName || "React class", location, typeSpecName, typeof error$1);
setCurrentlyValidatingElement(null);
}
if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) {
loggedTypeFailures[error$1.message] = true;
setCurrentlyValidatingElement(element);
error("Failed %s type: %s", location, error$1.message);
setCurrentlyValidatingElement(null);
}
}
}
}
}
var isArrayImpl = Array.isArray;
function isArray(a) {
return isArrayImpl(a);
}
function typeName(value) {
{
var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag;
var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
return type;
}
}
function willCoercionThrow(value) {
{
try {
testStringCoercion(value);
return false;
} catch (e) {
return true;
}
}
}
function testStringCoercion(value) {
return "" + value;
}
function checkKeyStringCoercion(value) {
{
if (willCoercionThrow(value)) {
error("The provided key is an unsupported type %s. This value must be coerced to a string before before using it here.", typeName(value));
return testStringCoercion(value);
}
}
}
var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
var RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true
};
var specialPropKeyWarningShown;
var specialPropRefWarningShown;
var didWarnAboutStringRefs;
{
didWarnAboutStringRefs = {};
}
function hasValidRef(config) {
{
if (hasOwnProperty.call(config, "ref")) {
var getter = Object.getOwnPropertyDescriptor(config, "ref").get;
if (getter && getter.isReactWarning) {
return false;
}
}
}
return config.ref !== void 0;
}
function hasValidKey(config) {
{
if (hasOwnProperty.call(config, "key")) {
var getter = Object.getOwnPropertyDescriptor(config, "key").get;
if (getter && getter.isReactWarning) {
return false;
}
}
}
return config.key !== void 0;
}
function warnIfStringRefCannotBeAutoConverted(config, self) {
{
if (typeof config.ref === "string" && ReactCurrentOwner.current && self && ReactCurrentOwner.current.stateNode !== self) {
var componentName = getComponentNameFromType(ReactCurrentOwner.current.type);
if (!didWarnAboutStringRefs[componentName]) {
error('Component "%s" contains the string ref "%s". Support for string refs will be removed in a future major release. This case cannot be automatically converted to an arrow function. We ask you to manually fix this case by using useRef() or createRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref', getComponentNameFromType(ReactCurrentOwner.current.type), config.ref);
didWarnAboutStringRefs[componentName] = true;
}
}
}
}
function defineKeyPropWarningGetter(props, displayName) {
{
var warnAboutAccessingKey = function() {
if (!specialPropKeyWarningShown) {
specialPropKeyWarningShown = true;
error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", displayName);
}
};
warnAboutAccessingKey.isReactWarning = true;
Object.defineProperty(props, "key", {
get: warnAboutAccessingKey,
configurable: true
});
}
}
function defineRefPropWarningGetter(props, displayName) {
{
var warnAboutAccessingRef = function() {
if (!specialPropRefWarningShown) {
specialPropRefWarningShown = true;
error("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", displayName);
}
};
warnAboutAccessingRef.isReactWarning = true;
Object.defineProperty(props, "ref", {
get: warnAboutAccessingRef,
configurable: true
});
}
}
var ReactElement = function(type, key, ref, self, source, owner, props) {
var element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type,
key,
ref,
props,
// Record the component responsible for creating this element.
_owner: owner
};
{
element._store = {};
Object.defineProperty(element._store, "validated", {
configurable: false,
enumerable: false,
writable: true,
value: false
});
Object.defineProperty(element, "_self", {
configurable: false,
enumerable: false,
writable: false,
value: self
});
Object.defineProperty(element, "_source", {
configurable: false,
enumerable: false,
writable: false,
value: source
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
};
function jsxDEV(type, config, maybeKey, source, self) {
{
var propName;
var props = {};
var key = null;
var ref = null;
if (maybeKey !== void 0) {
{
checkKeyStringCoercion(maybeKey);
}
key = "" + maybeKey;
}
if (hasValidKey(config)) {
{
checkKeyStringCoercion(config.key);
}
key = "" + config.key;
}
if (hasValidRef(config)) {
ref = config.ref;
warnIfStringRefCannotBeAutoConverted(config, self);
}
for (propName in config) {
if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === void 0) {
props[propName] = defaultProps[propName];
}
}
}
if (key || ref) {
var displayName = typeof type === "function" ? type.displayName || type.name || "Unknown" : type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
}
}
var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner;
var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame;
function setCurrentlyValidatingElement$1(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);
ReactDebugCurrentFrame$1.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame$1.setExtraStackFrame(null);
}
}
}
var propTypesMisspellWarningShown;
{
propTypesMisspellWarningShown = false;
}
function isValidElement(object) {
{
return typeof object === "object" && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
}
function getDeclarationErrorAddendum() {
{
if (ReactCurrentOwner$1.current) {
var name = getComponentNameFromType(ReactCurrentOwner$1.current.type);
if (name) {
return "\n\nCheck the render method of `" + name + "`.";
}
}
return "";
}
}
function getSourceInfoErrorAddendum(source) {
{
if (source !== void 0) {
var fileName = source.fileName.replace(/^.*[\\\/]/, "");
var lineNumber = source.lineNumber;
return "\n\nCheck your code at " + fileName + ":" + lineNumber + ".";
}
return "";
}
}
var ownerHasKeyUseWarning = {};
function getCurrentComponentErrorInfo(parentType) {
{
var info = getDeclarationErrorAddendum();
if (!info) {
var parentName = typeof parentType === "string" ? parentType : parentType.displayName || parentType.name;
if (parentName) {
info = "\n\nCheck the top-level render call using <" + parentName + ">.";
}
}
return info;
}
}
function validateExplicitKey(element, parentType) {
{
if (!element._store || element._store.validated || element.key != null) {
return;
}
element._store.validated = true;
var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
return;
}
ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
var childOwner = "";
if (element && element._owner && element._owner !== ReactCurrentOwner$1.current) {
childOwner = " It was passed a child from " + getComponentNameFromType(element._owner.type) + ".";
}
setCurrentlyValidatingElement$1(element);
error('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.', currentComponentErrorInfo, childOwner);
setCurrentlyValidatingElement$1(null);
}
}
function validateChildKeys(node, parentType) {
{
if (typeof node !== "object") {
return;
}
if (isArray(node)) {
for (var i = 0; i < node.length; i++) {
var child = node[i];
if (isValidElement(child)) {
validateExplicitKey(child, parentType);
}
}
} else if (isValidElement(node)) {
if (node._store) {
node._store.validated = true;
}
} else if (node) {
var iteratorFn = getIteratorFn(node);
if (typeof iteratorFn === "function") {
if (iteratorFn !== node.entries) {
var iterator = iteratorFn.call(node);
var step;
while (!(step = iterator.next()).done) {
if (isValidElement(step.value)) {
validateExplicitKey(step.value, parentType);
}
}
}
}
}
}
}
function validatePropTypes(element) {
{
var type = element.type;
if (type === null || type === void 0 || typeof type === "string") {
return;
}
var propTypes;
if (typeof type === "function") {
propTypes = type.propTypes;
} else if (typeof type === "object" && (type.$$typeof === REACT_FORWARD_REF_TYPE || // Note: Memo only checks outer props here.
// Inner props are checked in the reconciler.
type.$$typeof === REACT_MEMO_TYPE)) {
propTypes = type.propTypes;
} else {
return;
}
if (propTypes) {
var name = getComponentNameFromType(type);
checkPropTypes(propTypes, element.props, "prop", name, element);
} else if (type.PropTypes !== void 0 && !propTypesMisspellWarningShown) {
propTypesMisspellWarningShown = true;
var _name = getComponentNameFromType(type);
error("Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?", _name || "Unknown");
}
if (typeof type.getDefaultProps === "function" && !type.getDefaultProps.isReactClassApproved) {
error("getDefaultProps is only used on classic React.createClass definitions. Use a static property named `defaultProps` instead.");
}
}
}
function validateFragmentProps(fragment) {
{
var keys = Object.keys(fragment.props);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key !== "children" && key !== "key") {
setCurrentlyValidatingElement$1(fragment);
error("Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.", key);
setCurrentlyValidatingElement$1(null);
break;
}
}
if (fragment.ref !== null) {
setCurrentlyValidatingElement$1(fragment);
error("Invalid attribute `ref` supplied to `React.Fragment`.");
setCurrentlyValidatingElement$1(null);
}
}
}
var didWarnAboutKeySpread = {};
function jsxWithValidation(type, props, key, isStaticChildren, source, self) {
{
var validType = isValidElementType(type);
if (!validType) {
var info = "";
if (type === void 0 || typeof type === "object" && type !== null && Object.keys(type).length === 0) {
info += " You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.";
}
var sourceInfo = getSourceInfoErrorAddendum(source);
if (sourceInfo) {
info += sourceInfo;
} else {
info += getDeclarationErrorAddendum();
}
var typeString;
if (type === null) {
typeString = "null";
} else if (isArray(type)) {
typeString = "array";
} else if (type !== void 0 && type.$$typeof === REACT_ELEMENT_TYPE) {
typeString = "<" + (getComponentNameFromType(type.type) || "Unknown") + " />";
info = " Did you accidentally export a JSX literal instead of a component?";
} else {
typeString = typeof type;
}
error("React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", typeString, info);
}
var element = jsxDEV(type, props, key, source, self);
if (element == null) {
return element;
}
if (validType) {
var children = props.children;
if (children !== void 0) {
if (isStaticChildren) {
if (isArray(children)) {
for (var i = 0; i < children.length; i++) {
validateChildKeys(children[i], type);
}
if (Object.freeze) {
Object.freeze(children);
}
} else {
error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");
}
} else {
validateChildKeys(children, type);
}
}
}
{
if (hasOwnProperty.call(props, "key")) {
var componentName = getComponentNameFromType(type);
var keys = Object.keys(props).filter(function(k) {
return k !== "key";
});
var beforeExample = keys.length > 0 ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" : "{key: someKey}";
if (!didWarnAboutKeySpread[componentName + beforeExample]) {
var afterExample = keys.length > 0 ? "{" + keys.join(": ..., ") + ": ...}" : "{}";
error('A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />', beforeExample, componentName, afterExample, componentName);
didWarnAboutKeySpread[componentName + beforeExample] = true;
}
}
}
if (type === REACT_FRAGMENT_TYPE) {
validateFragmentProps(element);
} else {
validatePropTypes(element);
}
return element;
}
}
function jsxWithValidationStatic(type, props, key) {
{
return jsxWithValidation(type, props, key, true);
}
}
function jsxWithValidationDynamic(type, props, key) {
{
return jsxWithValidation(type, props, key, false);
}
}
var jsx = jsxWithValidationDynamic;
var jsxs = jsxWithValidationStatic;
exports.Fragment = REACT_FRAGMENT_TYPE;
exports.jsx = jsx;
exports.jsxs = jsxs;
})();
}
}
});
// ../node_modules/react/jsx-runtime.js
var require_jsx_runtime = __commonJS({
"../node_modules/react/jsx-runtime.js"(exports, module) {
if (false) {
module.exports = null;
} else {
module.exports = require_react_jsx_runtime_development();
}
}
});
export {
require_jsx_runtime
};
/*! Bundled license information:
react/cjs/react-jsx-runtime.development.js:
(**
* @license React
* react-jsx-runtime.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
*/
//# sourceMappingURL=chunk-JYSI5OBP.js.map
File diff suppressed because one or more lines are too long
+483
View File
@@ -0,0 +1,483 @@
import {
__commonJS
} from "./chunk-4MBMRILA.js";
// ../node_modules/scheduler/cjs/scheduler.development.js
var require_scheduler_development = __commonJS({
"../node_modules/scheduler/cjs/scheduler.development.js"(exports) {
"use strict";
if (true) {
(function() {
"use strict";
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === "function") {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
}
var enableSchedulerDebugging = false;
var enableProfiling = false;
var frameYieldMs = 5;
function push(heap, node) {
var index = heap.length;
heap.push(node);
siftUp(heap, node, index);
}
function peek(heap) {
return heap.length === 0 ? null : heap[0];
}
function pop(heap) {
if (heap.length === 0) {
return null;
}
var first = heap[0];
var last = heap.pop();
if (last !== first) {
heap[0] = last;
siftDown(heap, last, 0);
}
return first;
}
function siftUp(heap, node, i) {
var index = i;
while (index > 0) {
var parentIndex = index - 1 >>> 1;
var parent = heap[parentIndex];
if (compare(parent, node) > 0) {
heap[parentIndex] = node;
heap[index] = parent;
index = parentIndex;
} else {
return;
}
}
}
function siftDown(heap, node, i) {
var index = i;
var length = heap.length;
var halfLength = length >>> 1;
while (index < halfLength) {
var leftIndex = (index + 1) * 2 - 1;
var left = heap[leftIndex];
var rightIndex = leftIndex + 1;
var right = heap[rightIndex];
if (compare(left, node) < 0) {
if (rightIndex < length && compare(right, left) < 0) {
heap[index] = right;
heap[rightIndex] = node;
index = rightIndex;
} else {
heap[index] = left;
heap[leftIndex] = node;
index = leftIndex;
}
} else if (rightIndex < length && compare(right, node) < 0) {
heap[index] = right;
heap[rightIndex] = node;
index = rightIndex;
} else {
return;
}
}
}
function compare(a, b) {
var diff = a.sortIndex - b.sortIndex;
return diff !== 0 ? diff : a.id - b.id;
}
var ImmediatePriority = 1;
var UserBlockingPriority = 2;
var NormalPriority = 3;
var LowPriority = 4;
var IdlePriority = 5;
function markTaskErrored(task, ms) {
}
var hasPerformanceNow = typeof performance === "object" && typeof performance.now === "function";
if (hasPerformanceNow) {
var localPerformance = performance;
exports.unstable_now = function() {
return localPerformance.now();
};
} else {
var localDate = Date;
var initialTime = localDate.now();
exports.unstable_now = function() {
return localDate.now() - initialTime;
};
}
var maxSigned31BitInt = 1073741823;
var IMMEDIATE_PRIORITY_TIMEOUT = -1;
var USER_BLOCKING_PRIORITY_TIMEOUT = 250;
var NORMAL_PRIORITY_TIMEOUT = 5e3;
var LOW_PRIORITY_TIMEOUT = 1e4;
var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;
var taskQueue = [];
var timerQueue = [];
var taskIdCounter = 1;
var currentTask = null;
var currentPriorityLevel = NormalPriority;
var isPerformingWork = false;
var isHostCallbackScheduled = false;
var isHostTimeoutScheduled = false;
var localSetTimeout = typeof setTimeout === "function" ? setTimeout : null;
var localClearTimeout = typeof clearTimeout === "function" ? clearTimeout : null;
var localSetImmediate = typeof setImmediate !== "undefined" ? setImmediate : null;
var isInputPending = typeof navigator !== "undefined" && navigator.scheduling !== void 0 && navigator.scheduling.isInputPending !== void 0 ? navigator.scheduling.isInputPending.bind(navigator.scheduling) : null;
function advanceTimers(currentTime) {
var timer = peek(timerQueue);
while (timer !== null) {
if (timer.callback === null) {
pop(timerQueue);
} else if (timer.startTime <= currentTime) {
pop(timerQueue);
timer.sortIndex = timer.expirationTime;
push(taskQueue, timer);
} else {
return;
}
timer = peek(timerQueue);
}
}
function handleTimeout(currentTime) {
isHostTimeoutScheduled = false;
advanceTimers(currentTime);
if (!isHostCallbackScheduled) {
if (peek(taskQueue) !== null) {
isHostCallbackScheduled = true;
requestHostCallback(flushWork);
} else {
var firstTimer = peek(timerQueue);
if (firstTimer !== null) {
requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
}
}
}
}
function flushWork(hasTimeRemaining, initialTime2) {
isHostCallbackScheduled = false;
if (isHostTimeoutScheduled) {
isHostTimeoutScheduled = false;
cancelHostTimeout();
}
isPerformingWork = true;
var previousPriorityLevel = currentPriorityLevel;
try {
if (enableProfiling) {
try {
return workLoop(hasTimeRemaining, initialTime2);
} catch (error) {
if (currentTask !== null) {
var currentTime = exports.unstable_now();
markTaskErrored(currentTask, currentTime);
currentTask.isQueued = false;
}
throw error;
}
} else {
return workLoop(hasTimeRemaining, initialTime2);
}
} finally {
currentTask = null;
currentPriorityLevel = previousPriorityLevel;
isPerformingWork = false;
}
}
function workLoop(hasTimeRemaining, initialTime2) {
var currentTime = initialTime2;
advanceTimers(currentTime);
currentTask = peek(taskQueue);
while (currentTask !== null && !enableSchedulerDebugging) {
if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) {
break;
}
var callback = currentTask.callback;
if (typeof callback === "function") {
currentTask.callback = null;
currentPriorityLevel = currentTask.priorityLevel;
var didUserCallbackTimeout = currentTask.expirationTime <= currentTime;
var continuationCallback = callback(didUserCallbackTimeout);
currentTime = exports.unstable_now();
if (typeof continuationCallback === "function") {
currentTask.callback = continuationCallback;
} else {
if (currentTask === peek(taskQueue)) {
pop(taskQueue);
}
}
advanceTimers(currentTime);
} else {
pop(taskQueue);
}
currentTask = peek(taskQueue);
}
if (currentTask !== null) {
return true;
} else {
var firstTimer = peek(timerQueue);
if (firstTimer !== null) {
requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
}
return false;
}
}
function unstable_runWithPriority(priorityLevel, eventHandler) {
switch (priorityLevel) {
case ImmediatePriority:
case UserBlockingPriority:
case NormalPriority:
case LowPriority:
case IdlePriority:
break;
default:
priorityLevel = NormalPriority;
}
var previousPriorityLevel = currentPriorityLevel;
currentPriorityLevel = priorityLevel;
try {
return eventHandler();
} finally {
currentPriorityLevel = previousPriorityLevel;
}
}
function unstable_next(eventHandler) {
var priorityLevel;
switch (currentPriorityLevel) {
case ImmediatePriority:
case UserBlockingPriority:
case NormalPriority:
priorityLevel = NormalPriority;
break;
default:
priorityLevel = currentPriorityLevel;
break;
}
var previousPriorityLevel = currentPriorityLevel;
currentPriorityLevel = priorityLevel;
try {
return eventHandler();
} finally {
currentPriorityLevel = previousPriorityLevel;
}
}
function unstable_wrapCallback(callback) {
var parentPriorityLevel = currentPriorityLevel;
return function() {
var previousPriorityLevel = currentPriorityLevel;
currentPriorityLevel = parentPriorityLevel;
try {
return callback.apply(this, arguments);
} finally {
currentPriorityLevel = previousPriorityLevel;
}
};
}
function unstable_scheduleCallback(priorityLevel, callback, options) {
var currentTime = exports.unstable_now();
var startTime2;
if (typeof options === "object" && options !== null) {
var delay = options.delay;
if (typeof delay === "number" && delay > 0) {
startTime2 = currentTime + delay;
} else {
startTime2 = currentTime;
}
} else {
startTime2 = currentTime;
}
var timeout;
switch (priorityLevel) {
case ImmediatePriority:
timeout = IMMEDIATE_PRIORITY_TIMEOUT;
break;
case UserBlockingPriority:
timeout = USER_BLOCKING_PRIORITY_TIMEOUT;
break;
case IdlePriority:
timeout = IDLE_PRIORITY_TIMEOUT;
break;
case LowPriority:
timeout = LOW_PRIORITY_TIMEOUT;
break;
case NormalPriority:
default:
timeout = NORMAL_PRIORITY_TIMEOUT;
break;
}
var expirationTime = startTime2 + timeout;
var newTask = {
id: taskIdCounter++,
callback,
priorityLevel,
startTime: startTime2,
expirationTime,
sortIndex: -1
};
if (startTime2 > currentTime) {
newTask.sortIndex = startTime2;
push(timerQueue, newTask);
if (peek(taskQueue) === null && newTask === peek(timerQueue)) {
if (isHostTimeoutScheduled) {
cancelHostTimeout();
} else {
isHostTimeoutScheduled = true;
}
requestHostTimeout(handleTimeout, startTime2 - currentTime);
}
} else {
newTask.sortIndex = expirationTime;
push(taskQueue, newTask);
if (!isHostCallbackScheduled && !isPerformingWork) {
isHostCallbackScheduled = true;
requestHostCallback(flushWork);
}
}
return newTask;
}
function unstable_pauseExecution() {
}
function unstable_continueExecution() {
if (!isHostCallbackScheduled && !isPerformingWork) {
isHostCallbackScheduled = true;
requestHostCallback(flushWork);
}
}
function unstable_getFirstCallbackNode() {
return peek(taskQueue);
}
function unstable_cancelCallback(task) {
task.callback = null;
}
function unstable_getCurrentPriorityLevel() {
return currentPriorityLevel;
}
var isMessageLoopRunning = false;
var scheduledHostCallback = null;
var taskTimeoutID = -1;
var frameInterval = frameYieldMs;
var startTime = -1;
function shouldYieldToHost() {
var timeElapsed = exports.unstable_now() - startTime;
if (timeElapsed < frameInterval) {
return false;
}
return true;
}
function requestPaint() {
}
function forceFrameRate(fps) {
if (fps < 0 || fps > 125) {
console["error"]("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported");
return;
}
if (fps > 0) {
frameInterval = Math.floor(1e3 / fps);
} else {
frameInterval = frameYieldMs;
}
}
var performWorkUntilDeadline = function() {
if (scheduledHostCallback !== null) {
var currentTime = exports.unstable_now();
startTime = currentTime;
var hasTimeRemaining = true;
var hasMoreWork = true;
try {
hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime);
} finally {
if (hasMoreWork) {
schedulePerformWorkUntilDeadline();
} else {
isMessageLoopRunning = false;
scheduledHostCallback = null;
}
}
} else {
isMessageLoopRunning = false;
}
};
var schedulePerformWorkUntilDeadline;
if (typeof localSetImmediate === "function") {
schedulePerformWorkUntilDeadline = function() {
localSetImmediate(performWorkUntilDeadline);
};
} else if (typeof MessageChannel !== "undefined") {
var channel = new MessageChannel();
var port = channel.port2;
channel.port1.onmessage = performWorkUntilDeadline;
schedulePerformWorkUntilDeadline = function() {
port.postMessage(null);
};
} else {
schedulePerformWorkUntilDeadline = function() {
localSetTimeout(performWorkUntilDeadline, 0);
};
}
function requestHostCallback(callback) {
scheduledHostCallback = callback;
if (!isMessageLoopRunning) {
isMessageLoopRunning = true;
schedulePerformWorkUntilDeadline();
}
}
function requestHostTimeout(callback, ms) {
taskTimeoutID = localSetTimeout(function() {
callback(exports.unstable_now());
}, ms);
}
function cancelHostTimeout() {
localClearTimeout(taskTimeoutID);
taskTimeoutID = -1;
}
var unstable_requestPaint = requestPaint;
var unstable_Profiling = null;
exports.unstable_IdlePriority = IdlePriority;
exports.unstable_ImmediatePriority = ImmediatePriority;
exports.unstable_LowPriority = LowPriority;
exports.unstable_NormalPriority = NormalPriority;
exports.unstable_Profiling = unstable_Profiling;
exports.unstable_UserBlockingPriority = UserBlockingPriority;
exports.unstable_cancelCallback = unstable_cancelCallback;
exports.unstable_continueExecution = unstable_continueExecution;
exports.unstable_forceFrameRate = forceFrameRate;
exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel;
exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode;
exports.unstable_next = unstable_next;
exports.unstable_pauseExecution = unstable_pauseExecution;
exports.unstable_requestPaint = unstable_requestPaint;
exports.unstable_runWithPriority = unstable_runWithPriority;
exports.unstable_scheduleCallback = unstable_scheduleCallback;
exports.unstable_shouldYield = shouldYieldToHost;
exports.unstable_wrapCallback = unstable_wrapCallback;
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === "function") {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error());
}
})();
}
}
});
// ../node_modules/scheduler/index.js
var require_scheduler = __commonJS({
"../node_modules/scheduler/index.js"(exports, module) {
"use strict";
if (false) {
module.exports = null;
} else {
module.exports = require_scheduler_development();
}
}
});
export {
require_scheduler
};
/*! Bundled license information:
scheduler/cjs/scheduler.development.js:
(**
* @license React
* scheduler.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
*/
//# sourceMappingURL=chunk-RMSUKPN2.js.map
File diff suppressed because one or more lines are too long
+21158
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+425
View File
@@ -0,0 +1,425 @@
import "./chunk-4MBMRILA.js";
// ../node_modules/i18next-browser-languagedetector/dist/esm/i18nextBrowserLanguageDetector.js
var {
slice,
forEach
} = [];
function defaults(obj) {
forEach.call(slice.call(arguments, 1), (source) => {
if (source) {
for (const prop in source) {
if (obj[prop] === void 0) obj[prop] = source[prop];
}
}
});
return obj;
}
function hasXSS(input) {
if (typeof input !== "string") return false;
const xssPatterns = [/<\s*script.*?>/i, /<\s*\/\s*script\s*>/i, /<\s*img.*?on\w+\s*=/i, /<\s*\w+\s*on\w+\s*=.*?>/i, /javascript\s*:/i, /vbscript\s*:/i, /expression\s*\(/i, /eval\s*\(/i, /alert\s*\(/i, /document\.cookie/i, /document\.write\s*\(/i, /window\.location/i, /innerHTML/i];
return xssPatterns.some((pattern) => pattern.test(input));
}
var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
var serializeCookie = function(name, val) {
let options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {
path: "/"
};
const opt = options;
const value = encodeURIComponent(val);
let str = `${name}=${value}`;
if (opt.maxAge > 0) {
const maxAge = opt.maxAge - 0;
if (Number.isNaN(maxAge)) throw new Error("maxAge should be a Number");
str += `; Max-Age=${Math.floor(maxAge)}`;
}
if (opt.domain) {
if (!fieldContentRegExp.test(opt.domain)) {
throw new TypeError("option domain is invalid");
}
str += `; Domain=${opt.domain}`;
}
if (opt.path) {
if (!fieldContentRegExp.test(opt.path)) {
throw new TypeError("option path is invalid");
}
str += `; Path=${opt.path}`;
}
if (opt.expires) {
if (typeof opt.expires.toUTCString !== "function") {
throw new TypeError("option expires is invalid");
}
str += `; Expires=${opt.expires.toUTCString()}`;
}
if (opt.httpOnly) str += "; HttpOnly";
if (opt.secure) str += "; Secure";
if (opt.sameSite) {
const sameSite = typeof opt.sameSite === "string" ? opt.sameSite.toLowerCase() : opt.sameSite;
switch (sameSite) {
case true:
str += "; SameSite=Strict";
break;
case "lax":
str += "; SameSite=Lax";
break;
case "strict":
str += "; SameSite=Strict";
break;
case "none":
str += "; SameSite=None";
break;
default:
throw new TypeError("option sameSite is invalid");
}
}
if (opt.partitioned) str += "; Partitioned";
return str;
};
var cookie = {
create(name, value, minutes, domain) {
let cookieOptions = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : {
path: "/",
sameSite: "strict"
};
if (minutes) {
cookieOptions.expires = /* @__PURE__ */ new Date();
cookieOptions.expires.setTime(cookieOptions.expires.getTime() + minutes * 60 * 1e3);
}
if (domain) cookieOptions.domain = domain;
document.cookie = serializeCookie(name, value, cookieOptions);
},
read(name) {
const nameEQ = `${name}=`;
const ca = document.cookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === " ") c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
},
remove(name, domain) {
this.create(name, "", -1, domain);
}
};
var cookie$1 = {
name: "cookie",
// Deconstruct the options object and extract the lookupCookie property
lookup(_ref) {
let {
lookupCookie
} = _ref;
if (lookupCookie && typeof document !== "undefined") {
return cookie.read(lookupCookie) || void 0;
}
return void 0;
},
// Deconstruct the options object and extract the lookupCookie, cookieMinutes, cookieDomain, and cookieOptions properties
cacheUserLanguage(lng, _ref2) {
let {
lookupCookie,
cookieMinutes,
cookieDomain,
cookieOptions
} = _ref2;
if (lookupCookie && typeof document !== "undefined") {
cookie.create(lookupCookie, lng, cookieMinutes, cookieDomain, cookieOptions);
}
}
};
var querystring = {
name: "querystring",
// Deconstruct the options object and extract the lookupQuerystring property
lookup(_ref) {
var _a;
let {
lookupQuerystring
} = _ref;
let found;
if (typeof window !== "undefined") {
let {
search
} = window.location;
if (!window.location.search && ((_a = window.location.hash) == null ? void 0 : _a.indexOf("?")) > -1) {
search = window.location.hash.substring(window.location.hash.indexOf("?"));
}
const query = search.substring(1);
const params = query.split("&");
for (let i = 0; i < params.length; i++) {
const pos = params[i].indexOf("=");
if (pos > 0) {
const key = params[i].substring(0, pos);
if (key === lookupQuerystring) {
found = params[i].substring(pos + 1);
}
}
}
}
return found;
}
};
var hash = {
name: "hash",
// Deconstruct the options object and extract the lookupHash property and the lookupFromHashIndex property
lookup(_ref) {
var _a;
let {
lookupHash,
lookupFromHashIndex
} = _ref;
let found;
if (typeof window !== "undefined") {
const {
hash: hash2
} = window.location;
if (hash2 && hash2.length > 2) {
const query = hash2.substring(1);
if (lookupHash) {
const params = query.split("&");
for (let i = 0; i < params.length; i++) {
const pos = params[i].indexOf("=");
if (pos > 0) {
const key = params[i].substring(0, pos);
if (key === lookupHash) {
found = params[i].substring(pos + 1);
}
}
}
}
if (found) return found;
if (!found && lookupFromHashIndex > -1) {
const language = hash2.match(/\/([a-zA-Z-]*)/g);
if (!Array.isArray(language)) return void 0;
const index = typeof lookupFromHashIndex === "number" ? lookupFromHashIndex : 0;
return (_a = language[index]) == null ? void 0 : _a.replace("/", "");
}
}
}
return found;
}
};
var hasLocalStorageSupport = null;
var localStorageAvailable = () => {
if (hasLocalStorageSupport !== null) return hasLocalStorageSupport;
try {
hasLocalStorageSupport = typeof window !== "undefined" && window.localStorage !== null;
if (!hasLocalStorageSupport) {
return false;
}
const testKey = "i18next.translate.boo";
window.localStorage.setItem(testKey, "foo");
window.localStorage.removeItem(testKey);
} catch (e) {
hasLocalStorageSupport = false;
}
return hasLocalStorageSupport;
};
var localStorage = {
name: "localStorage",
// Deconstruct the options object and extract the lookupLocalStorage property
lookup(_ref) {
let {
lookupLocalStorage
} = _ref;
if (lookupLocalStorage && localStorageAvailable()) {
return window.localStorage.getItem(lookupLocalStorage) || void 0;
}
return void 0;
},
// Deconstruct the options object and extract the lookupLocalStorage property
cacheUserLanguage(lng, _ref2) {
let {
lookupLocalStorage
} = _ref2;
if (lookupLocalStorage && localStorageAvailable()) {
window.localStorage.setItem(lookupLocalStorage, lng);
}
}
};
var hasSessionStorageSupport = null;
var sessionStorageAvailable = () => {
if (hasSessionStorageSupport !== null) return hasSessionStorageSupport;
try {
hasSessionStorageSupport = typeof window !== "undefined" && window.sessionStorage !== null;
if (!hasSessionStorageSupport) {
return false;
}
const testKey = "i18next.translate.boo";
window.sessionStorage.setItem(testKey, "foo");
window.sessionStorage.removeItem(testKey);
} catch (e) {
hasSessionStorageSupport = false;
}
return hasSessionStorageSupport;
};
var sessionStorage = {
name: "sessionStorage",
lookup(_ref) {
let {
lookupSessionStorage
} = _ref;
if (lookupSessionStorage && sessionStorageAvailable()) {
return window.sessionStorage.getItem(lookupSessionStorage) || void 0;
}
return void 0;
},
cacheUserLanguage(lng, _ref2) {
let {
lookupSessionStorage
} = _ref2;
if (lookupSessionStorage && sessionStorageAvailable()) {
window.sessionStorage.setItem(lookupSessionStorage, lng);
}
}
};
var navigator$1 = {
name: "navigator",
lookup(options) {
const found = [];
if (typeof navigator !== "undefined") {
const {
languages,
userLanguage,
language
} = navigator;
if (languages) {
for (let i = 0; i < languages.length; i++) {
found.push(languages[i]);
}
}
if (userLanguage) {
found.push(userLanguage);
}
if (language) {
found.push(language);
}
}
return found.length > 0 ? found : void 0;
}
};
var htmlTag = {
name: "htmlTag",
// Deconstruct the options object and extract the htmlTag property
lookup(_ref) {
let {
htmlTag: htmlTag2
} = _ref;
let found;
const internalHtmlTag = htmlTag2 || (typeof document !== "undefined" ? document.documentElement : null);
if (internalHtmlTag && typeof internalHtmlTag.getAttribute === "function") {
found = internalHtmlTag.getAttribute("lang");
}
return found;
}
};
var path = {
name: "path",
// Deconstruct the options object and extract the lookupFromPathIndex property
lookup(_ref) {
var _a;
let {
lookupFromPathIndex
} = _ref;
if (typeof window === "undefined") return void 0;
const language = window.location.pathname.match(/\/([a-zA-Z-]*)/g);
if (!Array.isArray(language)) return void 0;
const index = typeof lookupFromPathIndex === "number" ? lookupFromPathIndex : 0;
return (_a = language[index]) == null ? void 0 : _a.replace("/", "");
}
};
var subdomain = {
name: "subdomain",
lookup(_ref) {
var _a, _b;
let {
lookupFromSubdomainIndex
} = _ref;
const internalLookupFromSubdomainIndex = typeof lookupFromSubdomainIndex === "number" ? lookupFromSubdomainIndex + 1 : 1;
const language = typeof window !== "undefined" && ((_b = (_a = window.location) == null ? void 0 : _a.hostname) == null ? void 0 : _b.match(/^(\w{2,5})\.(([a-z0-9-]{1,63}\.[a-z]{2,6})|localhost)/i));
if (!language) return void 0;
return language[internalLookupFromSubdomainIndex];
}
};
var canCookies = false;
try {
document.cookie;
canCookies = true;
} catch (e) {
}
var order = ["querystring", "cookie", "localStorage", "sessionStorage", "navigator", "htmlTag"];
if (!canCookies) order.splice(1, 1);
var getDefaults = () => ({
order,
lookupQuerystring: "lng",
lookupCookie: "i18next",
lookupLocalStorage: "i18nextLng",
lookupSessionStorage: "i18nextLng",
// cache user language
caches: ["localStorage"],
excludeCacheFor: ["cimode"],
// cookieMinutes: 10,
// cookieDomain: 'myDomain'
convertDetectedLanguage: (l) => l
});
var Browser = class {
constructor(services) {
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
this.type = "languageDetector";
this.detectors = {};
this.init(services, options);
}
init() {
let services = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {
languageUtils: {}
};
let options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
let i18nOptions = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
this.services = services;
this.options = defaults(options, this.options || {}, getDefaults());
if (typeof this.options.convertDetectedLanguage === "string" && this.options.convertDetectedLanguage.indexOf("15897") > -1) {
this.options.convertDetectedLanguage = (l) => l.replace("-", "_");
}
if (this.options.lookupFromUrlIndex) this.options.lookupFromPathIndex = this.options.lookupFromUrlIndex;
this.i18nOptions = i18nOptions;
this.addDetector(cookie$1);
this.addDetector(querystring);
this.addDetector(localStorage);
this.addDetector(sessionStorage);
this.addDetector(navigator$1);
this.addDetector(htmlTag);
this.addDetector(path);
this.addDetector(subdomain);
this.addDetector(hash);
}
addDetector(detector) {
this.detectors[detector.name] = detector;
return this;
}
detect() {
let detectionOrder = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.options.order;
let detected = [];
detectionOrder.forEach((detectorName) => {
if (this.detectors[detectorName]) {
let lookup = this.detectors[detectorName].lookup(this.options);
if (lookup && typeof lookup === "string") lookup = [lookup];
if (lookup) detected = detected.concat(lookup);
}
});
detected = detected.filter((d) => d !== void 0 && d !== null && !hasXSS(d)).map((d) => this.options.convertDetectedLanguage(d));
if (this.services && this.services.languageUtils && this.services.languageUtils.getBestMatchFromCodes) return detected;
return detected.length > 0 ? detected[0] : null;
}
cacheUserLanguage(lng) {
let caches = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : this.options.caches;
if (!caches) return;
if (this.options.excludeCacheFor && this.options.excludeCacheFor.indexOf(lng) > -1) return;
caches.forEach((cacheName) => {
if (this.detectors[cacheName]) this.detectors[cacheName].cacheUserLanguage(lng, this.options);
});
}
};
Browser.type = "languageDetector";
export {
Browser as default
};
//# sourceMappingURL=i18next-browser-languagedetector.js.map
File diff suppressed because one or more lines are too long
+38
View File
@@ -0,0 +1,38 @@
import {
changeLanguage,
createInstance,
dir,
exists,
getFixedT,
hasLoadedNamespace,
init,
instance,
keysFromSelector,
loadLanguages,
loadNamespaces,
loadResources,
reloadResources,
setDefaultNamespace,
t,
use
} from "./chunk-DRQXKEUS.js";
import "./chunk-4MBMRILA.js";
export {
changeLanguage,
createInstance,
instance as default,
dir,
exists,
getFixedT,
hasLoadedNamespace,
init,
keysFromSelector as keyFromSelector,
loadLanguages,
loadNamespaces,
loadResources,
reloadResources,
setDefaultNamespace,
t,
use
};
//# sourceMappingURL=i18next.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+29928
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}
+8
View File
@@ -0,0 +1,8 @@
import {
require_react_dom
} from "./chunk-TJ6I66L4.js";
import "./chunk-RMSUKPN2.js";
import "./chunk-7URR3GLA.js";
import "./chunk-4MBMRILA.js";
export default require_react_dom();
//# sourceMappingURL=react-dom.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+40
View File
@@ -0,0 +1,40 @@
import {
require_react_dom
} from "./chunk-TJ6I66L4.js";
import "./chunk-RMSUKPN2.js";
import "./chunk-7URR3GLA.js";
import {
__commonJS
} from "./chunk-4MBMRILA.js";
// ../node_modules/react-dom/client.js
var require_client = __commonJS({
"../node_modules/react-dom/client.js"(exports) {
var m = require_react_dom();
if (false) {
exports.createRoot = m.createRoot;
exports.hydrateRoot = m.hydrateRoot;
} else {
i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
exports.createRoot = function(c, o) {
i.usingClientEntryPoint = true;
try {
return m.createRoot(c, o);
} finally {
i.usingClientEntryPoint = false;
}
};
exports.hydrateRoot = function(c, h, o) {
i.usingClientEntryPoint = true;
try {
return m.hydrateRoot(c, h, o);
} finally {
i.usingClientEntryPoint = false;
}
};
}
var i;
}
});
export default require_client();
//# sourceMappingURL=react-dom_client.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../../../node_modules/react-dom/client.js"],
"sourcesContent": ["'use strict';\n\nvar m = require('react-dom');\nif (process.env.NODE_ENV === 'production') {\n exports.createRoot = m.createRoot;\n exports.hydrateRoot = m.hydrateRoot;\n} else {\n var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n exports.createRoot = function(c, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.createRoot(c, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n exports.hydrateRoot = function(c, h, o) {\n i.usingClientEntryPoint = true;\n try {\n return m.hydrateRoot(c, h, o);\n } finally {\n i.usingClientEntryPoint = false;\n }\n };\n}\n"],
"mappings": ";;;;;;;;;;AAAA;AAAA;AAEA,QAAI,IAAI;AACR,QAAI,OAAuC;AACzC,cAAQ,aAAa,EAAE;AACvB,cAAQ,cAAc,EAAE;AAAA,IAC1B,OAAO;AACD,UAAI,EAAE;AACV,cAAQ,aAAa,SAAS,GAAG,GAAG;AAClC,UAAE,wBAAwB;AAC1B,YAAI;AACF,iBAAO,EAAE,WAAW,GAAG,CAAC;AAAA,QAC1B,UAAE;AACA,YAAE,wBAAwB;AAAA,QAC5B;AAAA,MACF;AACA,cAAQ,cAAc,SAAS,GAAG,GAAG,GAAG;AACtC,UAAE,wBAAwB;AAC1B,YAAI;AACF,iBAAO,EAAE,YAAY,GAAG,GAAG,CAAC;AAAA,QAC9B,UAAE;AACA,YAAE,wBAAwB;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAjBM;AAAA;AAAA;",
"names": []
}
+1532
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+27611
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
import {
require_react
} from "./chunk-7URR3GLA.js";
import "./chunk-4MBMRILA.js";
export default require_react();
//# sourceMappingURL=react.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+913
View File
@@ -0,0 +1,913 @@
import {
require_react
} from "./chunk-7URR3GLA.js";
import {
__commonJS
} from "./chunk-4MBMRILA.js";
// ../node_modules/react/cjs/react-jsx-dev-runtime.development.js
var require_react_jsx_dev_runtime_development = __commonJS({
"../node_modules/react/cjs/react-jsx-dev-runtime.development.js"(exports) {
"use strict";
if (true) {
(function() {
"use strict";
var React = require_react();
var REACT_ELEMENT_TYPE = Symbol.for("react.element");
var REACT_PORTAL_TYPE = Symbol.for("react.portal");
var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
var REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode");
var REACT_PROFILER_TYPE = Symbol.for("react.profiler");
var REACT_PROVIDER_TYPE = Symbol.for("react.provider");
var REACT_CONTEXT_TYPE = Symbol.for("react.context");
var REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref");
var REACT_SUSPENSE_TYPE = Symbol.for("react.suspense");
var REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list");
var REACT_MEMO_TYPE = Symbol.for("react.memo");
var REACT_LAZY_TYPE = Symbol.for("react.lazy");
var REACT_OFFSCREEN_TYPE = Symbol.for("react.offscreen");
var MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = "@@iterator";
function getIteratorFn(maybeIterable) {
if (maybeIterable === null || typeof maybeIterable !== "object") {
return null;
}
var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
if (typeof maybeIterator === "function") {
return maybeIterator;
}
return null;
}
var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
function error(format) {
{
{
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
printWarning("error", format, args);
}
}
}
function printWarning(level, format, args) {
{
var ReactDebugCurrentFrame2 = ReactSharedInternals.ReactDebugCurrentFrame;
var stack = ReactDebugCurrentFrame2.getStackAddendum();
if (stack !== "") {
format += "%s";
args = args.concat([stack]);
}
var argsWithFormat = args.map(function(item) {
return String(item);
});
argsWithFormat.unshift("Warning: " + format);
Function.prototype.apply.call(console[level], console, argsWithFormat);
}
}
var enableScopeAPI = false;
var enableCacheElement = false;
var enableTransitionTracing = false;
var enableLegacyHidden = false;
var enableDebugTracing = false;
var REACT_MODULE_REFERENCE;
{
REACT_MODULE_REFERENCE = Symbol.for("react.module.reference");
}
function isValidElementType(type) {
if (typeof type === "string" || typeof type === "function") {
return true;
}
if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableCacheElement || enableTransitionTracing) {
return true;
}
if (typeof type === "object" && type !== null) {
if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object
// types supported by any Flight configuration anywhere since
// we don't know which Flight build this will end up being used
// with.
type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== void 0) {
return true;
}
}
return false;
}
function getWrappedName(outerType, innerType, wrapperName) {
var displayName = outerType.displayName;
if (displayName) {
return displayName;
}
var functionName = innerType.displayName || innerType.name || "";
return functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName;
}
function getContextName(type) {
return type.displayName || "Context";
}
function getComponentNameFromType(type) {
if (type == null) {
return null;
}
{
if (typeof type.tag === "number") {
error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.");
}
}
if (typeof type === "function") {
return type.displayName || type.name || null;
}
if (typeof type === "string") {
return type;
}
switch (type) {
case REACT_FRAGMENT_TYPE:
return "Fragment";
case REACT_PORTAL_TYPE:
return "Portal";
case REACT_PROFILER_TYPE:
return "Profiler";
case REACT_STRICT_MODE_TYPE:
return "StrictMode";
case REACT_SUSPENSE_TYPE:
return "Suspense";
case REACT_SUSPENSE_LIST_TYPE:
return "SuspenseList";
}
if (typeof type === "object") {
switch (type.$$typeof) {
case REACT_CONTEXT_TYPE:
var context = type;
return getContextName(context) + ".Consumer";
case REACT_PROVIDER_TYPE:
var provider = type;
return getContextName(provider._context) + ".Provider";
case REACT_FORWARD_REF_TYPE:
return getWrappedName(type, type.render, "ForwardRef");
case REACT_MEMO_TYPE:
var outerName = type.displayName || null;
if (outerName !== null) {
return outerName;
}
return getComponentNameFromType(type.type) || "Memo";
case REACT_LAZY_TYPE: {
var lazyComponent = type;
var payload = lazyComponent._payload;
var init = lazyComponent._init;
try {
return getComponentNameFromType(init(payload));
} catch (x) {
return null;
}
}
}
}
return null;
}
var assign = Object.assign;
var disabledDepth = 0;
var prevLog;
var prevInfo;
var prevWarn;
var prevError;
var prevGroup;
var prevGroupCollapsed;
var prevGroupEnd;
function disabledLog() {
}
disabledLog.__reactDisabledLog = true;
function disableLogs() {
{
if (disabledDepth === 0) {
prevLog = console.log;
prevInfo = console.info;
prevWarn = console.warn;
prevError = console.error;
prevGroup = console.group;
prevGroupCollapsed = console.groupCollapsed;
prevGroupEnd = console.groupEnd;
var props = {
configurable: true,
enumerable: true,
value: disabledLog,
writable: true
};
Object.defineProperties(console, {
info: props,
log: props,
warn: props,
error: props,
group: props,
groupCollapsed: props,
groupEnd: props
});
}
disabledDepth++;
}
}
function reenableLogs() {
{
disabledDepth--;
if (disabledDepth === 0) {
var props = {
configurable: true,
enumerable: true,
writable: true
};
Object.defineProperties(console, {
log: assign({}, props, {
value: prevLog
}),
info: assign({}, props, {
value: prevInfo
}),
warn: assign({}, props, {
value: prevWarn
}),
error: assign({}, props, {
value: prevError
}),
group: assign({}, props, {
value: prevGroup
}),
groupCollapsed: assign({}, props, {
value: prevGroupCollapsed
}),
groupEnd: assign({}, props, {
value: prevGroupEnd
})
});
}
if (disabledDepth < 0) {
error("disabledDepth fell below zero. This is a bug in React. Please file an issue.");
}
}
}
var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var prefix;
function describeBuiltInComponentFrame(name, source, ownerFn) {
{
if (prefix === void 0) {
try {
throw Error();
} catch (x) {
var match = x.stack.trim().match(/\n( *(at )?)/);
prefix = match && match[1] || "";
}
}
return "\n" + prefix + name;
}
}
var reentry = false;
var componentFrameCache;
{
var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map;
componentFrameCache = new PossiblyWeakMap();
}
function describeNativeComponentFrame(fn, construct) {
if (!fn || reentry) {
return "";
}
{
var frame = componentFrameCache.get(fn);
if (frame !== void 0) {
return frame;
}
}
var control;
reentry = true;
var previousPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = void 0;
var previousDispatcher;
{
previousDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = null;
disableLogs();
}
try {
if (construct) {
var Fake = function() {
throw Error();
};
Object.defineProperty(Fake.prototype, "props", {
set: function() {
throw Error();
}
});
if (typeof Reflect === "object" && Reflect.construct) {
try {
Reflect.construct(Fake, []);
} catch (x) {
control = x;
}
Reflect.construct(fn, [], Fake);
} else {
try {
Fake.call();
} catch (x) {
control = x;
}
fn.call(Fake.prototype);
}
} else {
try {
throw Error();
} catch (x) {
control = x;
}
fn();
}
} catch (sample) {
if (sample && control && typeof sample.stack === "string") {
var sampleLines = sample.stack.split("\n");
var controlLines = control.stack.split("\n");
var s = sampleLines.length - 1;
var c = controlLines.length - 1;
while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) {
c--;
}
for (; s >= 1 && c >= 0; s--, c--) {
if (sampleLines[s] !== controlLines[c]) {
if (s !== 1 || c !== 1) {
do {
s--;
c--;
if (c < 0 || sampleLines[s] !== controlLines[c]) {
var _frame = "\n" + sampleLines[s].replace(" at new ", " at ");
if (fn.displayName && _frame.includes("<anonymous>")) {
_frame = _frame.replace("<anonymous>", fn.displayName);
}
{
if (typeof fn === "function") {
componentFrameCache.set(fn, _frame);
}
}
return _frame;
}
} while (s >= 1 && c >= 0);
}
break;
}
}
}
} finally {
reentry = false;
{
ReactCurrentDispatcher.current = previousDispatcher;
reenableLogs();
}
Error.prepareStackTrace = previousPrepareStackTrace;
}
var name = fn ? fn.displayName || fn.name : "";
var syntheticFrame = name ? describeBuiltInComponentFrame(name) : "";
{
if (typeof fn === "function") {
componentFrameCache.set(fn, syntheticFrame);
}
}
return syntheticFrame;
}
function describeFunctionComponentFrame(fn, source, ownerFn) {
{
return describeNativeComponentFrame(fn, false);
}
}
function shouldConstruct(Component) {
var prototype = Component.prototype;
return !!(prototype && prototype.isReactComponent);
}
function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) {
if (type == null) {
return "";
}
if (typeof type === "function") {
{
return describeNativeComponentFrame(type, shouldConstruct(type));
}
}
if (typeof type === "string") {
return describeBuiltInComponentFrame(type);
}
switch (type) {
case REACT_SUSPENSE_TYPE:
return describeBuiltInComponentFrame("Suspense");
case REACT_SUSPENSE_LIST_TYPE:
return describeBuiltInComponentFrame("SuspenseList");
}
if (typeof type === "object") {
switch (type.$$typeof) {
case REACT_FORWARD_REF_TYPE:
return describeFunctionComponentFrame(type.render);
case REACT_MEMO_TYPE:
return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn);
case REACT_LAZY_TYPE: {
var lazyComponent = type;
var payload = lazyComponent._payload;
var init = lazyComponent._init;
try {
return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn);
} catch (x) {
}
}
}
}
return "";
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
var loggedTypeFailures = {};
var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
function setCurrentlyValidatingElement(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);
ReactDebugCurrentFrame.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame.setExtraStackFrame(null);
}
}
}
function checkPropTypes(typeSpecs, values, location, componentName, element) {
{
var has = Function.call.bind(hasOwnProperty);
for (var typeSpecName in typeSpecs) {
if (has(typeSpecs, typeSpecName)) {
var error$1 = void 0;
try {
if (typeof typeSpecs[typeSpecName] !== "function") {
var err = Error((componentName || "React class") + ": " + location + " type `" + typeSpecName + "` is invalid; it must be a function, usually from the `prop-types` package, but received `" + typeof typeSpecs[typeSpecName] + "`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.");
err.name = "Invariant Violation";
throw err;
}
error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED");
} catch (ex) {
error$1 = ex;
}
if (error$1 && !(error$1 instanceof Error)) {
setCurrentlyValidatingElement(element);
error("%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).", componentName || "React class", location, typeSpecName, typeof error$1);
setCurrentlyValidatingElement(null);
}
if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) {
loggedTypeFailures[error$1.message] = true;
setCurrentlyValidatingElement(element);
error("Failed %s type: %s", location, error$1.message);
setCurrentlyValidatingElement(null);
}
}
}
}
}
var isArrayImpl = Array.isArray;
function isArray(a) {
return isArrayImpl(a);
}
function typeName(value) {
{
var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag;
var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
return type;
}
}
function willCoercionThrow(value) {
{
try {
testStringCoercion(value);
return false;
} catch (e) {
return true;
}
}
}
function testStringCoercion(value) {
return "" + value;
}
function checkKeyStringCoercion(value) {
{
if (willCoercionThrow(value)) {
error("The provided key is an unsupported type %s. This value must be coerced to a string before before using it here.", typeName(value));
return testStringCoercion(value);
}
}
}
var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
var RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true
};
var specialPropKeyWarningShown;
var specialPropRefWarningShown;
var didWarnAboutStringRefs;
{
didWarnAboutStringRefs = {};
}
function hasValidRef(config) {
{
if (hasOwnProperty.call(config, "ref")) {
var getter = Object.getOwnPropertyDescriptor(config, "ref").get;
if (getter && getter.isReactWarning) {
return false;
}
}
}
return config.ref !== void 0;
}
function hasValidKey(config) {
{
if (hasOwnProperty.call(config, "key")) {
var getter = Object.getOwnPropertyDescriptor(config, "key").get;
if (getter && getter.isReactWarning) {
return false;
}
}
}
return config.key !== void 0;
}
function warnIfStringRefCannotBeAutoConverted(config, self) {
{
if (typeof config.ref === "string" && ReactCurrentOwner.current && self && ReactCurrentOwner.current.stateNode !== self) {
var componentName = getComponentNameFromType(ReactCurrentOwner.current.type);
if (!didWarnAboutStringRefs[componentName]) {
error('Component "%s" contains the string ref "%s". Support for string refs will be removed in a future major release. This case cannot be automatically converted to an arrow function. We ask you to manually fix this case by using useRef() or createRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref', getComponentNameFromType(ReactCurrentOwner.current.type), config.ref);
didWarnAboutStringRefs[componentName] = true;
}
}
}
}
function defineKeyPropWarningGetter(props, displayName) {
{
var warnAboutAccessingKey = function() {
if (!specialPropKeyWarningShown) {
specialPropKeyWarningShown = true;
error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", displayName);
}
};
warnAboutAccessingKey.isReactWarning = true;
Object.defineProperty(props, "key", {
get: warnAboutAccessingKey,
configurable: true
});
}
}
function defineRefPropWarningGetter(props, displayName) {
{
var warnAboutAccessingRef = function() {
if (!specialPropRefWarningShown) {
specialPropRefWarningShown = true;
error("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", displayName);
}
};
warnAboutAccessingRef.isReactWarning = true;
Object.defineProperty(props, "ref", {
get: warnAboutAccessingRef,
configurable: true
});
}
}
var ReactElement = function(type, key, ref, self, source, owner, props) {
var element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type,
key,
ref,
props,
// Record the component responsible for creating this element.
_owner: owner
};
{
element._store = {};
Object.defineProperty(element._store, "validated", {
configurable: false,
enumerable: false,
writable: true,
value: false
});
Object.defineProperty(element, "_self", {
configurable: false,
enumerable: false,
writable: false,
value: self
});
Object.defineProperty(element, "_source", {
configurable: false,
enumerable: false,
writable: false,
value: source
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
};
function jsxDEV(type, config, maybeKey, source, self) {
{
var propName;
var props = {};
var key = null;
var ref = null;
if (maybeKey !== void 0) {
{
checkKeyStringCoercion(maybeKey);
}
key = "" + maybeKey;
}
if (hasValidKey(config)) {
{
checkKeyStringCoercion(config.key);
}
key = "" + config.key;
}
if (hasValidRef(config)) {
ref = config.ref;
warnIfStringRefCannotBeAutoConverted(config, self);
}
for (propName in config) {
if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === void 0) {
props[propName] = defaultProps[propName];
}
}
}
if (key || ref) {
var displayName = typeof type === "function" ? type.displayName || type.name || "Unknown" : type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
}
}
var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner;
var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame;
function setCurrentlyValidatingElement$1(element) {
{
if (element) {
var owner = element._owner;
var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);
ReactDebugCurrentFrame$1.setExtraStackFrame(stack);
} else {
ReactDebugCurrentFrame$1.setExtraStackFrame(null);
}
}
}
var propTypesMisspellWarningShown;
{
propTypesMisspellWarningShown = false;
}
function isValidElement(object) {
{
return typeof object === "object" && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
}
function getDeclarationErrorAddendum() {
{
if (ReactCurrentOwner$1.current) {
var name = getComponentNameFromType(ReactCurrentOwner$1.current.type);
if (name) {
return "\n\nCheck the render method of `" + name + "`.";
}
}
return "";
}
}
function getSourceInfoErrorAddendum(source) {
{
if (source !== void 0) {
var fileName = source.fileName.replace(/^.*[\\\/]/, "");
var lineNumber = source.lineNumber;
return "\n\nCheck your code at " + fileName + ":" + lineNumber + ".";
}
return "";
}
}
var ownerHasKeyUseWarning = {};
function getCurrentComponentErrorInfo(parentType) {
{
var info = getDeclarationErrorAddendum();
if (!info) {
var parentName = typeof parentType === "string" ? parentType : parentType.displayName || parentType.name;
if (parentName) {
info = "\n\nCheck the top-level render call using <" + parentName + ">.";
}
}
return info;
}
}
function validateExplicitKey(element, parentType) {
{
if (!element._store || element._store.validated || element.key != null) {
return;
}
element._store.validated = true;
var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
return;
}
ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
var childOwner = "";
if (element && element._owner && element._owner !== ReactCurrentOwner$1.current) {
childOwner = " It was passed a child from " + getComponentNameFromType(element._owner.type) + ".";
}
setCurrentlyValidatingElement$1(element);
error('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.', currentComponentErrorInfo, childOwner);
setCurrentlyValidatingElement$1(null);
}
}
function validateChildKeys(node, parentType) {
{
if (typeof node !== "object") {
return;
}
if (isArray(node)) {
for (var i = 0; i < node.length; i++) {
var child = node[i];
if (isValidElement(child)) {
validateExplicitKey(child, parentType);
}
}
} else if (isValidElement(node)) {
if (node._store) {
node._store.validated = true;
}
} else if (node) {
var iteratorFn = getIteratorFn(node);
if (typeof iteratorFn === "function") {
if (iteratorFn !== node.entries) {
var iterator = iteratorFn.call(node);
var step;
while (!(step = iterator.next()).done) {
if (isValidElement(step.value)) {
validateExplicitKey(step.value, parentType);
}
}
}
}
}
}
}
function validatePropTypes(element) {
{
var type = element.type;
if (type === null || type === void 0 || typeof type === "string") {
return;
}
var propTypes;
if (typeof type === "function") {
propTypes = type.propTypes;
} else if (typeof type === "object" && (type.$$typeof === REACT_FORWARD_REF_TYPE || // Note: Memo only checks outer props here.
// Inner props are checked in the reconciler.
type.$$typeof === REACT_MEMO_TYPE)) {
propTypes = type.propTypes;
} else {
return;
}
if (propTypes) {
var name = getComponentNameFromType(type);
checkPropTypes(propTypes, element.props, "prop", name, element);
} else if (type.PropTypes !== void 0 && !propTypesMisspellWarningShown) {
propTypesMisspellWarningShown = true;
var _name = getComponentNameFromType(type);
error("Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?", _name || "Unknown");
}
if (typeof type.getDefaultProps === "function" && !type.getDefaultProps.isReactClassApproved) {
error("getDefaultProps is only used on classic React.createClass definitions. Use a static property named `defaultProps` instead.");
}
}
}
function validateFragmentProps(fragment) {
{
var keys = Object.keys(fragment.props);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key !== "children" && key !== "key") {
setCurrentlyValidatingElement$1(fragment);
error("Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.", key);
setCurrentlyValidatingElement$1(null);
break;
}
}
if (fragment.ref !== null) {
setCurrentlyValidatingElement$1(fragment);
error("Invalid attribute `ref` supplied to `React.Fragment`.");
setCurrentlyValidatingElement$1(null);
}
}
}
var didWarnAboutKeySpread = {};
function jsxWithValidation(type, props, key, isStaticChildren, source, self) {
{
var validType = isValidElementType(type);
if (!validType) {
var info = "";
if (type === void 0 || typeof type === "object" && type !== null && Object.keys(type).length === 0) {
info += " You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.";
}
var sourceInfo = getSourceInfoErrorAddendum(source);
if (sourceInfo) {
info += sourceInfo;
} else {
info += getDeclarationErrorAddendum();
}
var typeString;
if (type === null) {
typeString = "null";
} else if (isArray(type)) {
typeString = "array";
} else if (type !== void 0 && type.$$typeof === REACT_ELEMENT_TYPE) {
typeString = "<" + (getComponentNameFromType(type.type) || "Unknown") + " />";
info = " Did you accidentally export a JSX literal instead of a component?";
} else {
typeString = typeof type;
}
error("React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", typeString, info);
}
var element = jsxDEV(type, props, key, source, self);
if (element == null) {
return element;
}
if (validType) {
var children = props.children;
if (children !== void 0) {
if (isStaticChildren) {
if (isArray(children)) {
for (var i = 0; i < children.length; i++) {
validateChildKeys(children[i], type);
}
if (Object.freeze) {
Object.freeze(children);
}
} else {
error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");
}
} else {
validateChildKeys(children, type);
}
}
}
{
if (hasOwnProperty.call(props, "key")) {
var componentName = getComponentNameFromType(type);
var keys = Object.keys(props).filter(function(k) {
return k !== "key";
});
var beforeExample = keys.length > 0 ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" : "{key: someKey}";
if (!didWarnAboutKeySpread[componentName + beforeExample]) {
var afterExample = keys.length > 0 ? "{" + keys.join(": ..., ") + ": ...}" : "{}";
error('A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />', beforeExample, componentName, afterExample, componentName);
didWarnAboutKeySpread[componentName + beforeExample] = true;
}
}
}
if (type === REACT_FRAGMENT_TYPE) {
validateFragmentProps(element);
} else {
validatePropTypes(element);
}
return element;
}
}
var jsxDEV$1 = jsxWithValidation;
exports.Fragment = REACT_FRAGMENT_TYPE;
exports.jsxDEV = jsxDEV$1;
})();
}
}
});
// ../node_modules/react/jsx-dev-runtime.js
var require_jsx_dev_runtime = __commonJS({
"../node_modules/react/jsx-dev-runtime.js"(exports, module) {
if (false) {
module.exports = null;
} else {
module.exports = require_react_jsx_dev_runtime_development();
}
}
});
export default require_jsx_dev_runtime();
/*! Bundled license information:
react/cjs/react-jsx-dev-runtime.development.js:
(**
* @license React
* react-jsx-dev-runtime.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
*/
//# sourceMappingURL=react_jsx-dev-runtime.js.map
File diff suppressed because one or more lines are too long
+7
View File
@@ -0,0 +1,7 @@
import {
require_jsx_runtime
} from "./chunk-JYSI5OBP.js";
import "./chunk-7URR3GLA.js";
import "./chunk-4MBMRILA.js";
export default require_jsx_runtime();
//# sourceMappingURL=react_jsx-runtime.js.map
+7
View File
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
+186
View File
@@ -0,0 +1,186 @@
import {
require_shim
} from "./chunk-CITXGXPZ.js";
import {
require_react
} from "./chunk-7URR3GLA.js";
import {
__commonJS,
__toESM
} from "./chunk-4MBMRILA.js";
// ../node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js
var require_with_selector_development = __commonJS({
"../node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js"(exports) {
"use strict";
(function() {
function is(x, y) {
return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
}
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
var React = require_react(), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is, useSyncExternalStore = shim.useSyncExternalStore, useRef = React.useRef, useEffect = React.useEffect, useMemo = React.useMemo, useDebugValue2 = React.useDebugValue;
exports.useSyncExternalStoreWithSelector = function(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
var instRef = useRef(null);
if (null === instRef.current) {
var inst = { hasValue: false, value: null };
instRef.current = inst;
} else inst = instRef.current;
instRef = useMemo(
function() {
function memoizedSelector(nextSnapshot) {
if (!hasMemo) {
hasMemo = true;
memoizedSnapshot = nextSnapshot;
nextSnapshot = selector(nextSnapshot);
if (void 0 !== isEqual && inst.hasValue) {
var currentSelection = inst.value;
if (isEqual(currentSelection, nextSnapshot))
return memoizedSelection = currentSelection;
}
return memoizedSelection = nextSnapshot;
}
currentSelection = memoizedSelection;
if (objectIs(memoizedSnapshot, nextSnapshot))
return currentSelection;
var nextSelection = selector(nextSnapshot);
if (void 0 !== isEqual && isEqual(currentSelection, nextSelection))
return memoizedSnapshot = nextSnapshot, currentSelection;
memoizedSnapshot = nextSnapshot;
return memoizedSelection = nextSelection;
}
var hasMemo = false, memoizedSnapshot, memoizedSelection, maybeGetServerSnapshot = void 0 === getServerSnapshot ? null : getServerSnapshot;
return [
function() {
return memoizedSelector(getSnapshot());
},
null === maybeGetServerSnapshot ? void 0 : function() {
return memoizedSelector(maybeGetServerSnapshot());
}
];
},
[getSnapshot, getServerSnapshot, selector, isEqual]
);
var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);
useEffect(
function() {
inst.hasValue = true;
inst.value = value;
},
[value]
);
useDebugValue2(value);
return value;
};
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
})();
}
});
// ../node_modules/use-sync-external-store/shim/with-selector.js
var require_with_selector = __commonJS({
"../node_modules/use-sync-external-store/shim/with-selector.js"(exports, module) {
"use strict";
if (false) {
module.exports = null;
} else {
module.exports = require_with_selector_development();
}
}
});
// ../node_modules/zustand/esm/vanilla.mjs
var createStoreImpl = (createState) => {
let state;
const listeners = /* @__PURE__ */ new Set();
const setState = (partial, replace) => {
const nextState = typeof partial === "function" ? partial(state) : partial;
if (!Object.is(nextState, state)) {
const previousState = state;
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
listeners.forEach((listener) => listener(state, previousState));
}
};
const getState = () => state;
const getInitialState = () => initialState;
const subscribe = (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const destroy = () => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
console.warn(
"[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."
);
}
listeners.clear();
};
const api = { setState, getState, getInitialState, subscribe, destroy };
const initialState = state = createState(setState, getState, api);
return api;
};
var createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
// ../node_modules/zustand/esm/index.mjs
var import_react = __toESM(require_react(), 1);
var import_with_selector = __toESM(require_with_selector(), 1);
var { useDebugValue } = import_react.default;
var { useSyncExternalStoreWithSelector } = import_with_selector.default;
var didWarnAboutEqualityFn = false;
var identity = (arg) => arg;
function useStore(api, selector = identity, equalityFn) {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && equalityFn && !didWarnAboutEqualityFn) {
console.warn(
"[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"
);
didWarnAboutEqualityFn = true;
}
const slice = useSyncExternalStoreWithSelector(
api.subscribe,
api.getState,
api.getServerState || api.getInitialState,
selector,
equalityFn
);
useDebugValue(slice);
return slice;
}
var createImpl = (createState) => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && typeof createState !== "function") {
console.warn(
"[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`."
);
}
const api = typeof createState === "function" ? createStore(createState) : createState;
const useBoundStore = (selector, equalityFn) => useStore(api, selector, equalityFn);
Object.assign(useBoundStore, api);
return useBoundStore;
};
var create = (createState) => createState ? createImpl(createState) : createImpl;
var react = (createState) => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
console.warn(
"[DEPRECATED] Default export is deprecated. Instead use `import { create } from 'zustand'`."
);
}
return create(createState);
};
export {
create,
createStore,
react as default,
useStore
};
/*! Bundled license information:
use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js:
(**
* @license React
* use-sync-external-store-shim/with-selector.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
*/
//# sourceMappingURL=zustand.js.map
File diff suppressed because one or more lines are too long
+41
View File
@@ -0,0 +1,41 @@
{
"name": "creabook-client",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@tanstack/react-query": "^5.17.0",
"axios": "^1.6.5",
"clsx": "^2.1.0",
"i18next": "^26.0.3",
"i18next-browser-languagedetector": "^8.2.1",
"konva": "^9.3.4",
"lucide-react": "^0.303.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^17.0.2",
"react-konva": "^18.2.10",
"react-router-dom": "^6.21.1",
"tailwind-merge": "^2.2.0",
"zustand": "^4.4.7"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.33",
"tailwindcss": "^3.4.1",
"typescript": "^5.3.3",
"vite": "^5.0.10"
}
}
+6
View File
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
+99
View File
@@ -0,0 +1,99 @@
import { Routes, Route, Navigate } from 'react-router-dom';
import { BookOpen, Image, Settings } from 'lucide-react';
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useAuthStore } from './stores/authStore';
import AuthModal from './components/auth/AuthModal';
import CoverDesigner from './components/cover-designer/CoverDesigner';
import BookGenerator from './components/book-generator/BookGenerator';
import SettingsPage from './components/SettingsPage';
function App() {
const { t } = useTranslation();
const { user, isAuthenticated, logout, checkAuth } = useAuthStore();
const [isAuthModalOpen, setIsAuthModalOpen] = useState(false);
useEffect(() => {
checkAuth();
}, []);
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<header className="bg-white border-b border-gray-200 sticky top-0 z-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-gradient-to-br from-primary-500 to-accent-500 rounded-lg flex items-center justify-center">
<BookOpen className="w-5 h-5 text-white" />
</div>
<h1 className="text-xl font-bold text-gray-900">CreaBook</h1>
</div>
{/* Navigation */}
<nav className="flex items-center gap-1">
<a
href="/covers"
className="flex items-center gap-2 px-4 py-2 rounded-lg text-gray-600 hover:bg-gray-100 transition-colors"
>
<Image className="w-5 h-5" />
<span className="hidden sm:inline">{t('nav.coverDesigner')}</span>
</a>
<a
href="/books"
className="flex items-center gap-2 px-4 py-2 rounded-lg text-gray-600 hover:bg-gray-100 transition-colors"
>
<BookOpen className="w-5 h-5" />
<span className="hidden sm:inline">{t('nav.bookGenerator')}</span>
</a>
{user?.role === 'ADMIN' && (
<a
href="/settings"
className="flex items-center gap-2 px-4 py-2 rounded-lg text-gray-600 hover:bg-gray-100 transition-colors"
>
<Settings className="w-5 h-5" />
<span className="hidden sm:inline">{t('nav.settings')}</span>
</a>
)}
<div className="w-px h-6 bg-gray-200 mx-2"></div>
{isAuthenticated ? (
<div className="flex items-center gap-4 ml-2">
<span className="text-sm font-medium text-gray-700">{user?.name || user?.email}</span>
<button
onClick={logout}
className="text-sm text-red-600 hover:text-red-700 font-medium"
>
{t('nav.logout')}
</button>
</div>
) : (
<button
onClick={() => setIsAuthModalOpen(true)}
className="btn-primary ml-2 py-2"
>
{t('nav.loginRegister')}
</button>
)}
</nav>
</div>
</div>
</header>
{/* Main Content */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Routes>
<Route path="/" element={<Navigate to="/covers" replace />} />
<Route path="/covers" element={<CoverDesigner />} />
<Route path="/books" element={<BookGenerator />} />
<Route path="/settings" element={<SettingsPage />} />
</Routes>
</main>
<AuthModal isOpen={isAuthModalOpen} onClose={() => setIsAuthModalOpen(false)} />
</div>
);
}
export default App;
+111
View File
@@ -0,0 +1,111 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Cpu, Save, Globe } from 'lucide-react';
export default function SettingsPage() {
const [selectedModel] = useState('gpt-4o-mini');
const [imageModel] = useState('stable-diffusion-v1-6');
const { t, i18n } = useTranslation();
const handleLanguageChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
i18n.changeLanguage(e.target.value);
};
const handleSave = () => {
// Settings are now fixed to cloud models
alert('Cloud AI models are configured automatically!');
};
return (
<div className="max-w-2xl mx-auto space-y-6">
<div>
<h2 className="text-2xl font-bold text-gray-900">{t('settings.title')}</h2>
<p className="text-gray-500 mt-1">
Cloud AI configuration and application preferences
</p>
</div>
{/* Language Configuration */}
<div className="card">
<h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<Globe className="w-5 h-5" />
{t('settings.language')}
</h3>
<div className="space-y-4">
<div>
<label className="label">{t('settings.languageSelect')}</label>
<select
value={i18n.language}
onChange={handleLanguageChange}
className="input bg-white"
>
<option value="en">{t('settings.english')}</option>
<option value="es">{t('settings.spanish')}</option>
</select>
</div>
</div>
</div>
{/* Cloud AI Configuration */}
<div className="card">
<h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<Cpu className="w-5 h-5" />
Cloud AI Settings
</h3>
<div className="space-y-4">
<div>
<label className="label">Text Generation Model</label>
<select
value={selectedModel}
disabled
className="input bg-gray-100"
>
<option value="gpt-4o-mini">OpenAI GPT-4o Mini (via OpenRouter)</option>
</select>
<p className="text-sm text-gray-500 mt-1">
Used for book outlines, chapters, and text generation (free tier)
</p>
</div>
<div>
<label className="label">Image Generation Model</label>
<select
value={imageModel}
disabled
className="input bg-gray-100"
>
<option value="stable-diffusion-v1-6">Stability AI Stable Diffusion v1.6</option>
</select>
<p className="text-sm text-gray-500 mt-1">
Used for AI book cover generation (free credits available)
</p>
</div>
</div>
</div>
{/* API Setup Help */}
<div className="card bg-blue-50 border-blue-200">
<h3 className="font-medium text-blue-900 mb-2">API Key Setup</h3>
<p className="text-sm text-blue-700 mb-3">
Configure your API key in the server/.env file:
</p>
<code className="block bg-white rounded p-3 text-sm font-mono text-blue-800">
OPENROUTER_API_KEY=your_openrouter_api_key_here
</code>
<p className="text-sm text-blue-700 mt-2">
Get a free API key from: <a href="https://openrouter.ai/keys" className="underline" target="_blank" rel="noopener noreferrer">OpenRouter</a>
</p>
</div>
{/* Save Button */}
<div className="flex justify-end">
<button onClick={handleSave} className="btn-primary flex items-center gap-2">
<Save className="w-4 h-4" />
Save Settings
</button>
</div>
</div>
);
}
+128
View File
@@ -0,0 +1,128 @@
import { useState } from 'react';
import axios from 'axios';
import { useTranslation } from 'react-i18next';
import { useAuthStore } from '../../stores/authStore';
import { X } from 'lucide-react';
interface AuthModalProps {
isOpen: boolean;
onClose: () => void;
}
export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const [isLogin, setIsLogin] = useState(true);
const [email, setEmail] = useState('');
const [name, setName] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const { t } = useTranslation();
const { setAuth } = useAuthStore();
if (!isOpen) return null;
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setLoading(true);
try {
const endpoint = isLogin ? '/api/auth/login' : '/api/auth/register';
const payload = isLogin ? { email, password } : { email, password, name };
const response = await axios.post(endpoint, payload);
setAuth(response.data.user, response.data.token);
onClose();
} catch (err: any) {
setError(err.response?.data?.error || 'Authentication failed');
} finally {
setLoading(false);
}
};
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden relative">
<button
onClick={onClose}
className="absolute top-4 right-4 text-gray-400 flex items-center justify-center hover:bg-gray-100 rounded-lg p-2"
>
<X size={20} />
</button>
<div className="p-6">
<h2 className="text-2xl font-bold text-gray-900 mb-6 text-center">
{isLogin ? t('auth.welcomeBack') : t('auth.createAccount')}
</h2>
{error && (
<div className="bg-red-50 text-red-600 p-3 rounded-lg mb-4 text-sm">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
{!isLogin && (
<div>
<label className="label">{t('auth.name')}</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="input"
placeholder={t('auth.name')}
/>
</div>
)}
<div>
<label className="label">{t('auth.email')}</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="input"
placeholder="you@example.com"
/>
</div>
<div>
<label className="label">{t('auth.password')}</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="input"
placeholder="••••••••"
/>
</div>
<button
type="submit"
disabled={loading}
className="btn-primary w-full py-2.5 mt-2"
>
{loading ? t('auth.pleaseWait') : (isLogin ? t('auth.login') : t('auth.signUp'))}
</button>
</form>
<div className="mt-6 text-center text-sm text-gray-500">
{isLogin ? t('auth.dontHaveAccount') : t('auth.alreadyHaveAccount')}
<button
type="button"
onClick={() => {
setIsLogin(!isLogin);
setError('');
}}
className="text-primary-600 font-semibold hover:underline"
>
{isLogin ? t('auth.signUp') : t('auth.login')}
</button>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,219 @@
import { useState } from 'react';
import { Wand2, ChevronLeft, ChevronRight, Sparkles } from 'lucide-react';
import { useBookStore } from '../../stores/bookStore';
import { booksApi } from '../../services/api';
export default function BookEditor() {
const { activeBook, updateChapterContent, setCurrentChapter } = useBookStore();
const [isGenerating, setIsGenerating] = useState(false);
const [showAIHelp, setShowAIHelp] = useState(false);
if (!activeBook || !activeBook.outline) {
return (
<div className="card text-center py-12">
<p className="text-gray-500">
Generate an outline first to start writing your book.
</p>
</div>
);
}
const currentChapter = activeBook.outline.chapters.find(
(c) => c.number === activeBook.currentChapter
);
const handlePreviousChapter = () => {
if (activeBook.currentChapter > 1) {
setCurrentChapter(activeBook.currentChapter - 1);
}
};
const handleNextChapter = () => {
const maxChapter = activeBook.outline!.chapters.length;
if (activeBook.currentChapter < maxChapter) {
setCurrentChapter(activeBook.currentChapter + 1);
}
};
const handleGenerateChapter = async () => {
if (!currentChapter || !activeBook) return;
setIsGenerating(true);
try {
const previousChapter = activeBook.outline?.chapters.find(
(c) => c.number === activeBook.currentChapter - 1
);
const response = await booksApi.generateChapter(
activeBook.genre,
currentChapter.title,
currentChapter.summary,
previousChapter?.content
);
updateChapterContent(activeBook.currentChapter, response.data.content);
} catch (error) {
console.error('Failed to generate chapter:', error);
} finally {
setIsGenerating(false);
}
};
const handleExpandText = async () => {
// TODO: Implement expand functionality
alert('Expand feature coming soon!');
};
return (
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* Chapter Navigation */}
<div className="space-y-4">
<div className="card">
<h3 className="font-semibold text-gray-900 mb-4">Chapters</h3>
<div className="space-y-2">
{activeBook.outline.chapters.map((chapter) => (
<button
key={chapter.number}
onClick={() => setCurrentChapter(chapter.number)}
className={`w-full text-left p-3 rounded-lg transition-colors ${
chapter.number === activeBook.currentChapter
? 'bg-primary-100 text-primary-700'
: 'hover:bg-gray-50'
}`}
>
<div className="flex items-center gap-2">
<span className="flex-shrink-0 w-6 h-6 bg-white rounded-full flex items-center justify-center text-xs font-medium border">
{chapter.number}
</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">{chapter.title}</p>
{chapter.content && (
<span className="text-xs text-green-600">✓ Written</span>
)}
</div>
</div>
</button>
))}
</div>
</div>
{/* Chapter Info */}
<div className="card">
<h4 className="font-medium text-gray-900 mb-2">Chapter Summary</h4>
<p className="text-sm text-gray-600">{currentChapter?.summary}</p>
</div>
</div>
{/* Writing Area */}
<div className="lg:col-span-3">
<div className="card">
{/* Chapter Header */}
<div className="flex items-center justify-between mb-6 pb-4 border-b border-gray-200">
<div className="flex items-center gap-4">
<button
onClick={handlePreviousChapter}
disabled={activeBook.currentChapter <= 1}
className="p-2 rounded-lg hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
>
<ChevronLeft className="w-5 h-5" />
</button>
<div>
<h2 className="text-xl font-bold text-gray-900">
{currentChapter?.title}
</h2>
<p className="text-sm text-gray-500">
Chapter {activeBook.currentChapter} of {activeBook.outline.chapters.length}
</p>
</div>
<button
onClick={handleNextChapter}
disabled={activeBook.currentChapter >= activeBook.outline.chapters.length}
className="p-2 rounded-lg hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
>
<ChevronRight className="w-5 h-5" />
</button>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => setShowAIHelp(!showAIHelp)}
className="btn-secondary flex items-center gap-2"
>
<Sparkles className="w-4 h-4" />
AI Assist
</button>
<button
onClick={handleGenerateChapter}
disabled={isGenerating || !currentChapter}
className="btn-primary flex items-center gap-2"
>
<Wand2 className="w-4 h-4" />
{isGenerating ? 'Generating...' : 'Generate Chapter'}
</button>
</div>
</div>
{/* AI Help Panel */}
{showAIHelp && (
<div className="mb-6 bg-gradient-to-r from-accent-50 to-primary-50 rounded-lg p-4 border border-accent-200">
<h4 className="font-medium text-gray-900 mb-3">AI Writing Assistant</h4>
<div className="flex flex-wrap gap-2">
<button
onClick={handleExpandText}
className="text-sm px-3 py-1.5 bg-white rounded-lg border border-gray-200 hover:border-accent-300 transition-colors"
>
✨ Expand this section
</button>
<button className="text-sm px-3 py-1.5 bg-white rounded-lg border border-gray-200 hover:border-accent-300 transition-colors">
📝 Improve prose
</button>
<button className="text-sm px-3 py-1.5 bg-white rounded-lg border border-gray-200 hover:border-accent-300 transition-colors">
💡 Add description
</button>
<button className="text-sm px-3 py-1.5 bg-white rounded-lg border border-gray-200 hover:border-accent-300 transition-colors">
🔄 Rewrite paragraph
</button>
</div>
</div>
)}
{/* Editor */}
<div className="min-h-[500px]">
{currentChapter?.content ? (
<textarea
value={currentChapter.content}
onChange={(e) =>
updateChapterContent(activeBook.currentChapter, e.target.value)
}
className="w-full h-[600px] p-6 font-serif text-lg leading-relaxed border-0 focus:ring-0 resize-y outline-none"
placeholder="Start writing or use AI to generate this chapter..."
/>
) : (
<div className="h-[500px] flex items-center justify-center text-gray-400">
<div className="text-center">
<Wand2 className="w-12 h-12 mx-auto mb-3 opacity-50" />
<p>Click "Generate Chapter" to create content with AI</p>
<p className="text-sm mt-1">Or start writing manually</p>
</div>
</div>
)}
</div>
{/* Word Count */}
<div className="mt-4 pt-4 border-t border-gray-200 flex items-center justify-between text-sm text-gray-500">
<span>
{currentChapter?.content
? currentChapter.content.split(/\s+/).length
: 0}{' '}
words
</span>
<span>
Last updated:{' '}
{new Date(activeBook.updatedAt).toLocaleDateString()}
</span>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,223 @@
import { useState } from 'react';
import { BookOpen, Wand2, Edit3, Users, FileText } from 'lucide-react';
import GenreSelector from './GenreSelector';
import BookOutlineGenerator from './BookOutlineGenerator';
import BookEditor from './BookEditor';
import { useBookStore, Book, BookOutline } from '../../stores/bookStore';
import { booksApi } from '../../services/api';
import { useQuery } from '@tanstack/react-query';
export default function BookGenerator() {
const [activeTab, setActiveTab] = useState<'genre' | 'outline' | 'editor' | 'characters'>('genre');
const { activeBook, setActiveBook, setOutline } = useBookStore();
const { data: genresData } = useQuery({
queryKey: ['genres'],
queryFn: async () => {
const response = await booksApi.getGenres();
return response.data.genres;
},
});
const handleGenreSelect = (genreId: string, idea: string, title: string) => {
const newBook: Book = {
id: `book-${Date.now()}`,
title,
genre: genreId,
idea,
outline: null,
characters: [],
currentChapter: 1,
createdAt: new Date(),
updatedAt: new Date(),
};
setActiveBook(newBook);
setActiveTab('outline');
};
const handleOutlineGenerated = (outline: BookOutline) => {
if (activeBook && outline) {
setOutline(outline);
setActiveTab('editor');
}
};
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Book Generator</h2>
<p className="text-gray-500 mt-1">
Generate book ideas and write with AI assistance
</p>
</div>
{/* Tab Navigation */}
<div className="flex bg-white rounded-lg p-1 border border-gray-200">
<button
onClick={() => setActiveTab('genre')}
className={`flex items-center gap-2 px-4 py-2 rounded-md transition-colors ${
activeTab === 'genre' || !activeBook
? 'bg-primary-100 text-primary-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
disabled={!activeBook && activeTab !== 'genre'}
>
<BookOpen className="w-4 h-4" />
<span className="hidden sm:inline">Genre</span>
</button>
<button
onClick={() => setActiveTab('outline')}
disabled={!activeBook}
className={`flex items-center gap-2 px-4 py-2 rounded-md transition-colors ${
activeTab === 'outline'
? 'bg-primary-100 text-primary-700'
: 'text-gray-600 hover:bg-gray-100 disabled:opacity-50'
}`}
>
<FileText className="w-4 h-4" />
<span className="hidden sm:inline">Outline</span>
</button>
<button
onClick={() => setActiveTab('editor')}
disabled={!activeBook}
className={`flex items-center gap-2 px-4 py-2 rounded-md transition-colors ${
activeTab === 'editor'
? 'bg-primary-100 text-primary-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
<Edit3 className="w-4 h-4" />
<span className="hidden sm:inline">Write</span>
</button>
<button
onClick={() => setActiveTab('characters')}
disabled={!activeBook}
className={`flex items-center gap-2 px-4 py-2 rounded-md transition-colors ${
activeTab === 'characters'
? 'bg-primary-100 text-primary-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
<Users className="w-4 h-4" />
<span className="hidden sm:inline">Characters</span>
</button>
</div>
</div>
{activeTab === 'genre' && (
<GenreSelector
genres={genresData || []}
onSelect={handleGenreSelect}
/>
)}
{activeTab === 'outline' && activeBook && (
<BookOutlineGenerator
book={activeBook}
onComplete={handleOutlineGenerated}
/>
)}
{activeTab === 'editor' && activeBook && (
<BookEditor />
)}
{activeTab === 'characters' && activeBook && (
<CharacterGenerator />
)}
</div>
);
}
function CharacterGenerator() {
const { activeBook, addCharacter } = useBookStore();
const [isGenerating, setIsGenerating] = useState(false);
const handleGenerateCharacters = async () => {
if (!activeBook) return;
setIsGenerating(true);
try {
const response = await booksApi.generateCharacters(activeBook.genre, activeBook.idea);
const characters = response.data.characters;
if (Array.isArray(characters)) {
characters.forEach((char: any) => {
addCharacter({
name: char.name || 'Unknown',
role: char.role || 'Supporting',
traits: char.traits || [],
motivation: char.motivation || '',
backstory: char.backstory || '',
});
});
}
} catch (error) {
console.error('Failed to generate characters:', error);
} finally {
setIsGenerating(false);
}
};
if (!activeBook) return null;
return (
<div className="card">
<div className="flex items-center justify-between mb-6">
<h3 className="text-lg font-semibold text-gray-900">
Character Development
</h3>
<button
onClick={handleGenerateCharacters}
disabled={isGenerating}
className="btn-primary flex items-center gap-2"
>
<Wand2 className="w-4 h-4" />
{isGenerating ? 'Generating...' : 'Generate Characters'}
</button>
</div>
{activeBook.characters.length === 0 ? (
<div className="text-center py-8">
<Users className="w-12 h-12 text-gray-300 mx-auto mb-3" />
<p className="text-gray-500">
No characters yet. Click "Generate Characters" to create AI-suggested characters.
</p>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{activeBook.characters.map((character, index) => (
<div
key={index}
className="border border-gray-200 rounded-lg p-4 hover:border-primary-300 transition-colors"
>
<div className="flex items-start justify-between mb-2">
<h4 className="font-semibold text-gray-900">{character.name}</h4>
<span className={`text-xs px-2 py-1 rounded-full ${
character.role === 'protagonist'
? 'bg-green-100 text-green-700'
: character.role === 'antagonist'
? 'bg-red-100 text-red-700'
: 'bg-gray-100 text-gray-600'
}`}>
{character.role}
</span>
</div>
<div className="space-y-2 text-sm">
<div>
<span className="text-gray-500">Traits:</span>
<p className="text-gray-700">{character.traits?.join(', ') || 'N/A'}</p>
</div>
<div>
<span className="text-gray-500">Motivation:</span>
<p className="text-gray-700">{character.motivation || 'N/A'}</p>
</div>
</div>
</div>
))}
</div>
)}
</div>
);
}
@@ -0,0 +1,136 @@
import { useState } from 'react';
import { Wand2, CheckCircle, Loader2 } from 'lucide-react';
import { Book, useBookStore } from '../../stores/bookStore';
import { booksApi } from '../../services/api';
interface BookOutlineGeneratorProps {
book: Book;
onComplete: (outline: any) => void;
}
export default function BookOutlineGenerator({ book, onComplete }: BookOutlineGeneratorProps) {
const { activeBook } = useBookStore();
const [isGenerating, setIsGenerating] = useState(false);
const [error, setError] = useState<string>('');
const outline = activeBook?.outline;
const handleGenerate = async () => {
setIsGenerating(true);
setError('');
try {
const response = await booksApi.generateOutline(book.genre, book.idea, book.title);
const generatedOutline = response.data.outline;
onComplete(generatedOutline);
} catch (err: any) {
setError(err.response?.data?.error || 'Failed to generate outline');
} finally {
setIsGenerating(false);
}
};
return (
<div className="space-y-6">
{/* Book Info Summary */}
<div className="card bg-gradient-to-r from-primary-50 to-accent-50">
<div className="flex items-start justify-between">
<div>
<h3 className="font-semibold text-gray-900">{book.title || 'Untitled Book'}</h3>
<p className="text-sm text-gray-600 mt-1 capitalize">Genre: {book.genre}</p>
<p className="text-sm text-gray-500 mt-2 line-clamp-2">{book.idea}</p>
</div>
{!outline && (
<button
onClick={handleGenerate}
disabled={isGenerating}
className="btn-primary flex items-center gap-2"
>
{isGenerating ? (
<>
<Loader2 className="w-4 h-4 animate-spin" />
Generating...
</>
) : (
<>
<Wand2 className="w-4 h-4" />
Generate Outline
</>
)}
</button>
)}
</div>
</div>
{/* Error Message */}
{error && (
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
<p className="text-red-700">{error}</p>
</div>
)}
{/* Outline Display */}
{outline && (
<div className="card">
<div className="flex items-center gap-2 mb-6">
<CheckCircle className="w-5 h-5 text-green-500" />
<h3 className="text-lg font-semibold text-gray-900">
Generated Outline: {outline.title || book.title}
</h3>
</div>
{outline.logline && (
<div className="mb-6 pb-6 border-b border-gray-200">
<h4 className="text-sm font-medium text-gray-500 mb-2">Logline</h4>
<p className="text-gray-900 italic">{outline.logline}</p>
</div>
)}
<div>
<h4 className="text-sm font-medium text-gray-500 mb-4">Chapter Outline</h4>
<div className="space-y-3">
{outline.chapters?.map((chapter: any, index: number) => (
<div
key={index}
className="border border-gray-200 rounded-lg p-4 hover:border-primary-300 transition-colors"
>
<div className="flex items-start gap-3">
<span className="flex-shrink-0 w-8 h-8 bg-primary-100 text-primary-700 rounded-full flex items-center justify-center text-sm font-medium">
{chapter.number || index + 1}
</span>
<div className="flex-1">
<h5 className="font-medium text-gray-900">
{chapter.title || `Chapter ${chapter.number || index + 1}`}
</h5>
<p className="text-sm text-gray-600 mt-1">
{chapter.summary || 'No summary available'}
</p>
</div>
</div>
</div>
))}
</div>
</div>
<div className="mt-6 flex items-center justify-end gap-3">
<p className="text-sm text-gray-500">
Ready to start writing! Navigate to the Write tab to begin.
</p>
</div>
</div>
)}
{/* Initial State */}
{!outline && !isGenerating && (
<div className="card text-center py-12">
<Wand2 className="w-12 h-12 text-gray-300 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900">Ready to Generate</h3>
<p className="text-gray-500 mt-2 max-w-md mx-auto">
Click "Generate Outline" to create a detailed chapter outline based on your genre and book idea.
The AI will create a structure following genre-specific patterns.
</p>
</div>
)}
</div>
);
}
@@ -0,0 +1,111 @@
import { useState } from 'react';
import { BookOpen, Sparkles } from 'lucide-react';
interface Genre {
id: string;
name: string;
description: string;
icon: string;
}
interface GenreSelectorProps {
genres: Genre[];
onSelect: (genreId: string, idea: string, title: string) => void;
}
export default function GenreSelector({ genres, onSelect }: GenreSelectorProps) {
const [selectedGenre, setSelectedGenre] = useState<string>('');
const [title, setTitle] = useState('');
const [idea, setIdea] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (selectedGenre && idea.trim()) {
onSelect(selectedGenre, idea.trim(), title.trim());
}
};
return (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Genre Selection */}
<div className="lg:col-span-2">
<div className="card">
<h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<BookOpen className="w-5 h-5" />
Select Your Genre
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
{genres.map((genre) => (
<button
key={genre.id}
onClick={() => setSelectedGenre(genre.id)}
className={`p-4 rounded-xl border-2 text-left transition-all ${
selectedGenre === genre.id
? 'border-primary-500 bg-primary-50 shadow-md'
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'
}`}
>
<span className="text-2xl mb-2 block">{genre.icon}</span>
<h4 className="font-medium text-gray-900">{genre.name}</h4>
<p className="text-xs text-gray-500 mt-1 line-clamp-2">
{genre.description}
</p>
</button>
))}
</div>
</div>
</div>
{/* Book Details Form */}
<div>
<div className="card sticky top-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<Sparkles className="w-5 h-5" />
Book Details
</h3>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="label">Book Title (optional)</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="My Amazing Book"
className="input"
/>
</div>
<div>
<label className="label">
Core Idea <span className="text-red-500">*</span>
</label>
<textarea
value={idea}
onChange={(e) => setIdea(e.target.value)}
placeholder="Describe your book idea... What's the story about? Who are the main characters? What conflict drives the narrative?"
className="input min-h-[150px] resize-y"
required
/>
</div>
<div className="bg-amber-50 border border-amber-200 rounded-lg p-3">
<p className="text-xs text-amber-700">
<strong>Tip:</strong> The more details you provide, the better the AI can generate your outline and content.
</p>
</div>
<button
type="submit"
disabled={!selectedGenre || !idea.trim()}
className="btn-primary w-full py-3"
>
Generate Outline
</button>
</form>
</div>
</div>
</div>
);
}
@@ -0,0 +1,246 @@
import { useState } from 'react';
import { Image, Wand2, Type } from 'lucide-react';
import CoverGallery from './CoverGallery';
import CoverEditor from './CoverEditor';
import { useCoverStore, Cover } from '../../stores/coverStore';
import { coversApi } from '../../services/api';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
export default function CoverDesigner() {
const [activeTab, setActiveTab] = useState<'gallery' | 'editor' | 'ai'>('gallery');
const { activeCover, setActiveCover } = useCoverStore();
const queryClient = useQueryClient();
const { data: coversData } = useQuery({
queryKey: ['covers'],
queryFn: async () => {
const response = await coversApi.getAll();
return response.data.covers;
},
});
const generateCoverMutation = useMutation({
mutationFn: async (prompt: string) => {
const response = await coversApi.generate(prompt);
return response.data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['covers'] });
setActiveTab('gallery');
},
});
const handleGenerateAI = (prompt: string) => {
generateCoverMutation.mutate(prompt);
};
const handleSelectCover = (coverUrl: string) => {
const newCover: Cover = {
id: `cover-${Date.now()}`,
title: 'New Book',
author: 'Author Name',
backgroundImage: coverUrl,
backgroundColor: '#ffffff',
width: 1600,
height: 2400,
layers: [],
createdAt: new Date(),
updatedAt: new Date(),
};
setActiveCover(newCover);
setActiveTab('editor');
};
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Cover Designer</h2>
<p className="text-gray-500 mt-1">
Design stunning book covers with AI or manual editing
</p>
</div>
{/* Tab Navigation */}
<div className="flex bg-white rounded-lg p-1 border border-gray-200">
<button
onClick={() => setActiveTab('gallery')}
className={`flex items-center gap-2 px-4 py-2 rounded-md transition-colors ${
activeTab === 'gallery'
? 'bg-primary-100 text-primary-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
<Image className="w-4 h-4" />
Gallery
</button>
<button
onClick={() => setActiveTab('editor')}
className={`flex items-center gap-2 px-4 py-2 rounded-md transition-colors ${
activeTab === 'editor'
? 'bg-primary-100 text-primary-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
<Type className="w-4 h-4" />
Editor
</button>
<button
onClick={() => setActiveTab('ai')}
className={`flex items-center gap-2 px-4 py-2 rounded-md transition-colors ${
activeTab === 'ai'
? 'bg-primary-100 text-primary-700'
: 'text-gray-600 hover:bg-gray-100'
}`}
>
<Wand2 className="w-4 h-4" />
AI Generate
</button>
</div>
</div>
{activeTab === 'gallery' && (
<CoverGallery
covers={coversData || []}
onSelect={handleSelectCover}
onDelete={(id) => {
coversApi.delete(id).then(() => {
queryClient.invalidateQueries({ queryKey: ['covers'] });
});
}}
/>
)}
{activeTab === 'editor' && activeCover && (
<CoverEditor />
)}
{activeTab === 'ai' && (
<AIGenerator onGenerate={handleGenerateAI} isGenerating={generateCoverMutation.isPending} />
)}
</div>
);
}
function AIGenerator({
onGenerate,
isGenerating,
}: {
onGenerate: (prompt: string) => void;
isGenerating: boolean;
}) {
const [prompt, setPrompt] = useState('');
const [selectedStyle, setSelectedStyle] = useState('modern');
const styles = [
{ id: 'modern', name: 'Modern', icon: '✨' },
{ id: 'minimal', name: 'Minimalist', icon: '🎯' },
{ id: 'vintage', name: 'Vintage', icon: '📜' },
{ id: 'bold', name: 'Bold', icon: '🔥' },
{ id: 'elegant', name: 'Elegant', icon: '💎' },
{ id: 'playful', name: 'Playful', icon: '🎨' },
];
const genrePresets = [
{
genre: 'Mystery',
prompt: 'A mysterious book cover with dark shadows, silhouette of a detective, foggy street scene, noir atmosphere',
},
{
genre: 'Romance',
prompt: 'A romantic book cover with soft pastel colors, couple silhouette at sunset, dreamy and emotional',
},
{
genre: 'Fantasy',
prompt: 'An epic fantasy book cover with magical elements, dragon, castle in the background, mystical glowing effects',
},
{
genre: 'Sci-Fi',
prompt: 'A futuristic sci-fi book cover with spaceships, neon lights, cyberpunk city, high-tech atmosphere',
},
{
genre: 'Self-Help',
prompt: 'A clean self-help book cover with inspiring imagery, mountain peak or sunrise, professional and motivating',
},
];
const handleUsePreset = (presetPrompt: string) => {
setPrompt(presetPrompt);
};
const handleGenerate = () => {
if (prompt.trim()) {
const enhancedPrompt = `${prompt}, ${selectedStyle} style, professional book cover design, high quality, detailed`;
onGenerate(enhancedPrompt);
}
};
return (
<div className="card space-y-6">
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-4">
AI Cover Generator
</h3>
{/* Style Selection */}
<div className="mb-6">
<label className="label">Select Style</label>
<div className="grid grid-cols-3 sm:grid-cols-6 gap-2 mt-2">
{styles.map((style) => (
<button
key={style.id}
onClick={() => setSelectedStyle(style.id)}
className={`p-3 rounded-lg border text-center transition-colors ${
selectedStyle === style.id
? 'border-primary-500 bg-primary-50 text-primary-700'
: 'border-gray-200 hover:border-gray-300'
}`}
>
<span className="text-xl">{style.icon}</span>
<p className="text-xs mt-1">{style.name}</p>
</button>
))}
</div>
</div>
{/* Prompt Input */}
<div className="mb-6">
<label className="label">Describe Your Cover</label>
<textarea
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Describe the book cover you want to generate... e.g., 'A mysterious forest with glowing eyes in the darkness'"
className="input min-h-[120px] resize-y"
/>
</div>
{/* Genre Presets */}
<div className="mb-6">
<label className="label">Quick Presets by Genre</label>
<div className="grid gap-2 mt-2">
{genrePresets.map((preset) => (
<button
key={preset.genre}
onClick={() => handleUsePreset(preset.prompt)}
className="text-left px-4 py-2 rounded-lg border border-gray-200 hover:border-primary-300 hover:bg-primary-50 transition-colors"
>
<span className="font-medium">{preset.genre}</span>
<p className="text-sm text-gray-500 truncate">{preset.prompt}</p>
</button>
))}
</div>
</div>
{/* Generate Button */}
<button
onClick={handleGenerate}
disabled={!prompt.trim() || isGenerating}
className="btn-primary w-full py-3 flex items-center justify-center gap-2"
>
<Wand2 className="w-5 h-5" />
{isGenerating ? 'Generating...' : 'Generate Cover'}
</button>
</div>
</div>
);
}
@@ -0,0 +1,341 @@
import { useState, useRef, useEffect } from 'react';
import { Stage, Layer, Rect, Text, Transformer, Image as KonvaImage } from 'react-konva';
import type Konva from 'konva';
import { useCoverStore } from '../../stores/coverStore';
import { Type, Download } from 'lucide-react';
const BackgroundImage = ({ url, width, height }: { url: string; width: number; height: number }) => {
const [image, setImage] = useState<HTMLImageElement | null>(null);
useEffect(() => {
const img = new window.Image();
img.crossOrigin = 'Anonymous';
img.src = url;
img.onload = () => {
setImage(img);
};
}, [url]);
if (!image) return null;
return <KonvaImage image={image} x={0} y={0} width={width} height={height} />;
};
const FONTS = [
{ name: 'Roboto', label: 'Modern (Roboto)' },
{ name: 'Montserrat', label: 'Minimalist (Montserrat)' },
{ name: 'Playfair Display', label: 'Elegant (Playfair Display)' },
{ name: 'Bebas Neue', label: 'Bold (Bebas Neue)' },
{ name: 'Pacifico', label: 'Playful (Pacifico)' },
{ name: 'Georgia', label: 'Classic (Georgia)' },
{ name: 'Arial', label: 'Standard (Arial)' },
];
export default function CoverEditor() {
const { activeCover, addLayer, updateLayer, deleteLayer, selectedLayer, setSelectedLayer } = useCoverStore();
const stageRef = useRef<Konva.Stage>(null);
const [scale, setScale] = useState(0.5);
const [textTool, setTextTool] = useState<'title' | 'author'>('title');
const [newText, setNewText] = useState('');
const [selectedFont, setSelectedFont] = useState('Roboto');
if (!activeCover) {
return (
<div className="card text-center py-12">
<p className="text-gray-500">Select a cover from the gallery to edit</p>
</div>
);
}
const handleAddText = () => {
if (!newText.trim()) return;
const layer = {
id: `text-${Date.now()}`,
type: 'text' as const,
x: activeCover.width / 2,
y: activeCover.height / 2,
content: newText,
fontSize: textTool === 'title' ? 72 : 36,
fontFamily: selectedFont,
fill: textTool === 'title' ? '#ffffff' : '#f0f0f0',
rotation: 0,
opacity: 1,
};
addLayer(layer);
setNewText('');
};
const handleExport = () => {
const stage = stageRef.current;
if (stage) {
const dataURL = stage.toDataURL({ pixelRatio: 2 });
const link = document.createElement('a');
link.download = `${activeCover.title.replace(/\s+/g, '-')}-cover.png`;
link.href = dataURL;
link.click();
}
};
const containerWidth = 800;
const containerHeight = (activeCover.height / activeCover.width) * containerWidth;
return (
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* Editor Canvas */}
<div className="lg:col-span-3 card p-4 bg-gray-100">
<div className="flex items-center justify-between mb-4">
<h3 className="font-semibold text-gray-900">
Editing: {activeCover.title}
</h3>
<div className="flex items-center gap-2">
<button
onClick={handleExport}
className="btn-primary flex items-center gap-2"
>
<Download className="w-4 h-4" />
Export
</button>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm overflow-hidden flex items-center justify-center p-4">
<Stage
ref={stageRef}
width={containerWidth}
height={containerHeight}
scaleX={scale}
scaleY={scale}
>
<Layer>
{/* Background */}
<Rect
x={0}
y={0}
width={activeCover.width}
height={activeCover.height}
fill={activeCover.backgroundColor}
/>
{/* Background Image if exists */}
{activeCover.backgroundImage && (
<BackgroundImage
url={activeCover.backgroundImage}
width={activeCover.width}
height={activeCover.height}
/>
)}
{/* Layers */}
{activeCover.layers.map((layer) => (
<Text
key={layer.id}
id={layer.id}
x={layer.x}
y={layer.y}
text={layer.content}
fontSize={layer.fontSize}
fontFamily={layer.fontFamily}
fill={layer.fill}
rotation={layer.rotation}
opacity={layer.opacity}
draggable
onClick={() => setSelectedLayer(layer.id)}
onTap={() => setSelectedLayer(layer.id)}
/>
))}
{/* Transformer for selected layer */}
{selectedLayer && (
<Transformer
nodes={
activeCover.layers
.filter((l) => l.id === selectedLayer)
.map((l) => document.getElementById(l.id)) as any[]
}
/>
)}
</Layer>
</Stage>
</div>
{/* Zoom Control */}
<div className="mt-4 flex items-center justify-center gap-4">
<button
onClick={() => setScale(Math.max(0.2, scale - 0.1))}
className="btn-secondary px-3"
>
-
</button>
<span className="text-sm text-gray-600">
{Math.round(scale * 100)}%
</span>
<button
onClick={() => setScale(Math.min(1, scale + 0.1))}
className="btn-secondary px-3"
>
+
</button>
</div>
</div>
{/* Tools Panel */}
<div className="space-y-4">
{/* Add Text */}
<div className="card">
<h4 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
<Type className="w-4 h-4" />
Add Text
</h4>
<div className="space-y-3">
<div>
<label className="label">Text Type</label>
<div className="flex gap-2">
<button
onClick={() => setTextTool('title')}
className={`flex-1 py-2 rounded-lg text-sm font-medium transition-colors ${
textTool === 'title'
? 'bg-primary-100 text-primary-700'
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
}`}
>
Title
</button>
<button
onClick={() => setTextTool('author')}
className={`flex-1 py-2 rounded-lg text-sm font-medium transition-colors ${
textTool === 'author'
? 'bg-primary-100 text-primary-700'
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
}`}
>
Author
</button>
</div>
</div>
<div>
<label className="label">Font</label>
<select
value={selectedFont}
onChange={(e) => setSelectedFont(e.target.value)}
className="input"
>
{FONTS.map((font) => (
<option key={font.name} value={font.name}>
{font.label}
</option>
))}
</select>
</div>
<div>
<label className="label">Text Content</label>
<input
type="text"
value={newText}
onChange={(e) => setNewText(e.target.value)}
placeholder={textTool === 'title' ? 'Book Title' : 'Author Name'}
className="input"
onKeyPress={(e) => e.key === 'Enter' && handleAddText()}
/>
</div>
<button
onClick={handleAddText}
disabled={!newText.trim()}
className="btn-primary w-full"
>
Add Text Layer
</button>
</div>
</div>
{/* Edit Selected Text */}
{selectedLayer && activeCover.layers.find(l => l.id === selectedLayer)?.type === 'text' && (
<div className="card">
<h4 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
<Type className="w-4 h-4" />
Edit Selected Text
</h4>
<div className="space-y-3">
<div>
<label className="label">Font</label>
<select
value={activeCover.layers.find((l) => l.id === selectedLayer)?.fontFamily || 'Roboto'}
onChange={(e) => updateLayer(selectedLayer, { fontFamily: e.target.value })}
className="input"
>
{FONTS.map((font) => (
<option key={font.name} value={font.name}>
{font.label}
</option>
))}
</select>
</div>
</div>
</div>
)}
{/* Layers List */}
<div className="card">
<h4 className="font-medium text-gray-900 mb-4">Layers</h4>
{activeCover.layers.length === 0 ? (
<p className="text-sm text-gray-500">No layers yet</p>
) : (
<div className="space-y-2">
{activeCover.layers.map((layer, index) => (
<div
key={layer.id}
className={`flex items-center justify-between p-2 rounded-lg border cursor-pointer transition-colors ${
selectedLayer === layer.id
? 'border-primary-500 bg-primary-50'
: 'border-gray-200 hover:bg-gray-50'
}`}
onClick={() => setSelectedLayer(layer.id)}
>
<div className="flex items-center gap-2">
<Type className="w-4 h-4 text-gray-400" />
<span className="text-sm truncate max-w-[150px]">
{layer.content?.substring(0, 20) || `Layer ${index + 1}`}
</span>
</div>
<button
onClick={(e) => {
e.stopPropagation();
deleteLayer(layer.id);
}}
className="p-1 hover:bg-red-100 rounded"
>
<svg className="w-4 h-4 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
))}
</div>
)}
</div>
{/* Cover Info */}
<div className="card">
<h4 className="font-medium text-gray-900 mb-4">Cover Info</h4>
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-gray-500">Dimensions</span>
<span className="text-gray-900">
{activeCover.width} x {activeCover.height}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-500">Layers</span>
<span className="text-gray-900">{activeCover.layers.length}</span>
</div>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,83 @@
import { Image, Eye, Trash2, Download } from 'lucide-react';
interface CoverData {
id: string;
filename: string;
url: string;
createdAt: string;
}
interface CoverGalleryProps {
covers: CoverData[];
onSelect: (coverUrl: string) => void;
onDelete: (coverId: string) => void;
}
export default function CoverGallery({ covers, onSelect, onDelete }: CoverGalleryProps) {
if (covers.length === 0) {
return (
<div className="card text-center py-12">
<Image className="w-16 h-16 text-gray-300 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900">No covers yet</h3>
<p className="text-gray-500 mt-2">
Upload a cover image or generate one with AI to get started
</p>
</div>
);
}
return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{covers.map((cover) => (
<div
key={cover.id}
className="card p-0 overflow-hidden group hover:shadow-lg transition-shadow"
>
<div className="aspect-[2/3] relative bg-gray-100">
<img
src={cover.url}
alt={cover.filename}
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-2">
<button
onClick={() => onSelect(cover.url)}
className="p-2 bg-white rounded-lg hover:bg-gray-100 transition-colors"
title="Edit"
>
<Eye className="w-5 h-5 text-gray-700" />
</button>
<button
onClick={() => {
const link = document.createElement('a');
link.href = cover.url;
link.download = cover.filename;
link.click();
}}
className="p-2 bg-white rounded-lg hover:bg-gray-100 transition-colors"
title="Download"
>
<Download className="w-5 h-5 text-gray-700" />
</button>
<button
onClick={() => onDelete(cover.id)}
className="p-2 bg-red-500 rounded-lg hover:bg-red-600 transition-colors"
title="Delete"
>
<Trash2 className="w-5 h-5 text-white" />
</button>
</div>
</div>
<div className="p-3">
<p className="text-sm font-medium text-gray-900 truncate">
{cover.filename}
</p>
<p className="text-xs text-gray-500 mt-1">
{new Date(cover.createdAt).toLocaleDateString()}
</p>
</div>
</div>
))}
</div>
);
}
+22
View File
@@ -0,0 +1,22 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import enTranslation from './locales/en.json';
import esTranslation from './locales/es.json';
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: {
en: { translation: enTranslation },
es: { translation: esTranslation }
},
fallbackLng: 'en',
interpolation: {
escapeValue: false,
}
});
export default i18n;
+37
View File
@@ -0,0 +1,37 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
}
body {
margin: 0;
min-height: 100vh;
background-color: #f8fafc;
}
@layer components {
.btn-primary {
@apply bg-primary-600 hover:bg-primary-700 text-white font-medium px-4 py-2 rounded-lg transition-colors;
}
.btn-secondary {
@apply bg-white hover:bg-gray-50 text-gray-700 border border-gray-300 font-medium px-4 py-2 rounded-lg transition-colors;
}
.card {
@apply bg-white rounded-xl shadow-sm border border-gray-200 p-6;
}
.input {
@apply w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent outline-none transition-all;
}
.label {
@apply block text-sm font-medium text-gray-700 mb-1;
}
}
+28
View File
@@ -0,0 +1,28 @@
{
"nav": {
"coverDesigner": "Cover Designer",
"bookGenerator": "Book Generator",
"settings": "Settings",
"loginRegister": "Login / Register",
"logout": "Logout"
},
"auth": {
"welcomeBack": "Welcome Back",
"createAccount": "Create an Account",
"name": "Name",
"email": "Email",
"password": "Password",
"login": "Login",
"signUp": "Sign Up",
"pleaseWait": "Please wait...",
"dontHaveAccount": "Don't have an account? ",
"alreadyHaveAccount": "Already have an account? "
},
"settings": {
"title": "Settings",
"language": "Language",
"languageSelect": "Select your preferred language",
"english": "English",
"spanish": "Español"
}
}
+28
View File
@@ -0,0 +1,28 @@
{
"nav": {
"coverDesigner": "Diseñador de Portadas",
"bookGenerator": "Generador de Libros",
"settings": "Ajustes",
"loginRegister": "Entrar / Registrarse",
"logout": "Cerrar Sesión"
},
"auth": {
"welcomeBack": "Bienvenido de nuevo",
"createAccount": "Crea una cuenta",
"name": "Nombre",
"email": "Correo electrónico",
"password": "Contraseña",
"login": "Entrar",
"signUp": "Registrarse",
"pleaseWait": "Por favor espera...",
"dontHaveAccount": "¿No tienes una cuenta? ",
"alreadyHaveAccount": "¿Ya tienes una cuenta? "
},
"settings": {
"title": "Ajustes",
"language": "Idioma",
"languageSelect": "Selecciona tu idioma preferido",
"english": "Inglés",
"spanish": "Español"
}
}
+26
View File
@@ -0,0 +1,26 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './App';
import './index.css';
import './i18n';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
retry: 1,
},
},
});
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<App />
</BrowserRouter>
</QueryClientProvider>
</React.StrictMode>
);
+74
View File
@@ -0,0 +1,74 @@
import axios from 'axios';
export const api = axios.create({
baseURL: '/api',
headers: {
'Content-Type': 'application/json',
},
});
api.interceptors.request.use((config) => {
const language = localStorage.getItem('i18nextLng') || 'en';
// Autoinject into data wrapper payload for POST/PUT if structured JSON
if (config.data && typeof config.data === 'object' && !(config.data instanceof FormData)) {
config.data.language = language;
} else if (config.data instanceof FormData) {
config.data.append('language', language);
}
// Let's also attach explicitly to headers
config.headers['Accept-Language'] = language;
return config;
});
// Covers API calls
export const coversApi = {
getAll: () => api.get('/covers'),
upload: (file: File) => {
const formData = new FormData();
formData.append('image', file);
return api.post('/covers/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
},
delete: (id: string) => api.delete(`/covers/${id}`),
process: (file: File, options?: Record<string, string>) => {
const formData = new FormData();
formData.append('image', file);
if (options) {
Object.entries(options).forEach(([key, value]) => {
formData.append(key, value);
});
}
return api.post('/covers/process', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
},
generate: (prompt: string, genre?: string) =>
api.post('/covers/generate', { prompt, genre }),
};
// Books API calls
export const booksApi = {
getGenres: () => api.get('/books/genres'),
getGenre: (genreId: string) => api.get(`/books/genres/${genreId}`),
generateOutline: (genre: string, idea: string, title?: string) =>
api.post('/books/outline', { genre, idea, title }),
generateChapter: (
genre: string,
chapterTitle: string,
chapterSummary: string,
previousContent?: string
) =>
api.post('/books/chapter', {
genre,
chapterTitle,
chapterSummary,
previousContent,
}),
expand: (text: string, instruction?: string) =>
api.post('/books/expand', { text, instruction }),
generateCharacters: (genre: string, storyIdea: string) =>
api.post('/books/characters', { genre, storyIdea }),
generatePlot: (genre: string, currentPlot: string, issue?: string) =>
api.post('/books/plot', { genre, currentPlot, issue }),
};
+57
View File
@@ -0,0 +1,57 @@
import { create } from 'zustand';
import axios from 'axios';
interface User {
id: string;
email: string;
name?: string;
role?: string;
}
interface AuthState {
user: User | null;
token: string | null;
isAuthenticated: boolean;
setAuth: (user: User, token: string) => void;
logout: () => void;
checkAuth: () => Promise<void>;
}
export const useAuthStore = create<AuthState>((set) => ({
user: null,
token: localStorage.getItem('creabook_token'),
isAuthenticated: !!localStorage.getItem('creabook_token'),
setAuth: (user, token) => {
localStorage.setItem('creabook_token', token);
set({ user, token, isAuthenticated: true });
},
logout: async () => {
const token = localStorage.getItem('creabook_token');
if (token) {
try {
await axios.post('/api/auth/logout', {}, {
headers: { Authorization: `Bearer ${token}` }
});
} catch (err) {}
}
localStorage.removeItem('creabook_token');
set({ user: null, token: null, isAuthenticated: false });
},
checkAuth: async () => {
const token = localStorage.getItem('creabook_token');
if (token) {
try {
const response = await axios.get('/api/auth/me', {
headers: { Authorization: `Bearer ${token}` }
});
set({ user: response.data.user, token, isAuthenticated: true });
} catch (error) {
localStorage.removeItem('creabook_token');
set({ user: null, token: null, isAuthenticated: false });
}
}
}
}));
+185
View File
@@ -0,0 +1,185 @@
import { create } from 'zustand';
export interface Chapter {
number: number;
title: string;
summary: string;
content: string;
isGenerated: boolean;
}
export interface BookOutline {
title: string;
genre: string;
logline: string;
chapters: Chapter[];
}
export interface Character {
name: string;
role: string;
traits: string[];
motivation: string;
backstory: string;
}
export interface Book {
id: string;
title: string;
genre: string;
idea: string;
outline: BookOutline | null;
characters: Character[];
currentChapter: number;
coverId?: string;
createdAt: Date;
updatedAt: Date;
}
interface BookState {
books: Book[];
activeBook: Book | null;
isGenerating: boolean;
generationProgress: number;
// Actions
addBook: (book: Book) => void;
updateBook: (id: string, updates: Partial<Book>) => void;
deleteBook: (id: string) => void;
setActiveBook: (book: Book | null) => void;
setOutline: (outline: BookOutline) => void;
addCharacter: (character: Character) => void;
updateChapterContent: (chapterNumber: number, content: string) => void;
setCurrentChapter: (chapterNumber: number) => void;
setCoverForBook: (coverId: string) => void;
setIsGenerating: (isGenerating: boolean) => void;
setGenerationProgress: (progress: number) => void;
}
export const useBookStore = create<BookState>((set) => ({
books: [],
activeBook: null,
isGenerating: false,
generationProgress: 0,
addBook: (book) =>
set((state) => ({
books: [book, ...state.books],
activeBook: book,
})),
updateBook: (id, updates) =>
set((state) => ({
books: state.books.map((b) =>
b.id === id ? { ...b, ...updates, updatedAt: new Date() } : b
),
activeBook: state.activeBook?.id === id
? { ...state.activeBook, ...updates, updatedAt: new Date() }
: state.activeBook,
})),
deleteBook: (id) =>
set((state) => ({
books: state.books.filter((b) => b.id !== id),
activeBook: state.activeBook?.id === id ? null : state.activeBook,
})),
setActiveBook: (book) => set({ activeBook: book }),
setOutline: (outline) =>
set((state) => {
if (!state.activeBook) return state;
const updatedBook = {
...state.activeBook,
outline,
updatedAt: new Date(),
};
return {
activeBook: updatedBook,
books: state.books.map((b) =>
b.id === state.activeBook!.id ? updatedBook : b
),
};
}),
addCharacter: (character) =>
set((state) => {
if (!state.activeBook) return state;
const updatedBook = {
...state.activeBook,
characters: [...state.activeBook.characters, character],
updatedAt: new Date(),
};
return {
activeBook: updatedBook,
books: state.books.map((b) =>
b.id === state.activeBook!.id ? updatedBook : b
),
};
}),
updateChapterContent: (chapterNumber, content) =>
set((state) => {
if (!state.activeBook || !state.activeBook.outline) return state;
const updatedOutline = {
...state.activeBook.outline,
chapters: state.activeBook.outline.chapters.map((chapter) =>
chapter.number === chapterNumber
? { ...chapter, content, isGenerated: true }
: chapter
),
};
const updatedBook = {
...state.activeBook,
outline: updatedOutline,
updatedAt: new Date(),
};
return {
activeBook: updatedBook,
books: state.books.map((b) =>
b.id === state.activeBook!.id ? updatedBook : b
),
};
}),
setCurrentChapter: (chapterNumber) =>
set((state) => {
if (!state.activeBook) return state;
return {
activeBook: {
...state.activeBook,
currentChapter: chapterNumber,
},
};
}),
setCoverForBook: (coverId) =>
set((state) => {
if (!state.activeBook) return state;
const updatedBook = {
...state.activeBook,
coverId,
updatedAt: new Date(),
};
return {
activeBook: updatedBook,
books: state.books.map((b) =>
b.id === state.activeBook!.id ? updatedBook : b
),
};
}),
setIsGenerating: (isGenerating) => set({ isGenerating }),
setGenerationProgress: (progress) => set({ generationProgress: progress }),
}));
+134
View File
@@ -0,0 +1,134 @@
import { create } from 'zustand';
export interface CoverLayer {
id: string;
type: 'text' | 'image' | 'shape';
x: number;
y: number;
width?: number;
height?: number;
content?: string;
fontSize?: number;
fontFamily?: string;
fill?: string;
rotation?: number;
opacity?: number;
}
export interface Cover {
id: string;
title: string;
author: string;
backgroundImage?: string;
backgroundColor: string;
width: number;
height: number;
layers: CoverLayer[];
createdAt: Date;
updatedAt: Date;
}
interface CoverState {
covers: Cover[];
activeCover: Cover | null;
selectedLayer: string | null;
// Actions
addCover: (cover: Cover) => void;
updateCover: (id: string, updates: Partial<Cover>) => void;
deleteCover: (id: string) => void;
setActiveCover: (cover: Cover | null) => void;
setSelectedLayer: (layerId: string | null) => void;
addLayer: (layer: CoverLayer) => void;
updateLayer: (layerId: string, updates: Partial<CoverLayer>) => void;
deleteLayer: (layerId: string) => void;
}
export const useCoverStore = create<CoverState>((set) => ({
covers: [],
activeCover: null,
selectedLayer: null,
addCover: (cover) =>
set((state) => ({
covers: [cover, ...state.covers],
activeCover: cover,
})),
updateCover: (id, updates) =>
set((state) => ({
covers: state.covers.map((c) =>
c.id === id ? { ...c, ...updates, updatedAt: new Date() } : c
),
activeCover: state.activeCover?.id === id
? { ...state.activeCover, ...updates, updatedAt: new Date() }
: state.activeCover,
})),
deleteCover: (id) =>
set((state) => ({
covers: state.covers.filter((c) => c.id !== id),
activeCover: state.activeCover?.id === id ? null : state.activeCover,
})),
setActiveCover: (cover) => set({ activeCover: cover, selectedLayer: null }),
setSelectedLayer: (layerId) => set({ selectedLayer: layerId }),
addLayer: (layer) =>
set((state) => {
if (!state.activeCover) return state;
const updatedCover = {
...state.activeCover,
layers: [...state.activeCover.layers, layer],
updatedAt: new Date(),
};
return {
activeCover: updatedCover,
covers: state.covers.map((c) =>
c.id === state.activeCover!.id ? updatedCover : c
),
};
}),
updateLayer: (layerId, updates) =>
set((state) => {
if (!state.activeCover) return state;
const updatedCover = {
...state.activeCover,
layers: state.activeCover.layers.map((l) =>
l.id === layerId ? { ...l, ...updates } : l
),
updatedAt: new Date(),
};
return {
activeCover: updatedCover,
covers: state.covers.map((c) =>
c.id === state.activeCover!.id ? updatedCover : c
),
};
}),
deleteLayer: (layerId) =>
set((state) => {
if (!state.activeCover) return state;
const updatedCover = {
...state.activeCover,
layers: state.activeCover.layers.filter((l) => l.id !== layerId),
updatedAt: new Date(),
};
return {
activeCover: updatedCover,
covers: state.covers.map((c) =>
c.id === state.activeCover!.id ? updatedCover : c
),
selectedLayer: state.selectedLayer === layerId ? null : state.selectedLayer,
};
}),
}));
+38
View File
@@ -0,0 +1,38 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
},
accent: {
50: '#fdf4ff',
100: '#fae8ff',
200: '#f5d0fe',
300: '#f0abfc',
400: '#e879f9',
500: '#d946ef',
600: '#c026d3',
700: '#a21caf',
800: '#86198f',
900: '#701a75',
},
},
},
},
plugins: [],
}
+21
View File
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
+10
View File
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}
+25
View File
@@ -0,0 +1,25 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
server: {
port: 5000,
proxy: {
'/api': {
target: 'http://localhost:5001',
changeOrigin: true,
},
'/uploads': {
target: 'http://localhost:5001',
changeOrigin: true,
},
},
},
});