Skip to content
Draft

demo #28

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions public/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Redirecting...</title>

<meta http-equiv="refresh" content="0; url=https://demo.vividpdf.pages.dev">

<link rel="canonical" href="https://demo.vividpdf.pages.dev">

<script>
// Method 3: JavaScript location.replace (Does not add to browser history)
if (typeof window !== 'undefined') {
window.location.replace("https://demo.vividpdf.pages.dev");

// Method 4: JavaScript location.href (Fallback if replace fails)
window.location.href = "https://demo.vividpdf.pages.dev";
}
</script>
</head>

<body>
<p>Redirecting.</p>
<p>If your browser does not redirect you automatically, <a href="https://demo.vividpdf.pages.dev">click here to
proceed</a>.</p>
</body>

</html>
25 changes: 25 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -1010,4 +1010,29 @@ kbd {
padding: 2px 6px;
white-space: nowrap;
font-family: monospace;
}

.demo-banner {
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(90deg, #6366f1 0%, #a855f7 100%);
color: white;
text-align: center;
padding: 6px 16px;
font-size: 12px;
font-weight: 500;
z-index: 10000;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
white-space: nowrap;
}

.demo-banner a {
color: white;
text-decoration: underline;
font-weight: 600;
margin-left: 4px;
}
135 changes: 123 additions & 12 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ import { groupTokensIntoSentences } from './parsing';
import SpeechCustomizationPanel from './SpeechCustomizationPanel';
import { getVoiceSettings, calculateActualRate, PRIORITY_VOICES } from './voiceSpeedConfig'; // IMPORT VOICE CONFIG
import BugReport from './components/BugReport/BugReport';
import { initDemoFile } from './services/demoService';
import { initDemoFile, DEMO_DEFAULTS } from './services/demoService';
import './App.css';

pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker;

// --- Demo Mode Flag ---
const IS_DEMO_MODE = true;

// --- Local Storage Keys ---
const LS_GLOBALS = 'pdf_reader_globals';
const LS_AI_CONFIG = 'pdf_reader_ai_config'; // New Key
Expand All @@ -50,8 +53,8 @@ const DEFAULT_GLOBALS = {
skipSquare: false,
skipParens: false,
skipCurly: false,
skipCitations: true,
skipSuperscriptCitations: false,
skipCitations: true,
skipSuperscriptCitations: true,
visualIndicator: true
},
customPronunciations: [],
Expand All @@ -74,9 +77,94 @@ const DEFAULT_STORAGE_SETTINGS = {
autoMetadataOnly: false
};

const isWeChat = /MicroMessenger/i.test(navigator.userAgent);

const WeChatBlock = () => {
const [imageIndex, setImageIndex] = useState(1);

useEffect(() => {
const interval = setInterval(() => {
setImageIndex(prev => (prev === 1 ? 2 : 1));
}, 500);
return () => clearInterval(interval);
}, []);

return (
<div style={{
height: '100vh',
width: '100vw',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ffffff',
color: '#333333',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
textAlign: 'center',
padding: '20px',
boxSizing: 'border-box',
position: 'relative',
overflow: 'hidden'
}}>
<div style={{
fontSize: '24px',
fontWeight: 'bold',
marginBottom: '20px',
color: '#07C160' // WeChat Green
}}>
VIVIDpdf
</div>
<div style={{
fontSize: '18px',
lineHeight: '1.6',
maxWidth: '300px'
}}>
请用电脑/iPad浏览器打开
<div style={{
marginTop: '10px',
color: '#576b95',
wordBreak: 'break-all',
fontWeight: '500',
fontSize: '16px'
}}>
uoft.me/vividpdf
</div>
</div>

{/* Flickering Images at Bottom */}
<div style={{
position: 'absolute',
bottom: '40px',
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '120px'
}}>
<img
src={`/${imageIndex}.png`}
alt="flicker"
style={{
maxHeight: '100%',
maxWidth: '80%',
objectFit: 'contain',
opacity: 0.9
}}
/>
</div>
</div>
);
};

const App = () => {
if (isWeChat) {
return <WeChatBlock />;
}


// --- Global Settings (Init from LocalStorage) ---
const [globalSettings, setGlobalSettings] = useState(() => {
if (IS_DEMO_MODE) return { ...DEFAULT_GLOBALS, ...DEMO_DEFAULTS };
try {
const saved = localStorage.getItem(LS_GLOBALS);
return saved ? { ...DEFAULT_GLOBALS, ...JSON.parse(saved) } : DEFAULT_GLOBALS;
Expand All @@ -87,6 +175,7 @@ const App = () => {

// --- AI Config State ---
const [aiConfig, setAiConfig] = useState(() => {
if (IS_DEMO_MODE) return { ...DEFAULT_AI_CONFIG, ...DEMO_DEFAULTS.aiConfig };
try {
const saved = localStorage.getItem(LS_AI_CONFIG);
return saved ? { ...DEFAULT_AI_CONFIG, ...JSON.parse(saved) } : DEFAULT_AI_CONFIG;
Expand Down Expand Up @@ -122,8 +211,9 @@ const App = () => {

// Save AI Config on change
useEffect(() => {
localStorage.setItem(LS_AI_CONFIG, JSON.stringify(aiConfig));
aiConfigRef.current = aiConfig;
if (IS_DEMO_MODE) return;
localStorage.setItem(LS_AI_CONFIG, JSON.stringify(aiConfig));
}, [aiConfig]);

const aiConfigRef = useRef(aiConfig);
Expand Down Expand Up @@ -415,6 +505,7 @@ const App = () => {

// 1. Save Global Settings to LocalStorage on change
useEffect(() => {
if (IS_DEMO_MODE) return;
const settings = {
voiceURI: selectedVoiceURI,
readingMode,
Expand Down Expand Up @@ -449,15 +540,30 @@ const App = () => {

// 2. Load Recent Files on Mount
useEffect(() => {
const checkDemoRoute = async () => {
if (window.location.pathname === '/demo') {
console.log("[Demo] Detected /demo route, initializing demo.pdf");
await initDemoFile();
loadRecentFilesList();
const initDemo = async () => {
const fid = await initDemoFile();
if (fid) {
const record = await getFileRecord(fid);
if (record && record.blob) {
loadFromBlob(record.blob, record);
}
}
loadRecentFilesList();
};
checkDemoRoute();
loadRecentFilesList();

if (IS_DEMO_MODE) {
initDemo();
} else {
const checkDemoRoute = async () => {
if (window.location.pathname === '/demo') {
console.log("[Demo] Detected /demo route, initializing demo.pdf");
await initDemoFile();
loadRecentFilesList();
}
};
checkDemoRoute();
loadRecentFilesList();
}
}, []);

useEffect(() => {
Expand Down Expand Up @@ -906,7 +1012,7 @@ const App = () => {

} catch (error) {
console.error("Error loading PDF:", error);
alert("Failed to load PDF. Please ensure it is a valid file.");
alert("Failed to load PDF. Please ensure it is a valid file. 请使用电脑/平板打开");
} finally {
setIsLoading(false);
}
Expand Down Expand Up @@ -2146,6 +2252,11 @@ const App = () => {

return (
<div className="app-layout" onDragOver={handleDragOver} onDragLeave={handleDragLeave} onDrop={handleDrop}>
{IS_DEMO_MODE && (
<div className="demo-banner">
This is a demo page. To use our app, go to <a href="https://vividpdf.pages.dev" target="_blank" rel="noopener noreferrer">vividpdf.pages.dev</a>
</div>
)}
{/* Hidden File Input with Ref */}
<input
type="file"
Expand Down
50 changes: 49 additions & 1 deletion src/services/demoService.js

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/services/trash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import base64

def prepare_for_atob(input_string):
# 1. Convert the string to bytes (UTF-8 is standard)
message_bytes = input_string.encode('utf-8')

# 2. Encode bytes to Base64 bytes
base64_bytes = base64.b64encode(message_bytes)

# 3. Decode back to a string for transport/output
base64_message = base64_bytes.decode('utf-8')

return base64_message

# Example Usage
encoded_output = prepare_for_atob(original_text)

print(f"Original: {original_text}")
print(f"For atob(): {encoded_output}")