434 lines
19 KiB
TypeScript
434 lines
19 KiB
TypeScript
/**
|
|
* Notes module landing page — static HTML, no React.
|
|
*/
|
|
export function renderLanding(): string {
|
|
return `
|
|
<!-- Hero -->
|
|
<div class="rl-hero">
|
|
<span class="rl-tagline">rNotes</span>
|
|
<h1 class="rl-heading" style="background:linear-gradient(135deg,#f59e0b,#f97316);-webkit-background-clip:text;background-clip:text">(You)rNotes, your thoughts unbound.</h1>
|
|
<p class="rl-subtitle" style="background:linear-gradient(135deg,#f59e0b,#f97316);-webkit-background-clip:text;background-clip:text">Capture Everything, Find Anything, and Share your Insights</p>
|
|
<p class="rl-subtext">
|
|
Notes, clips, voice recordings, and live transcription — all in one place.
|
|
Speak and watch your words appear in real time, or drop in audio and video files to transcribe offline.
|
|
</p>
|
|
<div class="rl-cta-row">
|
|
<a href="https://demo.rspace.online/rnotes" class="rl-cta-primary" id="ml-primary">Open Notebook</a>
|
|
<a href="#transcription-demo" class="rl-cta-secondary">Transcribe</a>
|
|
<a href="#extension-download" class="rl-cta-secondary">Get Extension</a>
|
|
</div>
|
|
<p style="font-size:0.82rem;margin-top:0.5rem">
|
|
<a href="#" onclick="document.querySelector('folk-notes-app')?.startTour?.();window.__rspaceHideInfo?.();return false" style="color:var(--rs-primary,#06b6d4);text-decoration:none">
|
|
Start Guided Tour →
|
|
</a>
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Live Transcription Demo -->
|
|
<section class="rl-section" id="transcription-demo">
|
|
<div class="rl-container">
|
|
<h2 class="rl-heading" style="text-align:center">Live Transcription Demo</h2>
|
|
<p class="rl-subtext" style="text-align:center">Try it right here — click the mic and start speaking.</p>
|
|
|
|
<div style="max-width:640px;margin:2rem auto;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);border-radius:1rem;padding:1.5rem;position:relative">
|
|
<!-- Unsupported fallback (hidden by default, shown via JS) -->
|
|
<div id="transcription-unsupported" style="display:none;text-align:center;padding:2rem 1rem;color:#94a3b8">
|
|
<div style="font-size:2rem;margin-bottom:0.75rem">⚠️</div>
|
|
<p style="margin:0 0 0.5rem">Live transcription requires <strong>Chrome</strong> or <strong>Edge</strong> (Web Speech API).</p>
|
|
<p style="margin:0;font-size:0.85rem;color:#64748b">Try opening this page in a Chromium-based browser to test the demo.</p>
|
|
</div>
|
|
|
|
<!-- Demo UI (hidden if unsupported) -->
|
|
<div id="transcription-ui">
|
|
<!-- Controls -->
|
|
<div style="display:flex;align-items:center;justify-content:center;gap:1rem;margin-bottom:1.25rem">
|
|
<button id="mic-btn" style="width:56px;height:56px;border-radius:50%;border:2px solid rgba(245,158,11,0.4);background:rgba(245,158,11,0.1);color:#f59e0b;font-size:1.5rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.2s" title="Start transcription">
|
|
🎤
|
|
</button>
|
|
<div style="text-align:left">
|
|
<div id="mic-status" style="font-size:0.9rem;color:#94a3b8">Click mic to start</div>
|
|
<div id="mic-timer" style="font-size:0.75rem;color:#64748b;font-variant-numeric:tabular-nums">00:00</div>
|
|
</div>
|
|
<div id="live-indicator" style="display:none;background:rgba(239,68,68,0.15);color:#ef4444;font-size:0.7rem;font-weight:600;padding:0.2rem 0.6rem;border-radius:9999px;text-transform:uppercase;letter-spacing:0.05em">
|
|
● Live
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Transcript area -->
|
|
<div id="transcript-area" style="min-height:120px;max-height:240px;overflow-y:auto;background:rgba(0,0,0,0.2);border-radius:0.5rem;padding:1rem;font-size:0.9rem;line-height:1.6;color:#e2e8f0">
|
|
<span style="color:#64748b;font-style:italic">Your transcript will appear here…</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Capability badges -->
|
|
<div style="display:flex;flex-wrap:wrap;gap:0.5rem;justify-content:center;margin-top:1.25rem">
|
|
<span class="rl-badge" style="background:rgba(34,197,94,0.15);color:#22c55e">● Live streaming</span>
|
|
<span class="rl-badge" style="background:rgba(59,130,246,0.15);color:#3b82f6">🎵 Audio file upload</span>
|
|
<span class="rl-badge" style="background:rgba(168,85,247,0.15);color:#a855f7">🎥 Video transcription</span>
|
|
<span class="rl-badge" style="background:rgba(245,158,11,0.15);color:#f59e0b">🔌 Offline (Parakeet.js)</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Transcription Demo Script -->
|
|
<script>
|
|
(function() {
|
|
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
var ui = document.getElementById('transcription-ui');
|
|
var unsupported = document.getElementById('transcription-unsupported');
|
|
if (!SpeechRecognition) {
|
|
if (ui) ui.style.display = 'none';
|
|
if (unsupported) unsupported.style.display = 'block';
|
|
return;
|
|
}
|
|
|
|
var recognition = new SpeechRecognition();
|
|
recognition.continuous = true;
|
|
recognition.interimResults = true;
|
|
recognition.lang = 'en-US';
|
|
|
|
var micBtn = document.getElementById('mic-btn');
|
|
var micStatus = document.getElementById('mic-status');
|
|
var micTimer = document.getElementById('mic-timer');
|
|
var liveIndicator = document.getElementById('live-indicator');
|
|
var transcriptArea = document.getElementById('transcript-area');
|
|
|
|
var isListening = false;
|
|
var timerInterval = null;
|
|
var seconds = 0;
|
|
var finalTranscript = '';
|
|
|
|
function formatTime(s) {
|
|
var m = Math.floor(s / 60);
|
|
var sec = s % 60;
|
|
return (m < 10 ? '0' : '') + m + ':' + (sec < 10 ? '0' : '') + sec;
|
|
}
|
|
|
|
function startTimer() {
|
|
seconds = 0;
|
|
micTimer.textContent = '00:00';
|
|
timerInterval = setInterval(function() {
|
|
seconds++;
|
|
micTimer.textContent = formatTime(seconds);
|
|
}, 1000);
|
|
}
|
|
|
|
function stopTimer() {
|
|
if (timerInterval) { clearInterval(timerInterval); timerInterval = null; }
|
|
}
|
|
|
|
micBtn.addEventListener('click', function() {
|
|
if (!isListening) {
|
|
finalTranscript = '';
|
|
transcriptArea.innerHTML = '';
|
|
recognition.start();
|
|
} else {
|
|
recognition.stop();
|
|
}
|
|
});
|
|
|
|
recognition.onstart = function() {
|
|
isListening = true;
|
|
micBtn.style.background = 'rgba(239,68,68,0.2)';
|
|
micBtn.style.borderColor = '#ef4444';
|
|
micBtn.style.color = '#ef4444';
|
|
micBtn.title = 'Stop transcription';
|
|
micStatus.textContent = 'Listening...';
|
|
micStatus.style.color = '#ef4444';
|
|
liveIndicator.style.display = 'block';
|
|
startTimer();
|
|
};
|
|
|
|
recognition.onend = function() {
|
|
isListening = false;
|
|
micBtn.style.background = 'rgba(245,158,11,0.1)';
|
|
micBtn.style.borderColor = 'rgba(245,158,11,0.4)';
|
|
micBtn.style.color = '#f59e0b';
|
|
micBtn.title = 'Start transcription';
|
|
micStatus.textContent = 'Click mic to start';
|
|
micStatus.style.color = '#94a3b8';
|
|
liveIndicator.style.display = 'none';
|
|
stopTimer();
|
|
};
|
|
|
|
recognition.onresult = function(event) {
|
|
var interim = '';
|
|
for (var i = event.resultIndex; i < event.results.length; i++) {
|
|
var transcript = event.results[i][0].transcript;
|
|
if (event.results[i].isFinal) {
|
|
finalTranscript += transcript + ' ';
|
|
} else {
|
|
interim += transcript;
|
|
}
|
|
}
|
|
transcriptArea.innerHTML = finalTranscript +
|
|
(interim ? '<span style="color:#94a3b8">' + interim + '</span>' : '');
|
|
transcriptArea.scrollTop = transcriptArea.scrollHeight;
|
|
};
|
|
|
|
recognition.onerror = function(event) {
|
|
if (event.error === 'not-allowed') {
|
|
micStatus.textContent = 'Microphone access denied';
|
|
micStatus.style.color = '#ef4444';
|
|
}
|
|
};
|
|
})();
|
|
</script>
|
|
|
|
<!-- Features -->
|
|
<section class="rl-section">
|
|
<div class="rl-container">
|
|
<h2 class="rl-heading" style="text-align:center">What rNotes Handles</h2>
|
|
<div class="rl-grid-3">
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">📝</div>
|
|
<h3>Rich Text Notes</h3>
|
|
<p>Write with a full TipTap editor — formatting, code blocks, checklists, and embeds. Dual-format storage keeps Markdown portable.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🎤</div>
|
|
<h3>Voice & Transcription</h3>
|
|
<p>Record voice notes with live transcription via Web Speech API. Drop in audio or video files and get full transcripts — all in the browser.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🏷</div>
|
|
<h3>Tagging & Organization</h3>
|
|
<p>Tag freely, organize into notebooks, and search everything. Filtered views surface the right cards at the right time.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Chrome Extension -->
|
|
<section class="rl-section rl-section--alt" id="extension-download">
|
|
<div class="rl-container">
|
|
<h2 class="rl-heading" style="text-align:center">Chrome Extension</h2>
|
|
<p class="rl-subtext" style="text-align:center">Clip pages, record voice notes, and transcribe — right from the toolbar.</p>
|
|
<div class="rl-grid-2" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:1.5rem;max-width:860px;margin:2rem auto">
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">📋</div>
|
|
<h3>Web Clipper</h3>
|
|
<p>Save any page as a note with one click — article text, selection, or full HTML.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🎤</div>
|
|
<h3>Voice Recording</h3>
|
|
<p>Press <kbd style="background:rgba(255,255,255,0.1);padding:0.1rem 0.4rem;border-radius:4px;font-size:0.8rem">Ctrl+Shift+V</kbd> to start recording and transcribing from any tab.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🔓</div>
|
|
<h3>Article Unlock</h3>
|
|
<p>Bypass soft paywalls by fetching archived versions — read the article, then save it to your notebook.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🔌</div>
|
|
<h3>Offline Transcription</h3>
|
|
<p>Parakeet.js runs entirely in-browser — your audio never leaves the device.</p>
|
|
</div>
|
|
</div>
|
|
<div style="text-align:center;margin-top:1.5rem">
|
|
<a href="/rnotes/extension/download" class="rl-cta-primary" style="display:inline-flex;align-items:center;gap:0.5rem">
|
|
⬇ Download Extension
|
|
</a>
|
|
<p style="margin-top:0.75rem;font-size:0.8rem;color:#64748b">
|
|
Unzip, then load unpacked at <code style="font-size:0.75rem;color:#94a3b8">chrome://extensions</code>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- How It Works -->
|
|
<section class="rl-section">
|
|
<div class="rl-container">
|
|
<h2 class="rl-heading" style="text-align:center">How It Works</h2>
|
|
<div class="rl-grid-4" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1.5rem">
|
|
<div class="rl-step">
|
|
<div class="rl-step__num">1</div>
|
|
<h3>Live Transcribe</h3>
|
|
<p>Speak and watch words appear in real time via the Web Speech API. No uploads, no waiting.</p>
|
|
</div>
|
|
<div class="rl-step">
|
|
<div class="rl-step__num">2</div>
|
|
<h3>Audio & Video</h3>
|
|
<p>Drop files and get full transcripts via Parakeet, running entirely in-browser. Supports MP3, WAV, MP4, and more.</p>
|
|
</div>
|
|
<div class="rl-step">
|
|
<div class="rl-step__num">3</div>
|
|
<h3>Notebooks & Tags</h3>
|
|
<p>Organize transcripts alongside notes, clips, code, and files. Tag, search, and filter across everything.</p>
|
|
</div>
|
|
<div class="rl-step">
|
|
<div class="rl-step__num">4</div>
|
|
<h3>Private & Offline</h3>
|
|
<p>Parakeet.js runs in-browser — audio never leaves your device. Works offline once the model is cached.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Memory Cards -->
|
|
<section class="rl-section rl-section--alt">
|
|
<div class="rl-container">
|
|
<h2 class="rl-heading" style="text-align:center">Memory Cards</h2>
|
|
<p class="rl-subtext" style="text-align:center">
|
|
Every note is a Memory Card — a typed, structured unit of knowledge with hierarchy,
|
|
properties, and attachments. Designed for round-trip interoperability with Logseq.
|
|
</p>
|
|
<div class="rl-grid-3">
|
|
<!-- 7 Card Types -->
|
|
<div class="rl-card">
|
|
<div class="rl-icon-box">🏷</div>
|
|
<h3>7 Card Types</h3>
|
|
<div style="display:flex;flex-wrap:wrap;gap:0.35rem;margin-bottom:0.75rem">
|
|
<span class="rl-badge" style="background:rgba(245,158,11,0.2);color:#f59e0b">note</span>
|
|
<span class="rl-badge" style="background:rgba(59,130,246,0.2);color:#3b82f6">link</span>
|
|
<span class="rl-badge" style="background:rgba(34,197,94,0.2);color:#22c55e">task</span>
|
|
<span class="rl-badge" style="background:rgba(234,179,8,0.2);color:#eab308">idea</span>
|
|
<span class="rl-badge" style="background:rgba(168,85,247,0.2);color:#a855f7">person</span>
|
|
<span class="rl-badge" style="background:rgba(236,72,153,0.2);color:#ec4899">reference</span>
|
|
<span class="rl-badge" style="background:rgba(100,116,139,0.2);color:#94a3b8">file</span>
|
|
</div>
|
|
<p>Each card type has distinct styling and behavior. Typed notes surface in filtered views and canvas visualizations.</p>
|
|
</div>
|
|
|
|
<!-- Hierarchy & Properties -->
|
|
<div class="rl-card">
|
|
<div class="rl-icon-box">📂</div>
|
|
<h3>Hierarchy & Properties</h3>
|
|
<p>
|
|
Nest cards under parents to build knowledge trees. Add structured
|
|
<code style="font-size:0.8rem;color:rgba(245,158,11,0.8)">key:: value</code>
|
|
properties — compatible with Logseq's property syntax.
|
|
</p>
|
|
<div style="margin-top:0.5rem;font-family:monospace;font-size:0.75rem;color:#64748b;line-height:1.7">
|
|
<div><span style="color:#94a3b8">type::</span> idea</div>
|
|
<div><span style="color:#94a3b8">status::</span> doing</div>
|
|
<div><span style="color:#94a3b8">tags::</span> #research, #web3</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Data Source Integrations -->
|
|
<div class="rl-card">
|
|
<div class="rl-icon-box">🔄</div>
|
|
<h3>Import & Export</h3>
|
|
<p>
|
|
Bring your notes from <strong>Logseq</strong>, <strong>Obsidian</strong>,
|
|
<strong>Notion</strong>, and <strong>Google Docs</strong>.
|
|
Export back to any format anytime — your data, your choice.
|
|
</p>
|
|
<div style="display:flex;flex-wrap:wrap;gap:0.35rem;margin-top:0.5rem">
|
|
<span class="rl-badge" style="background:rgba(34,197,94,0.2);color:#22c55e">Logseq</span>
|
|
<span class="rl-badge" style="background:rgba(139,92,246,0.2);color:#8b5cf6">Obsidian</span>
|
|
<span class="rl-badge" style="background:rgba(59,130,246,0.2);color:#3b82f6">Notion</span>
|
|
<span class="rl-badge" style="background:rgba(245,158,11,0.2);color:#f59e0b">Google Docs</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dual Format Storage -->
|
|
<div class="rl-card">
|
|
<div class="rl-icon-box">📄</div>
|
|
<h3>Dual Format Storage</h3>
|
|
<p>
|
|
Every card stores rich TipTap JSON for editing and portable Markdown for search, export, and interoperability.
|
|
Write once, read anywhere.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Structured Attachments -->
|
|
<div class="rl-card">
|
|
<div class="rl-icon-box">📎</div>
|
|
<h3>Structured Attachments</h3>
|
|
<p>
|
|
Attach images, PDFs, audio, and files to any card with roles (primary, preview, supporting) and captions.
|
|
Thumbnails render inline.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- FUN Model -->
|
|
<div class="rl-card">
|
|
<div class="rl-icon-box">❤</div>
|
|
<h3>FUN, Not CRUD</h3>
|
|
<p>
|
|
<span style="color:#f59e0b;font-weight:600">F</span>orget,
|
|
<span style="color:#f59e0b;font-weight:600">U</span>pdate,
|
|
<span style="color:#f59e0b;font-weight:600">N</span>ew —
|
|
nothing is permanently destroyed. Forgotten cards are archived and can be remembered at any time.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Built on Open Source -->
|
|
<section class="rl-section">
|
|
<div class="rl-container">
|
|
<h2 class="rl-heading" style="text-align:center">Built on Open Source</h2>
|
|
<p class="rl-subtext" style="text-align:center">The libraries and tools that power rNotes.</p>
|
|
<div class="rl-grid-4" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1.5rem">
|
|
<div class="rl-card rl-card--center">
|
|
<h3>Automerge</h3>
|
|
<p>Local-first CRDT for conflict-free real-time collaboration. Your notes sync across devices without a central server.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<h3>Web Speech API</h3>
|
|
<p>Browser-native live transcription — speak and watch your words appear in real time.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<h3>Parakeet.js</h3>
|
|
<p>NVIDIA’s in-browser speech recognition. Transcribe audio and video files offline — nothing leaves your device.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<h3>Hono</h3>
|
|
<p>Ultra-fast, lightweight API framework powering the rNotes backend.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Your Data, Protected -->
|
|
<section class="rl-section rl-section--alt">
|
|
<div class="rl-container" style="text-align:center">
|
|
<h2 class="rl-heading">Your Data, Protected</h2>
|
|
<p class="rl-subtext">How rNotes keeps your information safe.</p>
|
|
<div class="rl-grid-3">
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🔒</div>
|
|
<h3>End-to-End Encryption</h3>
|
|
<span class="rl-badge">Coming Soon</span>
|
|
<p>All content encrypted before it leaves your device. Not even the server can read it.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🕵</div>
|
|
<h3>Zero-Knowledge Architecture</h3>
|
|
<span class="rl-badge">Coming Soon</span>
|
|
<p>The server processes your requests without ever seeing your data in the clear.</p>
|
|
</div>
|
|
<div class="rl-card rl-card--center">
|
|
<div class="rl-icon-box">🏠</div>
|
|
<h3>Self-Hosted</h3>
|
|
<p>Run on your own infrastructure. Your server, your rules, your data.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- CTA -->
|
|
<section class="rl-section">
|
|
<div class="rl-container" style="text-align:center">
|
|
<h2 class="rl-heading">(You)rNotes, your thoughts unbound.</h2>
|
|
<p class="rl-subtext">Try the demo or create a space to get started.</p>
|
|
<div class="rl-cta-row">
|
|
<a href="https://demo.rspace.online/rnotes" class="rl-cta-primary">Open Notebook</a>
|
|
<a href="#transcription-demo" class="rl-cta-secondary">Transcribe</a>
|
|
<a href="/create-space" class="rl-cta-secondary">Create a Space</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="rl-back">
|
|
<a href="/">← Back to rSpace</a>
|
|
</div>
|
|
`;
|
|
}
|