Skip to content

Commit

Permalink
Enjoy!
Browse files Browse the repository at this point in the history
The start of a WYSIWYG editor for Bootstrap 5.3 with vanilla JavaScript, no jQuery required!
  • Loading branch information
Yohn authored Nov 20, 2024
1 parent f6353fa commit be32808
Show file tree
Hide file tree
Showing 5 changed files with 589 additions and 0 deletions.
95 changes: 95 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vanilla WYSIWYG Editor</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid mt-5">
<div class="row-fluid">
<div class="col-lg-10 mx-auto">
<div class="card">
<div class="card-header">
<h2>Bootstrap 5.3.3 WYSIWYG, No JQuery</h2>
</div>
<ul id="toolbar" class="list-group list-group-flush">
<li class="list-group-item">
<div class="btn-toolbar justify-content-between">
<select id="headingSelect" class="form-select" style="width:auto;">
<option value="">Paragraph</option>
<option value="h1">Heading 1</option>
<option value="h2">Heading 2</option>
<option value="h3">Heading 3</option>
<option value="h4">Heading 4</option>
<option value="h5">Heading 5</option>
<option value="h6">Heading 6</option>
</select>
<select id="fontFamilySelect" class="form-select" style="width:auto;">
<option value="" disabled>Font Family</option>
</select>
<select id="fontSizeSelect" class="form-select" style="width:auto;">
<option value="" disabled>Font Size</option>
</select>
<button class="btn btn-outline-secondary" data-command="toggleSource" title="Toggle Source"><i class="bi bi-code-slash"></i></button>
</div>
</li>
<li class="list-group-item">
<div class="btn-toolbar justify-content-between">
<div class="btn-group">
<button class="btn btn-outline-secondary" data-command="bold" title="Bold"><i class="bi bi-type-bold"></i></button>
<button class="btn btn-outline-secondary" data-command="italic" title="Italic"><i class="bi bi-type-italic"></i></button>
<button class="btn btn-outline-secondary" data-command="underline" title="Underline"><i class="bi bi-type-underline"></i></button>
</div>
<div class="btn-group">
<button class="btn btn-outline-secondary" data-command="justifyLeft" title="Align Left"><i class="bi bi-text-left"></i></button>
<button class="btn btn-outline-secondary" data-command="justifyCenter" title="Align Center"><i class="bi bi-text-center"></i></button>
<button class="btn btn-outline-secondary" data-command="justifyRight" title="Align Right"><i class="bi bi-text-right"></i></button>
</div>
<div class="btn-group">
<button class="btn btn-outline-secondary" data-command="insertUnorderedList" title="Bullet List"><i class="bi bi-list-ul"></i></button>
<button class="btn btn-outline-secondary" data-command="insertOrderedList" title="Numbered List"><i class="bi bi-list-ol"></i></button>
<button class="btn btn-outline-secondary" data-command="insertCircleList" title="Circle List"><i class="bi bi-record-circle"></i></button>
<button class="btn btn-outline-secondary" data-command="insertSquareList" title="Square List"><i class="bi bi-square"></i></button>
</div>
</div>
</li>
<li class="list-group-item">
<div class="btn-toolbar justify-content-between">
<div class="btn-group">
<button class="btn btn-outline-secondary" data-command="createLink" title="Insert Link"><i class="bi bi-link"></i></button>
<button class="btn btn-outline-secondary" data-command="insertImage" title="Insert Image"><i class="bi bi-image"></i></button>
<button class="btn btn-outline-secondary" data-command="insertTable" title="Insert Table"><i class="bi bi-table"></i></button>
</div>
<div class="btn-group">
<button class="btn btn-outline-secondary bi bi-emoji-smile" data-command="insertEmoji" title="Insert Emoji"></button>
<button class="btn btn-outline-secondary bi bi-hash" data-command="insertSymbol" title="Insert Symbol"></button>
<button class="btn btn-outline-secondary bi bi-palette" data-command="insertColor" title="Text Color"></button>
</div>
<div class="btn-group">
<button class="btn btn-outline-secondary" data-command="undo" title="Undo"><i class="bi bi-arrow-counterclockwise"></i></button>
<button class="btn btn-outline-secondary" data-command="redo" title="Redo"><i class="bi bi-arrow-clockwise"></i></button>
</div>
<div class="btn-group">
<button class="btn btn-outline-secondary" data-command="cut" title="Cut"><i class="bi bi-scissors"></i></button>
<button class="btn btn-outline-secondary" data-command="copy" title="Copy"><i class="bi bi-files"></i></button>
<button class="btn btn-outline-secondary" data-command="paste" title="Paste"><i class="bi bi-clipboard"></i></button>
</div>
</div>
</li>
</ul>
<div class="card-body">
<div id="editor" class="form-control" contenteditable="true" style="min-height: 300px; max-height:700px; overflow-y: auto;">
Start typing here...
</div>
<textarea id="sourceView" class="form-control d-none" style="height: 300px; font-family: monospace;"></textarea>
</div>
</div>
</div>
</div>
</div>
<script type="module" src="main.js"></script>
</body>
</html>
8 changes: 8 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//import './style.css';
import { WysiwygEditor } from 'wysiwyg.js';

document.addEventListener('DOMContentLoaded', () => {
const editor = new WysiwygEditor('#editor', {
toolbar: '#toolbar'
});
});
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "vanilla-wysiwyg",
"private": true,
"version": "0.0.0",
"type": "module",
"dependencies": {
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3"
}
}
94 changes: 94 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#sourceView {
font-family: 'Courier New', Courier, monospace;
font-size: 14px;
white-space: pre-wrap;
resize: none;
}

/* Font controls */
#fontFamilySelect,
#fontSizeSelect,
#headingSelect {
min-width: 120px;
}

#fontFamilySelect option {
font-size: 14px;
}

/* Emoji and Symbol pickers */
.emoji-picker,
.color-picker,
.symbol-picker {
position: absolute;
background: var(--bs-body-bg);
border: 1px solid var(--bs-border-color-translucent);
border-radius: var(--bs-border-radius);
padding: 5px;
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 2px;
z-index: 1000;
box-shadow: var(--bs-box-shadow);
}

.emoji-picker button,
.color-picker button,
.symbol-picker button {
background: none;
border: 1px solid #464646;
padding: 5px;
cursor: pointer;
font-size: 16px;
}

.emoji-picker button:hover,
.color-picker button:hover,
.symbol-picker button:hover {
background: #575757;
}

/* Table styles */
.table {
width: 100%;
margin-bottom: 1rem;
border-collapse: collapse;
}

.table th,
.table td {
padding: 0.75rem;
vertical-align: top;
border: 1px solid #dee2e6;
min-width: 100px;
}

.table th {
font-weight: bold;
background-color: rgba(0, 0, 0, 0.05);
}

/* Add tooltips for better UX */
[data-command] {
position: relative;
}

[data-command]::after {
transition:opacity 1s linear;
opacity:0;
}
[data-command]:hover::after {
content: attr(title);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
padding: 4px 8px;
background-color: rgba(0, 0, 0, 0.8);
color: white;
opacity: 1;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
z-index: 1000;
}
Loading

0 comments on commit be32808

Please sign in to comment.