bug: fixed slow syntax higlighting & readme fixed

This commit is contained in:
Asad 2025-01-18 12:20:03 -05:00
parent c70da27183
commit 8a2b45099a
5 changed files with 115 additions and 51 deletions

@ -1,37 +1,36 @@
# [BinCode](jsbin.asadk.dev) - A Complete Self-Hostable JSFiddle Alternative
## Overview
BinCode is a minimalist platform for managing and sharing code snippets, built with Vue.js and SQLite. Unlike similar tools that depend on external services, BinCode runs entirely on your own infrastructure, giving you complete control over your data and workflow.
BinCode is a minimalist platform for managing and sharing code snippets, built with Vue.js and SQLite. It runs entirely on your own infrastructure, giving you full control over your data and workflow.
## Key Features
- **Fully Self-Contained:** No external dependencies or services required
- **Modern Stack:** Built with Vue.js frontend and SQLite database
- **Secure Authentication:** Simple JWT-based user management
- **Instant Sharing:** Generate unique URLs for any code snippet
- **Minimal Setup:** Just create users manually and start sharing code
- **Performance Focused:** Lightweight design ensures fast operation
- **Self-Contained:** No external dependencies required.
- **Modern Stack:** Vue.js frontend and SQLite database.
- **JWT Authentication:** Secure, simple user management.
- **Instant Sharing:** Generate unique URLs for snippets.
- **Minimal Setup:** Create users manually to start sharing.
- **Performance-Focused:** Lightweight and fast.
## Architecture
- Frontend: Vue.js
- Database: SQLite
- Authentication: JWT
- Deployment: Single server, self-contained
- **Frontend:** Vue.js
- **Database:** SQLite
- **Authentication:** JWT
- **Deployment:** Single self-contained server.
There is no signups its by design just create users manullay and they can start commits snippets to share
## Why BinCode?
During my search for open-source code sharing solutions, I found that most platforms required external services or had complex deployment requirements. I needed a straightforward, self-hostable tool that focused solely on creating and sharing code snippets.
BinCode was built with simplicity in mind. While it may not have all the features of larger platforms, its lightweight nature makes it perfect for teams and individuals who need a reliable, easy-to-maintain solution for code sharing.
BinCode is a lightweight, self-hostable tool for teams and individuals needing a simple, reliable solution for code sharing without relying on external services.
## Design Choices
- **No Signups:** User accounts are created manually by administrators to keep the system simple and secure
- **Self-Contained:** Everything runs on your infrastructure, ensuring data privacy and control
- **No Signups:** Admins manually create user accounts for simplicity and security.
- **Self-Hosted:** Ensures privacy and control over your data.
## Contributing
While BinCode is intentionally minimal, contributions are always welcome! Feel free to add features that enhance its functionality while maintaining its lightweight nature.
Contributions are welcome, as long as the tool remains lightweight and self-contained.
## Getting Started

@ -26,9 +26,13 @@ createApp({
// Tab state
activeTab: 'html',
tabs: [
{ id: 'html', label: 'HTML', icon: '📄', language: 'markup' },
{ id: 'css', label: 'CSS', icon: '🎨', language: 'css' },
{ id: 'js', label: 'JavaScript', icon: '⚡', language: 'javascript' }
{ id: 'html', label: 'HTML', icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="#E65100" d="m4 4 2 22 10 2 10-2 2-22Zm19.72 7H11.28l.29 3h11.86l-.802 9.335L15.99 25l-6.635-1.646L8.93 19h3.02l.19 2 3.86.77 3.84-.77.29-4H8.84L8 8h16Z"/></svg>', language: 'markup' },
{ id: 'css', label: 'CSS', icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill="#42a5f5" d="m29.18 4-3.57 18.36-.33 1.64-4.74 1.57-3.28 1.09L13.21 28 2.87 24.05 4.05 18h4.2l-.44 2.85 6.34 2.42.78-.26 6.52-2.16.17-.83.79-4.02H4.44l.74-3.76.05-.24h17.96l.78-4H6l.78-4z"/></svg>', language: 'css' },
{ id: 'js', label: 'JavaScript', icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#ffca28" d="M2 2h12v12H2zm3.153 10.027c.267.567.794 1.033 1.694 1.033 1 0 1.686-.533 1.686-1.7V7.507H7.4v3.827c0 .573-.233.72-.6.72-.387 0-.547-.267-.727-.58zm3.987-.12c.333.653 1.007 1.153 2.06 1.153 1.067 0 1.867-.553 1.867-1.573 0-.94-.54-1.36-1.5-1.773l-.28-.12c-.487-.207-.694-.347-.694-.68 0-.274.207-.487.54-.487.32 0 .534.14.727.487l.873-.58c-.366-.64-.886-.887-1.6-.887-1.006 0-1.653.64-1.653 1.487 0 .92.54 1.353 1.353 1.7l.28.12c.52.226.827.366.827.753 0 .32-.3.553-.767.553-.553 0-.873-.286-1.113-.686z"/></svg>', language: 'javascript' }
],
extraIcons: [
{ visible: `<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"/></svg>`},
{ hidden: `<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z"/></svg>`}
],
highlightedCode: {
html: '',
@ -41,6 +45,13 @@ createApp({
},
computed: {
displayCode() {
return {
html: this.highlightedCode.html || this.html,
css: this.highlightedCode.css || this.css,
js: this.highlightedCode.js || this.js
};
},
currentCode: {
get() {
return this[this.activeTab];
@ -77,7 +88,8 @@ createApp({
},
created() {
this.updatePreviewDebounced = this.debounce(this.updatePreview, 300);
this.highlightCodeDebounced = this.debounce(this.highlightCode, 50);
this.updatePreviewDebounced = this.debounce(this.updatePreview, 50);
const urlParams = new URLSearchParams(window.location.search);
const shareId = urlParams.get('share');
if (shareId) {
@ -121,17 +133,20 @@ createApp({
const language = languageMap[tab];
if (!language) return;
try {
this.highlightedCode[tab] = Prism.highlight(
code || '',
Prism.languages[language],
language
);
} catch (error) {
console.error('Highlighting error:', error);
this.highlightedCode[tab] = code || '';
}
// run highlighting in a requestAnimationFrame to avoid blocking the main thread
requestAnimationFrame(() => {
try {
this.highlightedCode[tab] = Prism.highlight(
code || '',
Prism.languages[language],
language
);
} catch (error) {
console.error('Highlighting error:', error);
this.highlightedCode[tab] = code || '';
}
});
},
handleKeydown(event) {
if (event.key === 'Tab') {

@ -15,13 +15,15 @@
<div class="title-input" v-if="token">
<input type="text" v-model="title" placeholder="Snippet title" />
</div>
<div>
<div class="toggle-container">
<button class="toggle-icon" @click="toggleEditor">
{{ showEditor ? '🙈 editor': '👀 editor'}}
<span v-html="showEditor ? extraIcons[0].visible : extraIcons[1].hidden"></span>
<span>editor</span>
</button>
<button class="toggle-icon" @click="togglePreview">
{{ showPreview ? '🙈 preview' : '👀 preview' }}
<span v-html="showPreview ? extraIcons[0].visible : extraIcons[1].hidden"></span>
<span>preview</span>
</button>
</div>
<div class="nav-actions">
@ -50,11 +52,8 @@
:class="{ active: activeTab === tab.id }"
@click="switchTab(tab.id)"
>
<span class="tab-icon">{{ tab.icon }}</span>
<svg class="tab-icon" v-html="tab.icon"></svg>
{{ tab.label }}
<kbd v-if="tab.id === 'html'">⌘1</kbd>
<kbd v-if="tab.id === 'css'">⌘2</kbd>
<kbd v-if="tab.id === 'js'">⌘3</kbd>
</button>
</div>

@ -11,6 +11,32 @@
--tab-active: #ffffff;
--danger: #d73a49;
--success: #28a745;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-webkit-scrollbar-track {
background: var(--background);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: var(--text-light);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(#cacaca);
}
::-webkit-scrollbar-thumb:window-inactive {
background: var(--primary-light);
}
* {
@ -37,7 +63,7 @@ body {
nav {
background: var(--tab-bg);
border-bottom: 1px solid var(--border);
padding: 0.75rem 1rem;
padding: 0.20rem 1rem;
display: flex;
align-items: center;
gap: 1rem;
@ -136,7 +162,8 @@ nav {
}
.tab-icon {
font-size: 1.1em;
height: 18px;
width: 18px;
line-height: 1;
}
@ -450,7 +477,7 @@ form > button {
display: flex;
flex-direction: column;
background: var(--background);
transition: all 0.3s ease;
transition: all 0.2s ease;
width: 100%;
}
@ -485,15 +512,38 @@ form > button {
margin-left: 10px;
}
.toggle-container {
display: flex;
flex-direction: row;
}
.toggle-icon {
background: transparent;
border-width: 1px;
border:rgba(0, 0, 0, 0.02);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 8px;
background: none;
border: none;
cursor: pointer;
font-size: 1rem;
padding: 5px 10px;
color: #555;
transition: color 0.3s;
padding: 8px;
font-size: 14px;
color: #5f6368;
}
.toggle-icon span,
.toggle-icon svg {
display: inline-flex;
align-items: center;
}
.toggle-icon svg {
width: 15px;
height: 15px;
}
.toggle-label {
margin-left: 4px;
}
.toggle-icon:hover {
@ -501,6 +551,7 @@ form > button {
}
/* Responsive */
@media (max-width: 768px) {
.user-menu {

@ -10,7 +10,7 @@ app.set('trust proxy', true);
app.use(rateLimit({
windowMs: 5 * 60 * 1000, // 5min
max: 100, // 100 request per IP
max: 1000000, // 100 request per IP
}));
app.use(express.json());