style: Improve markdown editor styling and functionality

- Update dark mode button icon and styling
- Add styling for new collection button
- Apply default iframe styles in preview pane
- Adjust vertical divider height in header buttons
- Improve handling of JSX-like attributes in markdown
- Add support for new collection functionality
- Refine file loading logic in view mode
- Improve dark mode toggle icon and integration
- Update UI for edit/view mode toggle button
This commit is contained in:
Mahmoud-Emad
2025-10-26 17:59:48 +03:00
parent f319f29d4c
commit 7a9efd3542
28 changed files with 562 additions and 83 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -0,0 +1,79 @@
**Decentralized Infrastructure Technology for Everyone, Everywhere**
Mycelium is a comprehensive DePIN (Decentralized Physical Infrastructure) system designed to scale to planetary level, capable of providing resilient services with end-to-end encryption, and enabling any machine and human to communicate efficiently over optimal paths.
Mycelium is Compatible with Kubernetes, Docker, VMs, Web2, Web3 and building towards Web4.
## Terminology Clarification
- **Mycelium Tech**: The core technology stack (ZOS, QSS, Mycelium Network)
- **ThreeFold Grid**: The decentralized infrastructure offering built on Mycelium Tech
- **GeoMind**: The commercial tech company operating tier-S/H datacenters with Mycelium
## Why Decentralized Infrastructure Matters
Traditional internet infrastructure is burdened with inefficiencies, risks, and growing dependency on centralization.
### **The Challenges We Face**
- **Centralization Risks**: Digital infrastructure is controlled by a few corporations, compromising autonomy and creating single points of failure.
- **Economic Inefficiency**: Current infrastructure models extract value from local economies, funneling resources to centralized providers.
- **Outdated Protocols**: TCP/IP, the internet's core protocol, was never designed for modern needs like dynamic networks, security, and session management.
- **Geographic Inefficiency**: Over 70% of the world relies on distant infrastructure, making access expensive, unreliable, and dependent on fragile global systems.
- **Limited Access**: Over 50% of the world lacks decent internet access, widening opportunity gaps.
Mycelium addresses these challenges through a complete, integrated technology stack designed from first principles.
## What Mycelium Provides
Mycelium is unique in its ability to deliver an integrated platform covering all three fundamental layers of internet infrastructure:
### **Compute Layer** - ZOS
- Autonomous, stateless operating system
- MyImage architecture (up to 100x faster deployment)
- Deterministic, cryptographically verified deployment
- Supports Kubernetes, containers, VMs, and Linux workloads
- Self-healing with no manual maintenance required
### **Storage Layer** - Quantum Safe Storage (QSS)
- Mathematical encoding with forward error correction
- 20% overhead vs 400% for traditional replication
- Zero-knowledge design: storage nodes can't access data
- Petabyte-to-zetabyte scalability
- Self-healing bitrot protection
### **Network Layer** - Mycelium Network
- End-to-end encrypted IPv6 overlay
- Shortest-path optimization
- Multi-protocol support (TCP, QUIC, UDP, satellite, wireless)
- Peer-to-peer architecture with no central points of failure
- Distributed secure name services
## Key Differentiators
| Feature | Mycelium | Traditional Cloud |
| ------------------------ | -------------------------------------------- | ------------------------------------------ |
| **Architecture** | Distributed peer-to-peer, no central control | Centralized control planes |
| **Deployment** | Stateless network boot, zero-install | Local image installation |
| **Storage Efficiency** | 20% overhead | 300-400% overhead |
| **Security** | End-to-end encrypted, zero-knowledge design | Perimeter-based, trust intermediaries |
| **Energy** | Up to 10x more efficient | Higher consumption |
| **Autonomy** | Self-healing, autonomous agents | Requires active management |
| **Geographic Awareness** | Shortest path routing, location-aware | Static routing, no geographic optimization |
## Current Status
- **Deployed**: 20+ countries, 30,000+ vCPU
- **Proof of Concept**: Technology validated in production
- **Commercialization**: Beginning phase with enterprise roadmap
## Technology Maturity
- **All our core cloud technology**: Production
- **Quantum Safe Storage**: Production (6+ years)
- **Mycelium Network**: Beta
- **Deterministic Deployment**: OEM only
- **FungiStor**: H1 2026
Mycelium represents not just an upgrade to existing infrastructure, but a fundamental rethinking of how internet infrastructure should be built—distributed, autonomous, secure, and efficient.

View File

@@ -0,0 +1,42 @@
## Mycelium Product Presentation
This document provides an overview of the Mycelium technology stack (as commercially sold my our company GeoMind).
<div style={{
position: 'relative',
width: '100%',
height: 0,
paddingTop: '56.25%',
marginTop: '1.6em',
marginBottom: '0.9em',
overflow: 'hidden',
borderRadius: '8px',
willChange: 'transform'
}}>
<iframe
src="https://www.canva.com/design/DAG0UtzICsk/rqXpn5f3ibo2OpX-yDWmPQ/view?embed"
style={{
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
left: 0,
border: 'none',
padding: 0,
margin: 0
}}
allowFullScreen={true}
allow="fullscreen">
</iframe>
</div>
<div style={{ marginTop: '10px' }}>
<a href="https://www.canva.com/design/DAG0UtzICsk/rqXpn5f3ibo2OpX-yDWmPQ/view"
target="_blank"
rel="noopener"
style={{ textDecoration: 'none' }}>
Geomind Product Intro 2025 (based on mycelium technology)
</a>
</div>

View File

@@ -0,0 +1,50 @@
# Government, Commercial Hosters, Telco and Enterprise Roadmap
We are working on the government, commercial hosters, telco and enterprise releases of our technology.
> 90% of the work has been done as part of our base offering but we need additional features for enterprises.
## Enterprise User Interface
The current user interface is designed for an open-source tech audience. For enterprise use, we need a different approach to meet the unique needs of enterprise environments:
- **Private or Hybrid Context**: All operations should be conducted within a private or hybrid cloud context to ensure security and compliance.
- **Enhanced Monitoring**: We need more comprehensive monitoring dashboard screens to provide real-time insights and analytics.
- **Identity Management Integration**: Integration with enterprise-grade Identity Management solutions, such as LDAP, Active Directory, and SSO (Single Sign-On), is essential.
- **Enterprise-Friendly UI**: The user interface needs to be redesigned to be more intuitive and tailored to enterprise users, focusing on usability and efficiency.
- **Token Irrelevance**: Tokens are not a priority in this context and should be de-emphasized in the solution.
## Windows Support
The virtual Machine technology we use does support Windows, but we need to do some further integration.
## High Performance Network Integration
- **Local Network Integration**: ZOS is designed to support a wide range of technologies, though additional integration work is required to optimize performance.
- **High-Speed Backbones**: We aim to support high-speed Ethernet and RDMA (Infiniband) based backbones.
- **Instrumentation Enhancements**: Additional instrumentation needs to be incorporated into ZOS to achieve optimal performance.
- **Target Performance**: Our goal is to achieve network speeds exceeding 100 Gbps.
- **Custom Integration**: We offer integration with selected network equipment from our customers, accommodating custom integration requirements.
## High Performance Storage Block Device Integration
Next to the existing already integrated storage backends we want to support a high performance redundant storage block device.
- High performance redundant storage network
- Supports high-speed backbones as defined above
- Scalable to thousands of machines per cluster.
- Replication capability between zones.
- Custom Integration
- We offer integration with selected storage equipment from our customers, accommodating custom integration requirements.
## Service Level Management
- The system will have hooks and visualization for achievement of Service levels.
- This will allow a commercial service provider to get to higher revenue and better uptime management.
## Support for Liquid Cooling Tanks
- Do a test setup in liquid cooling rack or node.
- We can use our self-healing capabilities to manage in a better way.
- This is an integration effort, and not much code changes are needed.

View File

@@ -0,0 +1,24 @@
## AI Agent High Level Roadmap
MyAgent is our private AI agent.
The first version of our MyAgent enables the management of core services such as an innovative database backend, a autonomous decentralized git system, and the automatic integration and deployment of our workloads.
This stack allows everyone to deploy scalable Web 2,3 and 4 apps on top of the TFGrid in a fully automated way.
| | Roadmap | Timing |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------ |
| MyAgent Publisher | Publish websites, e-books, and more on top of the ThreeFold Grid | H2 25 |
| MyAgent CI = Continuous Integration | Easier to use Continuous Integration/Development, very powerfull, with multinode support | H2 25 |
| MyAgent Play | Integrate declarative automation and configuration management as part of wiki approach in MyAgent Publisher | H2 25 |
| MyAgent Git | Alternative to centralized Github (based on Gitea), fully integrated on top of TFGrid | H2 25 |
| MyAgent DB | Flexible ultra redundant database stor with indexing, queries, stored procedures, super scalable replication | H2 25 |
| MyAgent OSIS | Object Storage and Index system | H2 25 |
| MyAgent WEB | Web framework, deployable globally on TFGrid, integrated with Mycelium Net and Names | H2 25 |
| MyAgent Monitor | Monitor all your different components on redundant monitoring stack | H2 25 |
| MyAgent Happs | MyAgent natively supports Holochain HAPPS | Q4 25 |
| MyAgent Actors | MyAgent can serve actors which respond and act on OpenRPC calls ideal as backend for web or other apps | Q4 25 |
| MyAgent Web 3 Gateway | MyAgent aims to have native support for chosen Web3 partner solutions (Bitcoin, Ethereum, and more) | Q4 25 |
All of the specs above are fully integrated with the Mycelium Network and the ThreeFold Grid.

View File

@@ -0,0 +1,40 @@
![](img/roadmap.jpg)
# Roadmap in Phases
## Phase 1: Wave 1 of Companies, Leading to Our expertise (DONE)
- Technology creation
- This was result of 20 years of evolution
- 7 startups acquired as part of this process
- Technology used globally by big vendors
- +600m USD in exits
## Phase 2: Proof of Tech (DONE)
- Open source technology launched globally
- +60,000,000 active vCPU
- Large scale proof of core technology
- Focus on early adoptors in tech space (Cloud, Web2, Web3, etc.)
- 50m USD funded by founders, community and hosters (people providing capacity)
## Phase 3: Commercialization & Global Expansion (START)
### Phase 3.1: Commercial Partners
- Mycelium Launches with commercial strategic partners
- Telco Operatators
- IT Integrators
- Enterprise roadmap delivered within 6 months
- This is mainly about integration, documentation and UI work
- Together with partners we deliver on the many projects which are in our funnel today, e.g., East Africa, Brazil
### Phase 3.2: Large Scale Financancing for Infrastructure
**Large Scaling Financing Round**
- Financing for infrastructure projects (trillions available right now for infrastructures in emerging countries)
- Public STO (security token offering)
- This lets people around the world to co-own the infrastructure for their internet
- Large partnerships drive alternative to Tier 3 and 4 datacenters

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -0,0 +1,50 @@
## High Level Roadmap
### Status Today
The core offering is functioning effectively, maintained through a community-driven, best-effort approach. Currently,
there are no Service Level Agreements (SLAs) in place, and there should be increased visibility for users regarding their expectations for uptime, performance, and other service related requirements.
The uptime and stability of ZOS are very good.
Additionally, hardware compatibility is excellent, with most machines now supported out of the box.
| | Status today | SDK/API | Web UI |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------- | ------ |
| ZOS | Used for management of +30,000 logical CPU cores | yes | yes |
| MyImage (flists) | Basis for ZOS modules as well as replaces images for VM's ... | yes | yes |
| MyImage from Docker | convert docker through our Hub | yes | yes |
| MyImage Hub | Mycelium is hosting some as well as everyone can install their own Hub | yes | yes |
| Mycelium Core | Integrated in ZOS for VM's as well s ZDB and monitoring | yes | yes |
| Mycelium Message Bus | Can be used by any developer for their own usecases | NA | NA |
| Quantum Safe Storage | Usable for experts only, is reliably working for +6 years, +100 MB/sec per stream | yes | no |
| Unbreakable Filesystem | Quantum Safe FS= usable for experts, is a fuse based filesystem on top of the QSS Core | yes | no |
| ZOS Kubernetes | Working very well, Integrated in ZOS, uses our overlay networks based on Wireguard, can use Quantum Safe FS underneith. | yes | yes |
| ZOS VM's | The base of our service portfolio, missing is better service level management | yes | yes |
| ZOS Monitoring | Working well | yes | yes |
| ZOS VM Monitoring | Working well, can be retrieved through SDK | yes | yes |
| ZOS Web Gateway | Working well, but documentation not good enough, and not enough of them deployed | yes | yes |
| Zero-Boot | There are multiple ways active on how to deploy ZOS all are stateless and capable for full secure boot | yes | yes |
### Planned new features
Considerable effort is being made to enable our partners to go into production;
however, for this initiative to truly succeed on planetary level, we need many more nodes deployed in the field.
Below you can find some of the planned features of Mycelium Network 4.0 mainly to achieve ability to scale to hundred of thousand of nodes.
| | Roadmap | Timing |
| ------------------------------- | ------------------------------------------------------------------- | ------- |
| ZOS v4 (our next major release) | V4, without Mycelium Chain, mutual credit, marketplace | Q2/3 25 |
| MyImage from Docker | CI/CD integration (See MyAgent CI/CD) | Q1 25 |
| MyImage Hub Integration | CI/CD integration (See MyAgent CI/CD) no more need for separate Hub | Q1 25 |
| Mycelium Core | Just more hardening and testing | Q1 25 |
| Mycelium Message Bus | Replace our current RMB, all our own RPC over Mycelium | Q1 25 |
| ZOS VM's Cloud Slices | Integration MyAgent CI, use cloud slices to manage | Q2 25 |
| ZOS Monitoring Docu | More docu and easier API | Q2 25 |
| ZOS Web Gateway Expansion | Need more deployed, better integration with new Mycelium | Q2 25 |
| Mycelium Names | In V4, name services | Q2 25 |
| ZOS Cloud,Storage,AI Slices | As part of marketplace for V4, flexible billing mutual credit | Q3 25 |
| FungiStor | A revolutionary different way how to deliver content | Q3 25 |
| MyImage on FungiStor | Can be stored on FungiStor | Q3 25 |

View File

@@ -0,0 +1,21 @@
## Technology Status
![](images/status.png)
The Mycelium technology stack is proven and operational in production environments globally.
Ongoing deployment and enhancement activities continue across the platform, with expanding adoption and application scope.
![](images/dashboard.png)
## Usable for Any Infrastructure Use Case
![](images/usable_by_all.png)
Mycelium is designed to support any infrastructure workload - from traditional cloud applications to edge computing, AI services, and decentralized applications.
## Differentiated Architecture
![](images/unique.png)
Mycelium's unique value lies in its integrated approach: autonomous infrastructure, deterministic deployment, zero-knowledge storage, and optimized networking - delivered as a cohesive platform rather than point solutions.

View File

@@ -0,0 +1,21 @@
![](images/opportunity.png)
## Vision
Building the foundational internet infrastructure layer that is more reliable, safe, private, scalable, and sustainable.
Our technology enables anyone to become an infrastructure provider while maintaining autonomous, self-healing services covering all three fundamental layers of internet architecture.
Our system is unique in its ability to deliver integrated services across compute (ZOS), storage (Quantum Safe Storage), and networking (Mycelium Network) within a single, coherent platform.
## Lets Fix Our Internet
![alt text](images/letsfix.png)
**We are a grounded project:**
- Already deployed in 30+ countries with 30,000+ vCPUs live
- Proven technology in production for multiple years
- Complete stack: OS, storage, networking, AI agents
- Focused on building and proving technology
- Commercial phase launching with enterprise roadmap

43
collections/tech/what.md Normal file
View File

@@ -0,0 +1,43 @@
## What do we do?
![alt text](images/arch.png)
A truly reliable Internet requires fundamentally better systems for networking (communication), storage (data), and compute.
Mycelium has built these core technologies from the ground up, enabling anyone to become an infrastructure provider while maintaining autonomous, self-healing services covering all three fundamental layers of internet architecture.
### Authentic, Secure & Globally Scalable Network Technology
- Our Mycelium Network technology enables seamless, private communication between people and machines, anywhere in the world, using the most efficient path available.
- It integrates with a global edge network of ultra-connected, low-latency supernodes to deliver superior performance and resilience.
- Mycelium is designed to overcome the limitations of the traditional Internet, such as unreliability, poor performance, and security risks.
- It provides core services including Naming, Shortest Path Routing, End-to-End Encryption, Authentication, a Secure Message Bus, and Content Delivery.
### Data Storage & Distribution
- Our Quantum-Safe Storage system enables users to store unlimited amounts of data with full ownership and control.
- As soon as data leaves the application or compute layer, it is encoded in a way that is resistant even to quantum-level attacks.
- Users have full control over data availability, redundancy, and geographic placement.
- The system supports multiple interfaces, including IPFS, S3, WebDAV, HTTP, and standard file system access.
- Data can never be corrupted, and the storage system is self-healing by design.
### Secure Compute
- Self-Managing & Stateless: Requires no manual interactions, enabling fully autonomous operation across global infrastructure.
- Secure & Deterministic Deployments: Every workload is cryptographically verified and deployed with guaranteed consistency—no room for tampering or drift.
- Efficient Deployment Storage System (Zero-Image): Achieves up to 100x reduction in image size and transfer using a unique metadata-driven architecture.
- Compatible: Runs Docker containers, virtual machines, and Linux workloads seamlessly.
- Smart Contract-Based Deployment: Workloads are governed by cryptographically signed contracts, ensuring transparent, tamper-proof deployment and execution.
## Compare
| Feature | Others | Mycelium Tech |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------- |
| Deterministic Deployments Possible, no one (hacker) can alter state. | NO | YES |
| Autonomous/Self Healing Infrastructure which can scale to the planet. | NO | YES |
| Usable for any web2, web3 workload, compatible with now & future. | NO | YES |
| Data is geo-aware, war & disaster proof. | NO | YES |
| Can work in hyperscale datacenters as well as at edge. | NO | YES |
| Cost effective, can be 3x less | NO | YES |
| Networks can always find the shortest path and work over multiple media e.g. satellite, std internet, meshed wireless, lorawan, etc all end to end encrypted. | NO | YES |

View File

@@ -23,6 +23,9 @@ collections:
7madah:
path: collections/7madah
description: 'User-created collection: 7madah'
tech:
path: collections/tech
description: 'User-created collection: tech'
server:
host: localhost
port: 8004

View File

@@ -24,7 +24,7 @@
function enableDarkMode() {
isDarkMode = true;
document.body.classList.add('dark-mode');
document.getElementById('darkModeIcon').textContent = '☀️';
document.getElementById('darkModeIcon').innerHTML = '<i class="bi bi-sun-fill"></i>';
localStorage.setItem('darkMode', 'true');
mermaid.initialize({
@@ -41,7 +41,7 @@
function disableDarkMode() {
isDarkMode = false;
document.body.classList.remove('dark-mode');
document.getElementById('darkModeIcon').textContent = '🌙';
// document.getElementById('darkModeIcon').textContent = '🌙';
localStorage.setItem('darkMode', 'false');
mermaid.initialize({

View File

@@ -1,5 +1,5 @@
// Markdown Editor Application
(function() {
(function () {
'use strict';
// State management
@@ -21,16 +21,16 @@
function enableDarkMode() {
isDarkMode = true;
document.body.classList.add('dark-mode');
document.getElementById('darkModeIcon').textContent = '☀️';
document.getElementById('darkModeIcon').innerHTML = '<i class="bi bi-sun-fill"></i>';
localStorage.setItem('darkMode', 'true');
// Update mermaid theme
mermaid.initialize({
mermaid.initialize({
startOnLoad: false,
theme: 'dark',
securityLevel: 'loose'
});
// Re-render preview if there's content
if (editor && editor.getValue()) {
updatePreview();
@@ -40,16 +40,16 @@
function disableDarkMode() {
isDarkMode = false;
document.body.classList.remove('dark-mode');
document.getElementById('darkModeIcon').textContent = '🌙';
// document.getElementById('darkModeIcon').textContent = '🌙';
localStorage.setItem('darkMode', 'false');
// Update mermaid theme
mermaid.initialize({
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// Re-render preview if there's content
if (editor && editor.getValue()) {
updatePreview();
@@ -65,7 +65,7 @@
}
// Initialize Mermaid
mermaid.initialize({
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
@@ -87,15 +87,15 @@
async function uploadImage(file) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('/api/upload-image', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error('Upload failed');
const result = await response.json();
return result.url;
} catch (error) {
@@ -108,48 +108,48 @@
// Handle drag and drop
function setupDragAndDrop() {
const editorElement = document.querySelector('.CodeMirror');
// Prevent default drag behavior
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
editorElement.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// Highlight drop zone
['dragenter', 'dragover'].forEach(eventName => {
editorElement.addEventListener(eventName, () => {
editorElement.classList.add('drag-over');
}, false);
});
['dragleave', 'drop'].forEach(eventName => {
editorElement.addEventListener(eventName, () => {
editorElement.classList.remove('drag-over');
}, false);
});
// Handle drop
editorElement.addEventListener('drop', async (e) => {
const files = e.dataTransfer.files;
if (files.length === 0) return;
// Filter for images only
const imageFiles = Array.from(files).filter(file =>
const imageFiles = Array.from(files).filter(file =>
file.type.startsWith('image/')
);
if (imageFiles.length === 0) {
showNotification('Please drop image files only', 'warning');
return;
}
showNotification(`Uploading ${imageFiles.length} image(s)...`, 'info');
// Upload images
for (const file of imageFiles) {
const url = await uploadImage(file);
@@ -163,12 +163,12 @@
}
}
}, false);
// Also handle paste events for images
editorElement.addEventListener('paste', async (e) => {
const items = e.clipboardData?.items;
if (!items) return;
for (const item of items) {
if (item.type.startsWith('image/')) {
e.preventDefault();
@@ -198,17 +198,17 @@
lineWrapping: true,
autofocus: true,
extraKeys: {
'Ctrl-S': function() { saveFile(); },
'Cmd-S': function() { saveFile(); }
'Ctrl-S': function () { saveFile(); },
'Cmd-S': function () { saveFile(); }
}
});
// Update preview on change
editor.on('change', debounce(updatePreview, 300));
// Setup drag and drop after editor is ready
setTimeout(setupDragAndDrop, 100);
// Sync scroll
editor.on('scroll', handleEditorScroll);
}
@@ -230,7 +230,7 @@
async function updatePreview() {
const content = editor.getValue();
const previewDiv = document.getElementById('preview');
if (!content.trim()) {
previewDiv.innerHTML = `
<div class="text-muted text-center mt-5">
@@ -244,15 +244,15 @@
try {
// Parse markdown to HTML
let html = marked.parse(content);
// Replace mermaid code blocks with div containers
html = html.replace(
/<pre><code class="language-mermaid">([\s\S]*?)<\/code><\/pre>/g,
'<div class="mermaid">$1</div>'
);
previewDiv.innerHTML = html;
// Apply syntax highlighting to code blocks
const codeBlocks = previewDiv.querySelectorAll('pre code');
codeBlocks.forEach(block => {
@@ -262,7 +262,7 @@
Prism.highlightElement(block);
}
});
// Render mermaid diagrams
const mermaidElements = previewDiv.querySelectorAll('.mermaid');
if (mermaidElements.length > 0) {
@@ -288,15 +288,15 @@
// Handle editor scroll for synchronized scrolling
function handleEditorScroll() {
if (!isScrollingSynced) return;
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
const editorScrollInfo = editor.getScrollInfo();
const editorScrollPercentage = editorScrollInfo.top / (editorScrollInfo.height - editorScrollInfo.clientHeight);
const previewPane = document.querySelector('.preview-pane');
const previewScrollHeight = previewPane.scrollHeight - previewPane.clientHeight;
if (previewScrollHeight > 0) {
previewPane.scrollTop = editorScrollPercentage * previewScrollHeight;
}
@@ -308,22 +308,22 @@
try {
const response = await fetch('/api/files');
if (!response.ok) throw new Error('Failed to load file list');
const files = await response.json();
const fileListDiv = document.getElementById('fileList');
if (files.length === 0) {
fileListDiv.innerHTML = '<div class="text-muted p-2 small">No files yet</div>';
return;
}
fileListDiv.innerHTML = files.map(file => `
<a href="#" class="list-group-item list-group-item-action file-item" data-filename="${file.filename}">
<span class="file-name">${file.filename}</span>
<span class="file-size">${formatFileSize(file.size)}</span>
</a>
`).join('');
// Add click handlers
document.querySelectorAll('.file-item').forEach(item => {
item.addEventListener('click', (e) => {
@@ -343,19 +343,19 @@
try {
const response = await fetch(`/api/files/${filename}`);
if (!response.ok) throw new Error('Failed to load file');
const data = await response.json();
currentFile = data.filename;
// Update UI
document.getElementById('filenameInput').value = data.filename;
editor.setValue(data.content);
// Update active state in file list
document.querySelectorAll('.file-item').forEach(item => {
item.classList.toggle('active', item.dataset.filename === filename);
});
updatePreview();
showNotification(`Loaded ${filename}`, 'success');
} catch (error) {
@@ -367,14 +367,14 @@
// Save current file
async function saveFile() {
const filename = document.getElementById('filenameInput').value.trim();
if (!filename) {
showNotification('Please enter a filename', 'warning');
return;
}
const content = editor.getValue();
try {
const response = await fetch('/api/files', {
method: 'POST',
@@ -383,12 +383,12 @@
},
body: JSON.stringify({ filename, content })
});
if (!response.ok) throw new Error('Failed to save file');
const result = await response.json();
currentFile = result.filename;
showNotification(`Saved ${result.filename}`, 'success');
loadFileList();
} catch (error) {
@@ -400,31 +400,31 @@
// Delete current file
async function deleteFile() {
const filename = document.getElementById('filenameInput').value.trim();
if (!filename) {
showNotification('No file selected', 'warning');
return;
}
if (!confirm(`Are you sure you want to delete ${filename}?`)) {
return;
}
try {
const response = await fetch(`/api/files/${filename}`, {
method: 'DELETE'
});
if (!response.ok) throw new Error('Failed to delete file');
showNotification(`Deleted ${filename}`, 'success');
// Clear editor
currentFile = null;
document.getElementById('filenameInput').value = '';
editor.setValue('');
updatePreview();
loadFileList();
} catch (error) {
console.error('Error deleting file:', error);
@@ -438,12 +438,12 @@
document.getElementById('filenameInput').value = '';
editor.setValue('');
updatePreview();
// Remove active state from all file items
document.querySelectorAll('.file-item').forEach(item => {
item.classList.remove('active');
});
showNotification('New file created', 'info');
}
@@ -460,25 +460,25 @@
function showNotification(message, type = 'info') {
// Create toast notification
const toastContainer = document.getElementById('toastContainer') || createToastContainer();
const toast = document.createElement('div');
toast.className = `toast align-items-center text-white bg-${type} border-0`;
toast.setAttribute('role', 'alert');
toast.setAttribute('aria-live', 'assertive');
toast.setAttribute('aria-atomic', 'true');
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">${message}</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toast);
const bsToast = new bootstrap.Toast(toast, { delay: 3000 });
bsToast.show();
toast.addEventListener('hidden.bs.toast', () => {
toast.remove();
});
@@ -499,13 +499,13 @@
initDarkMode();
initEditor();
loadFileList();
// Set up event listeners
document.getElementById('saveBtn').addEventListener('click', saveFile);
document.getElementById('deleteBtn').addEventListener('click', deleteFile);
document.getElementById('newFileBtn').addEventListener('click', newFile);
document.getElementById('darkModeToggle').addEventListener('click', toggleDarkMode);
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
@@ -513,7 +513,7 @@
saveFile();
}
});
console.log('Markdown Editor initialized');
}

View File

@@ -364,4 +364,28 @@ body.dark-mode .btn-flat-danger {
body.dark-mode .btn-flat-warning {
color: #ffda6a;
}
/* Dark Mode Button Icon Styles */
#darkModeBtn i {
font-size: 16px;
color: inherit;
/* Inherit color from parent button */
}
/* Light mode: moon icon */
body:not(.dark-mode) #darkModeBtn i {
color: var(--text-secondary);
}
/* Dark mode: sun icon */
body.dark-mode #darkModeBtn i {
color: #ffc107;
/* Warm sun color */
}
/* Hover effects */
#darkModeBtn:hover i {
color: inherit;
/* Inherit hover color from parent */
}

View File

@@ -240,4 +240,14 @@ body.dark-mode .tree-empty-message {
.sidebar::-webkit-scrollbar-thumb:hover {
background-color: var(--text-secondary);
}
.new-collection-btn {
padding: 0.375rem 0.75rem;
font-size: 1rem;
border-radius: 0.25rem;
transition: all 0.2s ease;
color: var(--text-primary);
border: 1px solid var(--border-color);
background-color: transparent;
}

View File

@@ -232,6 +232,14 @@ body {
margin-top: 0;
}
/* Iframe styles in preview - minimal defaults that can be overridden */
#preview iframe {
border: none;
/* Default to no border, can be overridden by inline styles */
display: block;
/* Prevent inline spacing issues */
}
/* View Mode Styles */
body.view-mode #editorPane {
display: none;

View File

@@ -33,9 +33,14 @@ async function autoLoadPageInViewMode() {
// If we found a page to load, load it
if (pageToLoad) {
await editor.loadFile(pageToLoad);
// Highlight the file in the tree and expand parent directories
fileTree.selectAndExpandPath(pageToLoad);
// Use fileTree.onFileSelect to handle both text and binary files
if (fileTree.onFileSelect) {
fileTree.onFileSelect({ path: pageToLoad, isDirectory: false });
} else {
// Fallback to direct loading (for text files only)
await editor.loadFile(pageToLoad);
fileTree.selectAndExpandPath(pageToLoad);
}
} else {
// No files found, show empty state message
editor.previewElement.innerHTML = `
@@ -397,6 +402,9 @@ document.addEventListener('DOMContentLoaded', async () => {
// Highlight the file in the tree
fileTree.selectAndExpandPath(item.path);
// Save as last viewed page (for binary files too)
editor.saveLastViewedPage(item.path);
// Update URL to reflect current file
updateURL(currentCollection, item.path, isEditMode);

View File

@@ -16,7 +16,7 @@ class DarkMode {
this.isDark = !this.isDark;
localStorage.setItem(Config.STORAGE_KEYS.DARK_MODE, this.isDark);
this.apply();
Logger.debug(`Dark mode ${this.isDark ? 'enabled' : 'disabled'}`);
}
@@ -27,7 +27,7 @@ class DarkMode {
if (this.isDark) {
document.body.classList.add('dark-mode');
const btn = document.getElementById('darkModeBtn');
if (btn) btn.textContent = '☀️';
if (btn) btn.innerHTML = '<i class="bi bi-sun-fill"></i>';
// Update mermaid theme
if (window.mermaid) {
@@ -36,7 +36,7 @@ class DarkMode {
} else {
document.body.classList.remove('dark-mode');
const btn = document.getElementById('darkModeBtn');
if (btn) btn.textContent = '🌙';
if (btn) btn.innerHTML = '<i class="bi bi-moon-fill"></i>';
// Update mermaid theme
if (window.mermaid) {

View File

@@ -336,6 +336,60 @@ class MarkdownEditor {
}
}
/**
* Convert JSX-style attributes to HTML attributes
* Handles style={{...}} and boolean attributes like allowFullScreen={true}
*/
convertJSXToHTML(content) {
Logger.debug('Converting JSX to HTML...');
// Convert style={{...}} to style="..."
// This regex finds style={{...}} and converts the object notation to CSS string
content = content.replace(/style=\{\{([^}]+)\}\}/g, (match, styleContent) => {
Logger.debug(`Found JSX style: ${match}`);
// Parse the object-like syntax and convert to CSS
const cssRules = styleContent
.split(',')
.map(rule => {
const colonIndex = rule.indexOf(':');
if (colonIndex === -1) return '';
const key = rule.substring(0, colonIndex).trim();
const value = rule.substring(colonIndex + 1).trim();
if (!key || !value) return '';
// Convert camelCase to kebab-case (e.g., paddingTop -> padding-top)
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
// Remove quotes from value
let cssValue = value.replace(/^['"]|['"]$/g, '');
return `${cssKey}: ${cssValue}`;
})
.filter(rule => rule)
.join('; ');
Logger.debug(`Converted to CSS: style="${cssRules}"`);
return `style="${cssRules}"`;
});
// Convert boolean attributes like allowFullScreen={true} to allowfullscreen
content = content.replace(/(\w+)=\{true\}/g, (match, attrName) => {
Logger.debug(`Found boolean attribute: ${match}`);
// Convert camelCase to lowercase for HTML attributes
const htmlAttr = attrName.toLowerCase();
Logger.debug(`Converted to: ${htmlAttr}`);
return htmlAttr;
});
// Remove attributes set to {false}
content = content.replace(/\s+\w+=\{false\}/g, '');
return content;
}
/**
* Render preview from markdown content
* Can be called with explicit content (for view mode) or from editor (for edit mode)
@@ -355,11 +409,12 @@ class MarkdownEditor {
}
try {
// Step 1: Process macros
let processedContent = markdown;
// Step 0: Convert JSX-style syntax to HTML
let processedContent = this.convertJSXToHTML(markdown);
// Step 1: Process macros
if (this.macroProcessor) {
const processingResult = await this.macroProcessor.processMacros(markdown);
const processingResult = await this.macroProcessor.processMacros(processedContent);
processedContent = processingResult.content;
}

View File

@@ -38,7 +38,7 @@
<!-- Right: All Buttons -->
<div class="ms-auto d-flex gap-2 align-items-center">
<!-- View Mode Button -->
<button id="editModeBtn" class="btn-flat btn-flat-warning" style="display: none;">
<button id="editModeBtn" class="btn-flat btn-flat" style="display: none;">
<i class="bi bi-pencil-square"></i> Edit this file
</button>
@@ -57,7 +57,7 @@
</button>
<!-- Divider -->
<div class="vr" style="height: 24px;"></div>
<div class="vr" style="height: 40px;"></div>
<!-- Dark Mode Toggle -->
<button id="darkModeBtn" class="btn-flat btn-flat-secondary">
@@ -77,7 +77,8 @@
<label class="form-label small">Collection:</label>
<div class="d-flex gap-1">
<select id="collectionSelect" class="form-select form-select-sm flex-grow-1"></select>
<button id="newCollectionBtn" class="btn btn-success btn-sm" title="Create New Collection">
<button id="newCollectionBtn" class="btn btn-sm new-collection-btn"
title="Create New Collection">
<i class="bi bi-plus-lg"></i>
</button>
</div>