<nav id="main-navbar"
data-turbo-permanent
data-controller="navbar"
data-navbar-menu-open-value="false"
class="navbar">
<div class="navbar-inner">
<div class="layout" data-controller="sidebar">
<aside class="sidebar">
<%= render "shared/sidebar", active: params[:controller] %>
</aside>
<main class="content-area">
class ProductsController < ApplicationController
PER_PAGE = 24
def index
@page = [params[:page].to_i, 1].max
@sort = %w[name price recent].include?(params[:sort]) ? params[:sort] : "recent"
<template>
<form @submit.prevent="form.post(route('posts.store'))">
<div>
<label>Title</label>
<input v-model="form.title" type="text" />
<div v-if="form.errors.title">{{ form.errors.title }}</div>
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { fetchCurrentUser, postLogin, postLogout } from './api';
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
class CommentsController < ApplicationController
before_action :set_post
def create
@comment = @post.comments.build(comment_params)
# Controller responding with Turbo Stream
class PostsController < ApplicationController
def create
@post = Post.new(post_params)
if @post.save
<div class="settings-layout">
<nav class="settings-sidebar">
<h2>Settings</h2>
<ul>
<% settings_sections.each do |section| %>
<li class="<%= "active" if current_page?(section.path) %>">
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static values = { keymap: Object }
connect() {
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "App" %></title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
import { Turbo } from "@hotwired/turbo-rails"
Turbo.StreamActions.redirect = function () {
const url = this.getAttribute("url")
if (!url) return
let installed = false;
function notify(message, level = "error") {
document.dispatchEvent(
new CustomEvent("flash:show", { detail: { message, level } })
);