Skip to content

Examples

These practical examples illustrate the main features of Teeny Store and are designed to help you learn how to use Teeny Store effectively.
For details on all available options and methods, see the API Reference.

Task Manager

    js
    import { createTaskManagerStore } from "./store";
    
    const store = createTaskManagerStore();
    store.useEffect(renderTasks, (state) => [state.tasks, state.filter]); 
    
    function renderTasks(state) {
      const taskList = document.getElementById('task-list');
      if (taskList) {
        taskList.innerHTML = '';
        state.tasks.forEach((task) => {
          if (state.filter === 'done' && !task.done) return;
          if (state.filter === 'pending' && task.done) return;
    
          const li = document.createElement('li');
          li.className = 'task-item';
    
          const info = document.createElement('div');
          info.className = 'task-info' + (task.done ? ' done' : '');
          info.innerHTML = `<strong>${task.title}</strong><br>${task.description}`;
    
          const btnGroup = document.createElement('div');
    
          const toggleBtn = document.createElement('button');
          toggleBtn.textContent = task.done ? 'Undone' : 'Done';
          toggleBtn.addEventListener('click', () => toggleTaskDone(task.id));
    
          const editBtn = document.createElement('button');
          editBtn.textContent = 'Edit';
          editBtn.addEventListener('click', () => editTask(task.id));
    
          const deleteBtn = document.createElement('button');
          deleteBtn.textContent = 'Delete';
          deleteBtn.addEventListener('click', () => deleteTask(task.id));
    
          btnGroup.appendChild(toggleBtn);
          btnGroup.appendChild(editBtn);
          btnGroup.appendChild(deleteBtn);
    
          li.appendChild(info);
          li.appendChild(btnGroup);
          taskList.appendChild(li);
        });
      }
    }
    
    function filterTasks(event) {
      store.actions.filterTasks(event.target.value);
    }
    
    function addTask() {
      const titleInput = document.getElementById('title');
      const descInput = document.getElementById('description');
    
      if (titleInput && descInput) {
        const newTitle = titleInput.value.trim();
        const newDesc = descInput.value.trim();
    
        if (newTitle && newDesc) {
          store.actions.addTask({ title: newTitle, desc: newDesc });
          titleInput.value = '';
          descInput.value = '';
        }
      }
    }
    
    function editTask(id) {
      const tasks = store.getState().tasks;
      const task = tasks.find((task) => task.id === id);
      if (!task) return;
    
      const newTitle = prompt('Edit title:', task.title);
      const newDesc = prompt('Edit description:', task.description);
      if (newTitle && newDesc) {
        store.actions.editTask({ id, title: newTitle.trim(), desc: newDesc.trim() });
      }
    }
    
    function toggleTaskDone(id) {
      store.actions.toggleTaskDone(id);
    }
    
    function deleteTask(id) {
      store.actions.deleteTask(id);
    }
    
    function clearAllTasks() {
      if (confirm('Are you sure you want to delete all tasks?')) {
        store.actions.clearAllTasks();
      }
    }
    
    document.getElementById('filter')?.addEventListener('change', filterTasks);
    document.getElementById('add-btn')?.addEventListener('click', addTask);
    document.getElementById('clear-btn')?.addEventListener('click', clearAllTasks);
    js
    import { createPersistencePlugin, defineStore } from "@vuezy/teeny-store";
    
    export function createTaskManagerStore() {
      const store = defineStore({ tasks: [], filter: 'all' }, {
        addTask: (state, setState, task) => {
          const tasks = [
            ...state.tasks,
            {
              id: crypto.randomUUID(),
              title: task.title,
              description: task.desc,
              done: false,
            },
          ];
          setState(() => ({ ...state, tasks }));
        },
        editTask: (state, setState, updatedTask) => {
          const tasks = state.tasks.map((task) => {
            return task.id === updatedTask.id
              ? { ...task, title: updatedTask.title, description: updatedTask.desc }
              : task;
          });
          setState(() => ({ ...state, tasks }));
        },
        toggleTaskDone: (state, setState, id) => {
          const tasks = state.tasks.map((task) => {
            return task.id === id ? { ...task, done: !task.done } : task;
          });
          setState(() => ({ ...state, tasks }));
        },
        deleteTask: (state, setState, id) => {
          const tasks = state.tasks.filter((task) => task.id !== id);
          setState(() => ({ ...state, tasks }));
        },
        clearAllTasks: (state, setState) => {
          setState(() => ({ ...state, tasks: [] }));
        },
        filterTasks: (state, setState, filter) => {
          setState(() => ({ ...state, filter }));
        },
      }).use(createPersistencePlugin({
        storage: 'localStorage',
        key: 'task-manager',
        onLoaded: (data) => {
          return { ...data, filter: 'all' };
        },
      })).create();
    
      return store;
    };

    Cart System

    Total: $
    js
    import { createCartStore } from "./cartStore";
    import { createProductStore } from "./productStore";
    
    const productStore = createProductStore();
    const cartStore = createCartStore();
    
    productStore.useEffect(renderProducts, (state) => [state]);
    cartStore.useEffect(renderCart, (state) => [state]);
    cartStore.useEffect(renderCartItemCount, () => [cartStore.computed.itemCount]);
    cartStore.useEffect(renderCartTotalPrice, () => [cartStore.computed.totalPrice]);
    
    function renderProducts(products) {
      const productList = document.getElementById('products');
      if (productList) {
        productList.innerHTML = '';
        products.forEach((product) => {
          const productContainer = document.createElement('div');
          productContainer.className = 'product-container';
          productContainer.innerHTML = `
            <span>${product.name} - $${product.price}<br><small>${product.stock} item(s) available</small></span>
            <button>Add to cart</button>
          `;
          
          const addBtn = productContainer.querySelector('button');
          if (addBtn) {
            if (product.stock > 0) {
              addBtn.addEventListener('click', () => addToCart(product.id));
            } else {
              addBtn.className = 'disabled';
              addBtn.setAttribute('disabled', true);
            }
          }
    
          productList.appendChild(productContainer);
        });
      }
    }
    
    function renderCart(cart) {
      const cartEl = document.getElementById('cart');
      if (cartEl) {
        cartEl.innerHTML = '';
        cart.forEach((item) => {
          const cartItemContainer = document.createElement('div');
          cartItemContainer.className = 'cart-item-container';
          cartItemContainer.innerHTML = `
            <div>${item.name}<br><small>@ $${item.price}</small></div>
            <div>
              <div class="cart-item-total">$${item.price * item.quantity}</div>
              <div class="cart-item-quantity">
                <button class="decrement-btn">-</button>
                <span>${item.quantity}</span>
                <button class="increment-btn">+</button>
              </div>
            </div>
          `;
    
          const decrementBtn = cartItemContainer.querySelector('.decrement-btn');
          if (decrementBtn) {
            decrementBtn.addEventListener('click', () => removeFromCart(item.id));
          }
          const incrementBtn = cartItemContainer.querySelector('.increment-btn');
          if (incrementBtn) {
            incrementBtn.addEventListener('click', () => addToCart(item.id));
          }
    
          cartEl.appendChild(cartItemContainer);
        });
      }
    }
    
    function renderCartItemCount() {
      const itemCountEl = document.getElementById('cart-item-count');
      if (itemCountEl) {
        itemCountEl.textContent = cartStore.computed.itemCount;
      }
    }
    
    function renderCartTotalPrice() {
      const totalPriceEl = document.getElementById('cart-total-price');
      if (totalPriceEl) {
        totalPriceEl.textContent = cartStore.computed.totalPrice;
      }
    }
    
    function addToCart(productId) {
      const stockDecremented = productStore.actions.decrementStock(productId);
      if (stockDecremented) {
        cartStore.actions.addProduct(productStore.getState().find((product) => product.id === productId));
      }
    }
    
    function removeFromCart(productId) {
      const productRemoved = cartStore.actions.removeProduct(productId);
      if (productRemoved) {
        productStore.actions.incrementStock(productId);
      }
    }
    js
    import { createPersistencePlugin, defineStore } from "@vuezy/teeny-store";
    
    const products = [
      { id: 1, name: 'Laptop', price: 1200, stock: 10 },
      { id: 2, name: 'Headphones', price: 150, stock: 6 },
      { id: 3, name: 'Mouse', price: 50, stock: 30 },
      { id: 4, name: 'Keyboard', price: 80, stock: 5 },
      { id: 5, name: 'Smartphone', price: 900, stock: 50 },
      { id: 6, name: 'Monitor', price: 400, stock: 4 },
      { id: 7, name: 'External HDD', price: 200, stock: 5 },
      { id: 8, name: 'Webcam', price: 100, stock: 2 },
    ];
    
    export function createProductStore() {
      const store = defineStore(products, {
        decrementStock: (state, setState, id) => {
          const { products, stockDecremented } = state.reduce((result, product) => {
            if (product.id === id && product.stock > 0) {
              result.products.push({ ...product, stock: product.stock - 1 });
              result.stockDecremented = true;
            } else {
              result.products.push(product);
            }
            return result;
          }, { products: [], stockDecremented: false });
    
          setState(() => products);
          return stockDecremented;
        },
        incrementStock: (state, setState, id) => {
          const products = state.map((product) => {
            return product.id === id ? { ...product, stock: product.stock + 1 } : product;
          });
          setState(() => products);
        },
      }).use(createPersistencePlugin({
        storage: 'localStorage',
        key: 'cart-system:products',
      })).create();
    
      return store;
    };
    js
    import { createPersistencePlugin, defineStore } from "@vuezy/teeny-store";
    
    export function createCartStore() {
      const store = defineStore([], {
        addProduct: (state, setState, product) => {
          const { cart, itemUpdated } = state.reduce((result, item) => {
            if (item.id === product.id) {
              result.cart.push({ ...item, quantity: item.quantity + 1 });
              result.itemUpdated = true;
            } else {
              result.cart.push(item);
            }
            return result;
          }, { cart: [], itemUpdated: false });
    
          if (!itemUpdated) {
            cart.push({
              id: product.id,
              name: product.name,
              price: product.price,
              quantity: 1,
            });
          }
          setState(() => cart);
        },
        removeProduct: (state, setState, productId) => {
          const { cart, productRemoved } = state.reduce((result, item) => {
            if (item.id === productId) {
              if (item.quantity > 1) {
                result.cart.push({ ...item, quantity: item.quantity - 1 });
              }
              result.productRemoved = true;
            } else {
              result.cart.push(item);
            }
            return result;
          }, { cart: [], productRemoved: false });
    
          setState(() => cart);
          return productRemoved;
        },
      }).use(createPersistencePlugin({
        storage: 'localStorage',
        key: 'cart-system:cart',
      })).create();
    
      store.compute('itemCount', (state) => {
        return state.reduce((count, item) => count + item.quantity, 0);
      }, (state) => [state]);
    
      store.compute('totalPrice', (state) => {
        return state.reduce((total, item) => total + item.price * item.quantity, 0);
      }, (state) => [state]);
    
      return store;
    };

    Released under the MIT License.