Skip to content
Draft
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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ A minimalist browser-based playground for testing Nunjucks templates with live H
## Features

- **Live Preview**: Real-time HTML rendering in an iframe
- **Three-Panel Layout**: Template input, JSON data input, and HTML output
- **Three-Panel Layout**: JSON data input (collapsible), template input, and HTML output
- **Collapsible JSON Panel**: Collapse the JSON data panel to maximize workspace
- **Error Handling**: Clear error messages for invalid JSON or template syntax
- **Keyboard Shortcuts**: Press Ctrl+Enter (or Cmd+Enter on Mac) to render
- **No Server Required**: Runs entirely in the browser
Expand All @@ -18,8 +19,8 @@ A minimalist browser-based playground for testing Nunjucks templates with live H
## Usage

1. Open `docs/index.html` in your web browser (or visit the GitHub Pages URL)
2. Edit the Nunjucks template in the left panel
3. Modify the JSON data in the middle panel
2. Edit the JSON data in the left panel (collapsible for more space)
3. Modify the Nunjucks template in the middle panel
4. Click "Render" or press Ctrl+Enter to see the output
5. The rendered HTML appears in the right panel

Expand Down
112 changes: 96 additions & 16 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
transition: flex 0.3s ease;
}

.panel.collapsed {
flex: 0 0 auto;
min-width: 40px;
}

.panel.collapsed .panel-content {
display: none;
}

.panel-header {
Expand All @@ -61,6 +71,37 @@
padding: 0.75rem 1rem;
font-weight: 500;
font-size: 0.9rem;
display: flex;
justify-content: space-between;
align-items: center;
}

.toggle-btn {
background: transparent;
color: white;
border: 1px solid rgba(255,255,255,0.3);
padding: 0.25rem 0.5rem;
margin: 0;
border-radius: 3px;
cursor: pointer;
font-size: 0.8rem;
transition: all 0.2s;
}

.toggle-btn:hover {
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.5);
}

.panel.collapsed .panel-header {
writing-mode: vertical-rl;
text-orientation: mixed;
padding: 1rem 0.5rem;
}

.panel.collapsed .toggle-btn {
writing-mode: horizontal-tb;
transform: rotate(90deg);
}

.panel-content {
Expand Down Expand Up @@ -118,6 +159,32 @@
button:active {
transform: translateY(1px);
}

/* Responsive design */
@media (max-width: 768px) {
.container {
flex-direction: column;
}

.panel {
min-height: 200px;
}

.panel.collapsed {
min-height: auto;
flex: 0 0 auto;
}

.panel.collapsed .panel-header {
writing-mode: horizontal-tb;
text-orientation: initial;
padding: 0.75rem 1rem;
}

.panel.collapsed .toggle-btn {
transform: none;
}
}
</style>
</head>
<body>
Expand All @@ -127,6 +194,25 @@ <h1>instant.njk</h1>
</header>

<div class="container">
<div class="panel" id="jsonPanel">
<div class="panel-header">
<span>JSON Data</span>
<button class="toggle-btn" id="toggleJson" aria-label="Toggle JSON Data panel" aria-expanded="true">◀</button>
</div>
<div class="panel-content">
<textarea id="data" placeholder="Enter your JSON data here...">{
"title": "My Shop",
"heading": "Welcome to my shop!",
"items": [
{ "name": "Apple", "price": "$1.00" },
{ "name": "Banana", "price": "$0.50" },
{ "name": "Orange", "price": "$0.75" }
]
}</textarea>
<button id="render">Render</button>
</div>
</div>

<div class="panel">
<div class="panel-header">Nunjucks Template</div>
<div class="panel-content">
Expand All @@ -147,22 +233,6 @@ <h1>{{ heading }}</h1>
</div>
</div>

<div class="panel">
<div class="panel-header">JSON Data</div>
<div class="panel-content">
<textarea id="data" placeholder="Enter your JSON data here...">{
"title": "My Shop",
"heading": "Welcome to my shop!",
"items": [
{ "name": "Apple", "price": "$1.00" },
{ "name": "Banana", "price": "$0.50" },
{ "name": "Orange", "price": "$0.75" }
]
}</textarea>
<button id="render">Render</button>
</div>
</div>

<div class="panel">
<div class="panel-header">Output (HTML Preview)</div>
<div class="panel-content">
Expand All @@ -177,6 +247,16 @@ <h1>{{ heading }}</h1>
const dataInput = document.getElementById('data');
const outputDiv = document.getElementById('output');
const renderButton = document.getElementById('render');
const jsonPanel = document.getElementById('jsonPanel');
const toggleJsonBtn = document.getElementById('toggleJson');

// Toggle JSON panel collapse/expand
toggleJsonBtn.addEventListener('click', (e) => {
e.stopPropagation();
const isCollapsed = jsonPanel.classList.toggle('collapsed');
toggleJsonBtn.textContent = isCollapsed ? '▶' : '◀';
toggleJsonBtn.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');
});

function renderTemplate() {
try {
Expand Down
112 changes: 96 additions & 16 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
transition: flex 0.3s ease;
}

.panel.collapsed {
flex: 0 0 auto;
min-width: 40px;
}

.panel.collapsed .panel-content {
display: none;
}

.panel-header {
Expand All @@ -61,6 +71,37 @@
padding: 0.75rem 1rem;
font-weight: 500;
font-size: 0.9rem;
display: flex;
justify-content: space-between;
align-items: center;
}

.toggle-btn {
background: transparent;
color: white;
border: 1px solid rgba(255,255,255,0.3);
padding: 0.25rem 0.5rem;
margin: 0;
border-radius: 3px;
cursor: pointer;
font-size: 0.8rem;
transition: all 0.2s;
}

.toggle-btn:hover {
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.5);
}

.panel.collapsed .panel-header {
writing-mode: vertical-rl;
text-orientation: mixed;
padding: 1rem 0.5rem;
}

.panel.collapsed .toggle-btn {
writing-mode: horizontal-tb;
transform: rotate(90deg);
}

.panel-content {
Expand Down Expand Up @@ -118,6 +159,32 @@
button:active {
transform: translateY(1px);
}

/* Responsive design */
@media (max-width: 768px) {
.container {
flex-direction: column;
}

.panel {
min-height: 200px;
}

.panel.collapsed {
min-height: auto;
flex: 0 0 auto;
}

.panel.collapsed .panel-header {
writing-mode: horizontal-tb;
text-orientation: initial;
padding: 0.75rem 1rem;
}

.panel.collapsed .toggle-btn {
transform: none;
}
}
</style>
</head>
<body>
Expand All @@ -127,6 +194,25 @@ <h1>instant.njk</h1>
</header>

<div class="container">
<div class="panel" id="jsonPanel">
<div class="panel-header">
<span>JSON Data</span>
<button class="toggle-btn" id="toggleJson" aria-label="Toggle JSON Data panel" aria-expanded="true">◀</button>
</div>
<div class="panel-content">
<textarea id="data" placeholder="Enter your JSON data here...">{
"title": "My Shop",
"heading": "Welcome to my shop!",
"items": [
{ "name": "Apple", "price": "$1.00" },
{ "name": "Banana", "price": "$0.50" },
{ "name": "Orange", "price": "$0.75" }
]
}</textarea>
<button id="render">Render</button>
</div>
</div>

<div class="panel">
<div class="panel-header">Nunjucks Template</div>
<div class="panel-content">
Expand All @@ -147,22 +233,6 @@ <h1>{{ heading }}</h1>
</div>
</div>

<div class="panel">
<div class="panel-header">JSON Data</div>
<div class="panel-content">
<textarea id="data" placeholder="Enter your JSON data here...">{
"title": "My Shop",
"heading": "Welcome to my shop!",
"items": [
{ "name": "Apple", "price": "$1.00" },
{ "name": "Banana", "price": "$0.50" },
{ "name": "Orange", "price": "$0.75" }
]
}</textarea>
<button id="render">Render</button>
</div>
</div>

<div class="panel">
<div class="panel-header">Output (HTML Preview)</div>
<div class="panel-content">
Expand All @@ -177,6 +247,16 @@ <h1>{{ heading }}</h1>
const dataInput = document.getElementById('data');
const outputDiv = document.getElementById('output');
const renderButton = document.getElementById('render');
const jsonPanel = document.getElementById('jsonPanel');
const toggleJsonBtn = document.getElementById('toggleJson');

// Toggle JSON panel collapse/expand
toggleJsonBtn.addEventListener('click', (e) => {
e.stopPropagation();
const isCollapsed = jsonPanel.classList.toggle('collapsed');
toggleJsonBtn.textContent = isCollapsed ? '▶' : '◀';
toggleJsonBtn.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true');
});

function renderTemplate() {
try {
Expand Down