Models 44

Mistral Small 4

by MistralReasoningClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
25.6 s
Cost
$0.0032
Output tokens
5,201
Spent thinking
0 tokens
Speed
207.9 tok/s
Console errors
0
First token after
564 ms
First visible text after
564 ms
Prompt tokens
514
Code size
19.6 KB
Finish reason
stop
Served by
Mistral
Model id
mistralai/mistral-small-2603
Reasoning sent
model default
Max output
209,715 tokens
Generated
Nov 12, 2026

What it was asked

The prompt
Build an interactive Kanban board in vanilla HTML, CSS and JavaScript (no framework, no library). Requirements: - Three columns: "To do", "In progress", "Done", each showing its card count. - Pre-populate the board with 6 realistic cards spread across the columns so the first screenshot looks alive. - Each card has a title and a priority (low / medium / high) shown as a colored badge. - Add a card through a small modal form (title required), and delete a card with a button on it. - Drag and drop cards between columns with the mouse, with a clear visual drop indicator. - A search field that filters cards live by title. - A light / dark theme toggle. - State lives in memory only (no storage APIs).
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 721 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kanban Board</title>
  <style>
    :root {
      --bg-primary: #f5f5f5;
      --bg-secondary: #ffffff;
      --text-primary: #333333;
      --text-secondary: #666666;
      --border-color: #dddddd;
      --shadow-color: rgba(0, 0, 0, 0.1);
      --card-bg: #ffffff;
      --card-border: #e0e0e0;
      --priority-low: #4caf50;
      --priority-medium: #ff9800;
      --priority-high: #f44336;
      --column-bg: #f9f9f9;
    }

    [data-theme="dark"] {
      --bg-primary: #1a1a1a;
      --bg-secondary: #2d2d2d;
      --text-primary: #f0f0f0;
      --text-secondary: #cccccc;
      --border-color: #444444;
      --shadow-color: rgba(0, 0, 0, 0.3);
      --card-bg: #333333;
      --card-border: #555555;
      --column-bg: #222222;
    }

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      background-color: var(--bg-primary);
      color: var(--text-primary);
      line-height: 1.6;
      padding: 20px;
      min-height: 100vh;
    }

    .header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 30px;
      flex-wrap: wrap;
      gap: 20px;
    }

    .header h1 {
      font-size: 2rem;
      font-weight: 600;
    }

    .search-container {
      position: relative;
      flex: 1;
      min-width: 250px;
    }

    .search-container input {
      width: 100%;
      padding: 12px 15px 12px 40px;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      background-color: var(--bg-secondary);
      color: var(--text-primary);
      font-size: 1rem;
      transition: box-shadow 0.2s;
    }

    .search-container input:focus {
      outline: none;
      box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
    }

    .search-icon {
      position: absolute;
      left: 15px;
      top: 50%;
      transform: translateY(-50%);
      color: var(--text-secondary);
      pointer-events: none;
    }

    .theme-toggle {
      background: none;
      border: none;
      padding: 10px 15px;
      border-radius: 6px;
      cursor: pointer;
      font-size: 1rem;
      transition: background-color 0.2s;
    }

    .theme-toggle:hover {
      background-color: rgba(0, 0, 0, 0.1);
    }

    [data-theme="dark"] .theme-toggle:hover {
      background-color: rgba(255, 255, 255, 0.1);
    }

    .board {
      display: flex;
      gap: 20px;
      overflow-x: auto;
      padding-bottom: 10px;
    }

    .column {
      flex: 1;
      min-width: 280px;
      background-color: var(--column-bg);
      border-radius: 8px;
      padding: 15px;
      box-shadow: 0 2px 8px var(--shadow-color);
    }

    .column-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 15px;
      padding-bottom: 10px;
      border-bottom: 1px solid var(--border-color);
    }

    .column-title {
      font-size: 1.1rem;
      font-weight: 600;
      color: var(--text-primary);
    }

    .card-count {
      background-color: var(--bg-secondary);
      color: var(--text-secondary);
      padding: 4px 8px;
      border-radius: 12px;
      font-size: 0.85rem;
      font-weight: 500;
    }

    .add-card-btn {
      width: 100%;
      padding: 10px;
      background-color: var(--bg-secondary);
      border: 2px dashed var(--border-color);
      border-radius: 6px;
      color: var(--text-secondary);
      cursor: pointer;
      font-size: 0.9rem;
      transition: all 0.2s;
    }

    .add-card-btn:hover {
      border-color: var(--text-secondary);
      color: var(--text-primary);
    }

    .cards-container {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }

    .card {
      background-color: var(--card-bg);
      border: 1px solid var(--card-border);
      border-radius: 6px;
      padding: 12px;
      cursor: grab;
      transition: all 0.2s;
      position: relative;
    }

    .card:hover {
      box-shadow: 0 2px 8px var(--shadow-color);
      transform: translateY(-2px);
    }

    .card.dragging {
      opacity: 0.5;
      background-color: var(--bg-secondary);
    }

    .card-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 8px;
    }

    .card-title {
      font-weight: 500;
      color: var(--text-primary);
    }

    .priority-badge {
      padding: 4px 8px;
      border-radius: 12px;
      font-size: 0.75rem;
      font-weight: 600;
      color: white;
    }

    .priority-low {
      background-color: var(--priority-low);
    }

    .priority-medium {
      background-color: var(--priority-medium);
    }

    .priority-high {
      background-color: var(--priority-high);
    }

    .delete-btn {
      background: none;
      border: none;
      color: var(--text-secondary);
      cursor: pointer;
      padding: 4px;
      margin-left: 8px;
      transition: color 0.2s;
    }

    .delete-btn:hover {
      color: var(--priority-high);
    }

    .modal-overlay {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(0, 0, 0, 0.5);
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 1000;
    }

    .modal {
      background-color: var(--bg-secondary);
      border-radius: 8px;
      padding: 25px;
      width: 100%;
      max-width: 400px;
      box-shadow: 0 4px 20px var(--shadow-color);
    }

    .modal h2 {
      margin-bottom: 20px;
      font-size: 1.3rem;
      color: var(--text-primary);
    }

    .form-group {
      margin-bottom: 15px;
    }

    .form-group label {
      display: block;
      margin-bottom: 5px;
      font-weight: 500;
      color: var(--text-primary);
    }

    .form-group input {
      width: 100%;
      padding: 10px;
      border: 1px solid var(--border-color);
      border-radius: 4px;
      background-color: var(--bg-primary);
      color: var(--text-primary);
      font-size: 1rem;
    }

    .form-group input:focus {
      outline: none;
      border-color: #007bff;
      box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
    }

    .priority-selector {
      display: flex;
      gap: 10px;
      margin-bottom: 20px;
    }

    .priority-option {
      flex: 1;
      padding: 10px;
      border-radius: 4px;
      text-align: center;
      cursor: pointer;
      font-weight: 500;
      transition: all 0.2s;
    }

    .priority-option.selected {
      color: white;
    }

    .priority-low.selected {
      background-color: var(--priority-low);
    }

    .priority-medium.selected {
      background-color: var(--priority-medium);
    }

    .priority-high.selected {
      background-color: var(--priority-high);
    }

    .modal-buttons {
      display: flex;
      justify-content: flex-end;
      gap: 10px;
      margin-top: 20px;
    }

    .btn {
      padding: 10px 20px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-weight: 500;
      transition: all 0.2s;
    }

    .btn-primary {
      background-color: #007bff;
      color: white;
    }

    .btn-primary:hover {
      background-color: #0056b3;
    }

    .btn-secondary {
      background-color: var(--bg-primary);
      color: var(--text-primary);
      border: 1px solid var(--border-color);
    }

    .btn-secondary:hover {
      background-color: var(--border-color);
    }

    .drop-indicator {
      height: 4px;
      background-color: #007bff;
      margin-bottom: 8px;
      border-radius: 2px;
      display: none;
    }

    .column.drop-target {
      background-color: rgba(0, 123, 255, 0.1);
    }

    @media (max-width: 768px) {
      .board {
        flex-direction: column;
      }

      .column {
        min-width: 100%;
      }

      .header {
        flex-direction: column;
        align-items: stretch;
      }

      .search-container {
        order: -1;
      }
    }
  </style>
</head>
<body>
  <div class="header">
    <h1>Kanban Board</h1>
    <div class="search-container">
      <span class="search-icon">🔍</span>
      <input type="text" id="search-input" placeholder="Search cards...">
    </div>
    <button class="theme-toggle" id="theme-toggle">🌓 Toggle Theme</button>
  </div>

  <div class="board" id="board">
    <div class="column" id="todo-column">
      <div class="column-header">
        <span class="column-title">To do</span>
        <span class="card-count" id="todo-count">0</span>
      </div>
      <div class="drop-indicator" id="todo-drop-indicator"></div>
      <div class="cards-container" id="todo-cards"></div>
      <button class="add-card-btn" id="add-todo-card">+ Add Card</button>
    </div>

    <div class="column" id="inprogress-column">
      <div class="column-header">
        <span class="column-title">In progress</span>
        <span class="card-count" id="inprogress-count">0</span>
      </div>
      <div class="drop-indicator" id="inprogress-drop-indicator"></div>
      <div class="cards-container" id="inprogress-cards"></div>
      <button class="add-card-btn" id="add-inprogress-card">+ Add Card</button>
    </div>

    <div class="column" id="done-column">
      <div class="column-header">
        <span class="column-title">Done</span>
        <span class="card-count" id="done-count">0</span>
      </div>
      <div class="drop-indicator" id="done-drop-indicator"></div>
      <div class="cards-container" id="done-cards"></div>
      <button class="add-card-btn" id="add-done-card">+ Add Card</button>
    </div>
  </div>

  <div class="modal-overlay" id="modal-overlay">
    <div class="modal">
      <h2>Add New Card</h2>
      <form id="card-form">
        <div class="form-group">
          <label for="card-title">Title*</label>
          <input type="text" id="card-title" required>
        </div>
        <div class="form-group">
          <label>Priority</label>
          <div class="priority-selector">
            <div class="priority-option" data-priority="low">Low</div>
            <div class="priority-option" data-priority="medium">Medium</div>
            <div class="priority-option" data-priority="high">High</div>
          </div>
        </div>
        <input type="hidden" id="selected-priority" value="medium">
        <div class="modal-buttons">
          <button type="button" class="btn btn-secondary" id="cancel-btn">Cancel</button>
          <button type="submit" class="btn btn-primary">Add Card</button>
        </div>
      </form>
    </div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      // State
      let cards = [
        { id: 1, title: 'Implement login page', priority: 'high', column: 'todo' },
        { id: 2, title: 'Design database schema', priority: 'medium', column: 'inprogress' },
        { id: 3, title: 'Write API documentation', priority: 'low', column: 'done' },
        { id: 4, title: 'Fix mobile navigation bug', priority: 'high', column: 'inprogress' },
        { id: 5, title: 'Update project README', priority: 'medium', column: 'todo' },
        { id: 6, title: 'Test payment integration', priority: 'low', column: 'done' }
      ];

      let draggedCard = null;
      let searchQuery = '';

      // DOM elements
      const board = document.getElementById('board');
      const modalOverlay = document.getElementById('modal-overlay');
      const cardForm = document.getElementById('card-form');
      const cardTitleInput = document.getElementById('card-title');
      const selectedPriorityInput = document.getElementById('selected-priority');
      const cancelBtn = document.getElementById('cancel-btn');
      const themeToggle = document.getElementById('theme-toggle');
      const searchInput = document.getElementById('search-input');

      const todoColumn = document.getElementById('todo-column');
      const inprogressColumn = document.getElementById('inprogress-column');
      const doneColumn = document.getElementById('done-column');

      const todoCardsContainer = document.getElementById('todo-cards');
      const inprogressCardsContainer = document.getElementById('inprogress-cards');
      const doneCardsContainer = document.getElementById('done-cards');

      const todoCount = document.getElementById('todo-count');
      const inprogressCount = document.getElementById('inprogress-count');
      const doneCount = document.getElementById('done-count');

      // Initialize
      renderCards();
      updateCounts();

      // Event listeners
      themeToggle.addEventListener('click', toggleTheme);
      searchInput.addEventListener('input', handleSearch);
      cardForm.addEventListener('submit', handleAddCard);
      cancelBtn.addEventListener('click', closeModal);

      // Add card buttons
      document.getElementById('add-todo-card').addEventListener('click', () => openModal('todo'));
      document.getElementById('add-inprogress-card').addEventListener('click', () => openModal('inprogress'));
      document.getElementById('add-done-card').addEventListener('click', () => openModal('done'));

      // Priority selector
      const priorityOptions = document.querySelectorAll('.priority-option');
      priorityOptions.forEach(option => {
        option.addEventListener('click', function() {
          priorityOptions.forEach(opt => opt.classList.remove('selected'));
          this.classList.add('selected');
          selectedPriorityInput.value = this.dataset.priority;
        });
      });

      // Drag and drop setup
      document.addEventListener('dragstart', handleDragStart);
      document.addEventListener('dragover', handleDragOver);
      document.addEventListener('dragleave', handleDragLeave);
      document.addEventListener('drop', handleDrop);
      document.addEventListener('dragend', handleDragEnd);

      // Functions
      function toggleTheme() {
        const html = document.documentElement;
        const currentTheme = html.getAttribute('data-theme');
        const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
        html.setAttribute('data-theme', newTheme);
      }

      function handleSearch(e) {
        searchQuery = e.target.value.toLowerCase();
        renderCards();
      }

      function openModal(column) {
        document.getElementById('selected-priority').value = 'medium';
        priorityOptions.forEach(opt => opt.classList.remove('selected'));
        priorityOptions[1].classList.add('selected');
        modalOverlay.style.display = 'flex';
        cardTitleInput.focus();
      }

      function closeModal() {
        modalOverlay.style.display = 'none';
        cardForm.reset();
      }

      function handleAddCard(e) {
        e.preventDefault();
        const title = cardTitleInput.value.trim();
        if (!title) return;

        const priority = selectedPriorityInput.value;
        const column = document.querySelector('.modal-overlay').dataset.column || 'todo';

        const newCard = {
          id: Date.now(),
          title,
          priority,
          column
        };

        cards.push(newCard);
        renderCards();
        updateCounts();
        closeModal();
      }

      function handleDragStart(e) {
        if (e.target.classList.contains('card')) {
          draggedCard = e.target;
          e.target.classList.add('dragging');
          e.dataTransfer.setData('text/plain', e.target.dataset.cardId);
        }
      }

      function handleDragOver(e) {
        e.preventDefault();
        if (e.target.classList.contains('column') || e.target.classList.contains('cards-container')) {
          clearDropIndicators();
          e.target.classList.add('drop-target');

          const columnId = e.target.id;
          const dropIndicator = document.getElementById(`${columnId.replace('-column', '')}-drop-indicator`);
          dropIndicator.style.display = 'block';
        }
      }

      function handleDragLeave(e) {
        if (e.target.classList.contains('column') || e.target.classList.contains('cards-container')) {
          e.target.classList.remove('drop-target');
          clearDropIndicators();
        }
      }

      function handleDrop(e) {
        e.preventDefault();
        if (e.target.classList.contains('column') || e.target.classList.contains('cards-container')) {
          const columnId = e.target.id;
          const targetColumn = columnId.replace('-column', '');

          const cardId = draggedCard.dataset.cardId;
          const cardIndex = cards.findIndex(card => card.id == cardId);

          if (cardIndex !== -1) {
            cards[cardIndex].column = targetColumn;
            renderCards();
            updateCounts();
          }
        }
      }

      function handleDragEnd(e) {
        if (e.target.classList.contains('card')) {
          e.target.classList.remove('dragging');
          clearDropIndicators();
        }
      }

      function clearDropIndicators() {
        document.querySelectorAll('.drop-indicator').forEach(indicator => {
          indicator.style.display = 'none';
        });
        document.querySelectorAll('.column').forEach(column => {
          column.classList.remove('drop-target');
        });
      }

      function renderCards() {
        // Filter cards by search query
        const filteredCards = cards.filter(card =>
          card.title.toLowerCase().includes(searchQuery)
        );

        // Clear containers
        todoCardsContainer.innerHTML = '';
        inprogressCardsContainer.innerHTML = '';
        doneCardsContainer.innerHTML = '';

        // Group cards by column
        const columns = {
          todo: [],
          inprogress: [],
          done: []
        };

        filteredCards.forEach(card => {
          columns[card.column].push(card);
        });

        // Render cards for each column
        renderColumnCards(todoCardsContainer, columns.todo, 'todo');
        renderColumnCards(inprogressCardsContainer, columns.inprogress, 'inprogress');
        renderColumnCards(doneCardsContainer, columns.done, 'done');
      }

      function renderColumnCards(container, cards, columnId) {
        cards.forEach(card => {
          const cardElement = createCardElement(card);
          container.appendChild(cardElement);
        });
      }

      function createCardElement(card) {
        const cardElement = document.createElement('div');
        cardElement.className = 'card';
        cardElement.draggable = true;
        cardElement.dataset.cardId = card.id;

        const priorityClass = `priority-${card.priority}`;
        cardElement.innerHTML = `
          <div class="card-header">
            <span class="card-title">${escapeHtml(card.title)}</span>
            <button class="delete-btn" data-card-id="${card.id}">✕</button>
          </div>
          <span class="priority-badge ${priorityClass}">${card.priority}</span>
        `;

        // Add delete event listener
        cardElement.querySelector('.delete-btn').addEventListener('click', (e) => {
          e.stopPropagation();
          cards = cards.filter(c => c.id !== card.id);
          renderCards();
          updateCounts();
        });

        return cardElement;
      }

      function updateCounts() {
        const todoCountValue = cards.filter(card => card.column === 'todo').length;
        const inprogressCountValue = cards.filter(card => card.column === 'inprogress').length;
        const doneCountValue = cards.filter(card => card.column === 'done').length;

        todoCount.textContent = todoCountValue;
        inprogressCount.textContent = inprogressCountValue;
        doneCount.textContent = doneCountValue;
      }

      function escapeHtml(unsafe) {
        return unsafe
          .replace(/&/g, "&amp;")
          .replace(/</g, "&lt;")
          .replace(/>/g, "&gt;")
          .replace(/"/g, "&quot;")
          .replace(/'/g, "&#039;");
      }
    });
  </script>
</body>
</html>