### Install Cinder using Igniter
Source: https://github.com/sevenseacat/cinder/blob/main/README.md
Recommended installation method using the Igniter tool. This command automates the setup process.
```bash
mix igniter.install cinder
```
--------------------------------
### Install Cinder and Configure Tailwind CSS
Source: https://context7.com/sevenseacat/cinder/llms.txt
Install Cinder and set up Tailwind CSS integration using the `mix cinder.install` mix task.
```bash
# Install Cinder and configure Tailwind CSS
mix cinder.install
```
--------------------------------
### Quick Start Table Collection
Source: https://github.com/sevenseacat/cinder/blob/main/README.md
A simplified example for a table view, demonstrating essential column configurations for filtering and sorting.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:col :let={user} field="email" filter>{user.email}
<:col :let={user} field="role" filter>{user.role}
```
--------------------------------
### Complete Manual Installation of Cinder
Source: https://github.com/sevenseacat/cinder/blob/main/README.md
After adding the dependency, run these commands to fetch dependencies and install Cinder, including Tailwind CSS configuration.
```bash
mix deps.get
mix cinder.install # Configure Tailwind CSS
```
--------------------------------
### Autocomplete Filter Examples
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
Implement autocomplete filters for searchable dropdowns with server-side option filtering. The first example shows basic usage with static options, and the second demonstrates custom placeholder and result limit.
```heex
<:col
:let={order}
field="customer_id"
filter={[type: :autocomplete, options: @customers]}>
{order.customer.name}
```
```heex
<:col
:let={order}
field="product_id"
filter={[
type: :autocomplete,
options: @products,
placeholder: "Search products...",
max_results: 15
]}>
{order.product.name}
```
--------------------------------
### Date Range Filter Examples
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
Implement date range filters using from/to date pickers. The first example auto-detects for date/datetime fields, while the second includes time selection.
```heex
<:col :let={order} field="created_at" filter sort>{order.created_at}
```
```heex
<:col
:let={order}
field="shipped_at"
filter={[type: :date_range, include_time: true]}>
{order.shipped_at}
```
--------------------------------
### URL Examples for State Management
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Illustrates various URL query parameters for filtering, date range selection, pagination, and sorting within Cinder collections.
```url
# Basic filtering
/users?name=john&email=gmail
```
```url
# Date range
/users?created_at_from=2024-01-01&created_at_to=2024-12-31
```
```url
# Pagination and sorting
/users?page=3&sort=-created_at
```
```url
# Complex state
/users?name=admin&is_active=true&page=2&sort=name
```
--------------------------------
### Basic Cinder Collection Usage
Source: https://github.com/sevenseacat/cinder/blob/main/usage-rules.md
Demonstrates the basic setup for a Cinder collection, specifying the resource and actor, and defining columns with filtering, sorting, and searching capabilities.
```heex
<:col :let={user} field="name" filter sort search>{user.name}
<:col :let={user} field="email" filter>{user.email}
<:col :let={user} field="created_at" sort>{user.created_at}
```
--------------------------------
### HTML with Data Attributes for Theming
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theming.md
Example HTML structure showing `data-key` attributes that correspond to Cinder theme properties.
```html
Name
```
--------------------------------
### Using Theme Modules Directly
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theme-showcase.md
Alternatively, you can reference theme modules directly when applying themes, providing more flexibility for custom or complex theme setups.
```elixir
# Or use theme modules directly
theme={Cinder.Themes.Modern}
theme={MyApp.CustomTheme}
```
--------------------------------
### Filter Slot Attributes Example
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
This example demonstrates the various attributes available for filter slots, including required, optional, and type-specific parameters for different filter types.
```heex
<:filter
field="field_name" # Required
type="filter_type" # Optional, auto-detected if not provided
label="Custom Label" # Optional
options={[...]} # For select/multi-select
placeholder="..." # For text filters
operator={:contains} # For text filters
case_sensitive={true} # For text filters
match_mode={:any} # For multi-select
min={0} # For number range
max={100} # For number range
step={1} # For number range
include_time={true} # For date range
fn={&custom_filter/2} # Custom filter function
/>
```
--------------------------------
### Add Cinder Dependency to mix.exs
Source: https://github.com/sevenseacat/cinder/blob/main/README.md
Manual installation step to add Cinder as a project dependency in your `mix.exs` file.
```elixir
def deps do
[{:cinder, "~> 0.9"}]
end
```
--------------------------------
### Setup URL State Management in LiveView
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Integrate Cinder.UrlSync into your LiveView to synchronize collection state with the browser URL. This allows for bookmarkable and shareable views.
```elixir
defmodule MyAppWeb.UsersLive do
use MyAppWeb, :live_view
use Cinder.UrlSync
def mount(_params, _session, socket) do
{:ok, assign(socket, :current_user, get_current_user(socket))}
end
def handle_params(params, uri, socket) do
socket = Cinder.UrlSync.handle_params(params, uri, socket)
{:noreply, socket}
end
def render(assigns) do
~H"""
<:col :let={user} field="name" filter sort>{user.name}
<:col :let={user} field="email" filter>{user.email}
<:col :let={user} field="is_active" filter={:boolean}>
{if user.is_active, do: "Active", else: "Inactive"}
"""
end
end
```
--------------------------------
### Grid Layout Collection with Custom Item Template
Source: https://github.com/sevenseacat/cinder/blob/main/README.md
Example of using Cinder for a grid layout with a specified number of columns. Includes a custom item template for rendering each product.
```heex
<:col field="name" filter sort />
<:item :let={product}>
{product.name}
```
--------------------------------
### Dynamic Filter Options Rendering
Source: https://github.com/sevenseacat/cinder/blob/main/docs/custom-filters.md
Example of a render function that fetches filter options dynamically from a database or context before rendering the filter UI.
```elixir
def render(column, current_value, theme, assigns) do
# Get options from database or context
options = get_dynamic_options(column.field, assigns)
assigns = Map.put(assigns, :dynamic_options, options)
# ... render with dynamic options
end
```
--------------------------------
### Cinder Collection Component Example
Source: https://context7.com/sevenseacat/cinder/llms.txt
Use the Cinder.collection component to display a paginated and filterable list of resources. Allows per-component override of page size and query options.
```heex
<%!-- Per-component override with user-selectable sizes --%>
<:col :let={user} field="name" filter sort>{user.name}
<:col :let={user} field="department.name">{user.department.name}
```
--------------------------------
### Number Range Filter Examples
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
Use number range filters with Min/Max inputs for numeric filtering. The first example auto-detects for integer/decimal fields, and the second includes constraints for min, max, and step.
```heex
<:col :let={product} field="price" filter sort>{product.price}
```
```heex
<:col
:let={product}
field="quantity"
filter={[type: :number_range, min: 0, max: 10000, step: 10]}>
{product.quantity}
```
--------------------------------
### Extend and Override Theme Properties
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theme-showcase.md
Inherit from an existing theme like `:retro` and override specific properties to create a new theme. This example darkens the retro theme and adds green accents.
```elixir
defmodule MyApp.DarkRetro do
use Cinder.Theme
extends :retro
# Table - Keep retro styling but make it even darker
set :container_class, "bg-black border-4 border-green-400 shadow-green-400/50"
set :th_class, "px-6 py-4 text-green-100 font-bold bg-green-900 border-b-4 border-green-400"
end
```
--------------------------------
### Slider Filter Module Documentation
Source: https://github.com/sevenseacat/cinder/blob/main/docs/custom-filters.md
Provides documentation for a custom Slider filter module, detailing its purpose, available options (min, max, step, operator), and a usage example.
```elixir
defmodule MyApp.Filters.Slider do
@moduledoc """
Slider filter for numeric range filtering.
## Options
- `:min` - Minimum value (default: 0)
- `:max` - Maximum value (default: 100)
- `:step` - Step increment (default: 1)
- `:operator` - Comparison operator (default: :equals)
## Usage
%{
field: "price",
filter: :slider,
filter_options: [min: 0, max: 1000, step: 50, operator: :less_than_or_equal]
}
"""
use Cinder.Filter
# ... implementation
end
```
--------------------------------
### Table Layout Cinder Collection
Source: https://github.com/sevenseacat/cinder/blob/main/docs/getting-started.md
The default table layout provides a traditional HTML table with sortable column headers. This example is identical to the minimal collection but explicitly shows the default layout.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:col :let={user} field="email" filter>{user.email}
```
--------------------------------
### Enable Keyset Pagination
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Use keyset pagination for large datasets, offering faster performance than offset pagination.
```heex
...
```
--------------------------------
### Collapsible Filters - Per Component
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
Configure individual Cinder collections to have collapsible filters. The `show_filters` attribute can be set to `:toggle` for filters that start collapsed, or `:toggle_open` to start expanded.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:col :let={user} field="email" filter>{user.email}
<:col :let={user} field="status" filter={:select}>{user.status}
...
```
--------------------------------
### Initialize Cinder in Elixir Application
Source: https://github.com/sevenseacat/cinder/blob/main/docs/custom-filters.md
Ensure Cinder is set up during your application's startup by calling `Cinder.setup()`. This integrates configured custom filters into the Cinder framework.
```elixir
defmodule MyApp.Application do
use Application
def start(_type, _args) do
# Set up Cinder with configured filters
Cinder.setup()
children = [
# your supervisors...
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
```
--------------------------------
### Checkbox Filter Examples
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
Use checkbox filters for boolean fields or to filter by a specific value when checked. The first example filters for true when checked, while the second filters for 'high' priority.
```heex
<:col :let={article} field="published" filter={[type: :checkbox, label: "Published only"]}>
{if article.published, do: "✓", else: "✗"}
```
```heex
<:col :let={article} field="priority" filter={[type: :checkbox, value: "high", label: "High priority only"]}>
{article.priority}
```
--------------------------------
### Cinder Layouts: Table, List, and Grid
Source: https://github.com/sevenseacat/cinder/blob/main/usage-rules.md
Illustrates how to configure different layouts for Cinder collections, including the default table layout, a list layout, and a grid layout with customizable columns.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:col field="name" filter sort />
<:item :let={user}>
```
--------------------------------
### Text Filter with Custom Placeholder
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
Customize the placeholder text for text filters to guide user input.
```heex
<:col
:let={article}
field="content"
filter={[type: :text, placeholder: "Search content..."]}
>
{String.slice(article.content, 0, 100)}...
```
--------------------------------
### Collection with Pre-filtered Query and Keyset Pagination
Source: https://context7.com/sevenseacat/cinder/llms.txt
Use this snippet when you need to display a pre-filtered set of resources. It also demonstrates how to configure keyset pagination for efficient data retrieval.
```heex
<%!-- With pre-filtered query and keyset pagination --%>
Ash.Query.filter(active: true)}
actor={@current_user}
pagination={:keyset}
page_size={50}
>
<:col :let={user} field="name" filter sort>{user.name}
```
--------------------------------
### Grid Layout with Responsive Columns
Source: https://context7.com/sevenseacat/cinder/llms.txt
Implement a grid layout for displaying resources. Control the number of columns across different screen sizes using `grid_columns`. Supports filtering and custom item rendering.
```heex
<%!-- Grid layout with responsive columns --%>
<:col field="name" filter sort search />
<:col field="category" filter={:select} />
<:item :let={product}>
{product.name}
${product.price}
```
--------------------------------
### Run Cinder Upgrade Task
Source: https://github.com/sevenseacat/cinder/blob/main/docs/upgrading.md
Execute the `mix cinder.upgrade` task to automatically convert your theme files from the old `component/2` syntax to the new flat `set` calls.
```bash
mix cinder.upgrade 0.8.1 0.9.0
```
--------------------------------
### Collection with Multi-Tenant Admin Query
Source: https://github.com/sevenseacat/cinder/blob/main/docs/getting-started.md
Configure collections for multi-tenant environments using the `query` attribute and specifying a `tenant`.
```heex
...
```
--------------------------------
### Using String Theme Presets
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theme-showcase.md
Apply built-in themes directly using their string names. This is a convenient way to quickly switch between predefined styles.
```elixir
# String preset names
theme="default" # Minimal unstyled
theme="modern" # Professional blue theme
theme="retro" # 80s cyberpunk neon
theme="futuristic" # Sci-fi holographic
theme="dark" # Elegant dark mode
theme="daisy_ui" # daisyUI compatibility
theme="flowbite" # Flowbite compatibility
theme="compact" # High-density minimal
```
--------------------------------
### Load Specific Data with query_opts
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Use `query_opts` to specify which related data to load and which fields to select for efficient data retrieval.
```heex
...
```
--------------------------------
### Configurable Filter Options in Column Definition
Source: https://github.com/sevenseacat/cinder/blob/main/docs/custom-filters.md
Example of a column definition specifying a slider filter with custom options like min, max, step, and operator.
```elixir
%{
field: "score",
filter: :slider,
filter_options: [
min: 0,
max: 1000,
step: 10,
operator: :less_than_or_equal
]
}
```
--------------------------------
### Configure User-Selectable Page Size
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Allow users to select their preferred page size from a list of options.
```heex
...
```
--------------------------------
### Add Action Column with Custom Links and Buttons
Source: https://github.com/sevenseacat/cinder/blob/main/docs/getting-started.md
Create action columns without a `field` to include custom content like navigation links and buttons for performing actions.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:col :let={user} field="email" filter>{user.email}
<:col :let={user} label="Actions">
```
--------------------------------
### Configure Custom Filters in Elixir
Source: https://github.com/sevenseacat/cinder/blob/main/docs/custom-filters.md
Add custom filters to your Cinder application by listing their module names in the application configuration. This example shows how to register a slider filter.
```elixir
config :cinder, :filters, [
slider: MyApp.Filters.Slider,
color_picker: MyApp.Filters.ColorPicker,
date_picker: MyApp.Filters.DatePicker
]
```
--------------------------------
### Define a Custom Theme with DSL
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theme-showcase.md
Use Cinder.Theme and the `set` macro to define custom styles for components like tables and filters. Extend existing themes using `extends`.
```elixir
defmodule MyApp.CustomTheme do
use Cinder.Theme
extends :modern
# Table
set :container_class, "bg-gradient-to-r from-purple-900 to-blue-900 rounded-2xl shadow-2xl"
set :th_class, "px-6 py-4 text-yellow-300 font-bold uppercase tracking-widest"
set :row_class, "border-b border-purple-500/30 hover:bg-purple-800/50"
# Filters
set :filter_container_class, "bg-black border-2 border-yellow-400 p-6 rounded-lg"
set :filter_text_input_class, "bg-gray-900 border-yellow-400 text-yellow-100"
end
```
```html
<:col field="name" />
```
--------------------------------
### Filter-Only Slots Example
Source: https://github.com/sevenseacat/cinder/blob/main/docs/filters.md
Use filter-only slots to add filtering UI without displaying columns. This is useful for filtering by metadata or keeping tables focused on essential information.
```heex
<:col :let={order} field="order_number">{order.order_number}
<:col :let={order} field="total">${order.total}
<:filter field="created_at" type="date_range" label="Order Date" />
<:filter field="status" type="select" options={["pending", "shipped", "delivered"]} />
<:filter field="customer_name" type="text" placeholder="Customer name..." />
```
--------------------------------
### Handle Bulk Action Callbacks in LiveView
Source: https://github.com/sevenseacat/cinder/blob/main/usage-rules.md
Implement `handle_info` callbacks in your LiveView to process success or failure events from bulk actions, allowing you to display feedback to the user.
```elixir
def handle_info({:deleted, %{count: count}}, socket) do
{:noreply, put_flash(socket, :info, "Deleted #{count} users")}
end
def handle_info({:delete_failed, %{reason: reason}}, socket) do
{:noreply, put_flash(socket, :error, "Failed: #{inspect(reason)}")}
end
```
--------------------------------
### Define Custom Bulk Actions
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Provide inner content for `bulk_action` slots for complete control over button rendering.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:bulk_action action={:archive} :let={context}>
<:bulk_action action={:destroy} confirm="Delete {count} users?">
```
--------------------------------
### Table Layout with Filters, Sorting, and Search
Source: https://context7.com/sevenseacat/cinder/llms.txt
Use this snippet to display data in a table format. It supports column-specific filtering, sorting, and searching. Configure pagination with `page_size`.
```heex
<%!-- Table layout with filters, sorting, and search --%>
<:col :let={user} field="name" filter sort search>{user.name}
<:col :let={user} field="email" filter>{user.email}
<%!-- Auto-detects enum → select filter --%>
<:col :let={user} field="role" filter sort>{user.role}
<%!-- Relationship field via dot notation --%>
<:col :let={user} field="department.name" filter sort>{user.department.name}
<%!-- Embedded resource via double-underscore --%>
<:col :let={user} field="profile__country" filter>{user.profile.country}
<%!-- Action column: no field required --%>
<:col :let={user} label="Actions">
<.link navigate={~p"/users/#{user.id}"}>View
```
--------------------------------
### Cinder Column Configuration: Sorting
Source: https://github.com/sevenseacat/cinder/blob/main/usage-rules.md
Demonstrates basic sorting and custom sort cycles for Cinder columns. Basic sorting cycles through nil, ascending, and descending.
```heex
<:col field="name" sort />
<:col field="priority" sort={[cycle: [:desc, :asc]]} />
<:col field="created_at" sort={[cycle: [:desc, :asc, nil]]} />
```
--------------------------------
### Filter Options Based on Dependencies
Source: https://github.com/sevenseacat/cinder/blob/main/docs/custom-filters.md
Demonstrates how a filter's rendering can adapt its options based on the values of other filters present in the assigns.
```elixir
def render(column, current_value, theme, assigns) do
# Access other filter values
category_filter = get_in(assigns, [:filters, "category"])
# Adjust options based on other filters
options = get_options_for_category(category_filter)
# ... render
end
```
--------------------------------
### Configure Custom Filters in Cinder
Source: https://context7.com/sevenseacat/cinder/llms.txt
Register custom filter modules in your application's configuration file (`config/config.exs`). Ensure `Cinder.setup()` is called in your application's start function to register these filters.
```elixir
# config/config.exs
config :cinder, :filters, [
slider: MyApp.Filters.Slider,
color_picker: MyApp.Filters.ColorPicker
]
# lib/my_app/application.ex
defmodule MyApp.Application do
use Application
def start(_type, _args) do
Cinder.setup() # registers all configured custom filters, returns :ok
children = [MyAppWeb.Endpoint]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
end
```
--------------------------------
### Customize Sort Cycles
Source: https://github.com/sevenseacat/cinder/blob/main/docs/sorting.md
Customize the sort cycle for a column using the `cycle` option within the `sort` attribute. This allows for different sequences, including omitting the neutral state or starting with a specific direction.
```heex
<:col field="name" sort={[cycle: [:asc, :desc]]} />
```
```heex
<:col field="created_at" sort={[cycle: [:desc, :asc, nil]]} />
```
```heex
<:col field="completed_at" sort={[cycle: [:desc_nils_last, :asc_nils_first, nil]]} />
```
--------------------------------
### Passing Additional Ash Bulk Options
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Provide extra Ash bulk options, such as `return_records?` and `notify?`, using the `action_opts` attribute.
```heex
<:bulk_action action={:archive} action_opts={[return_records?: true, notify?: true]}>
Archive Selected
```
--------------------------------
### Override Cinder Gettext Strings
Source: https://context7.com/sevenseacat/cinder/llms.txt
Override default Cinder strings by providing custom translations in your application's Gettext catalog. Example shows overrides for 'Filters', 'Loading...', and 'No results found'.
```po
# priv/gettext/en/LC_MESSAGES/cinder.po — override specific strings
msgid "Filters"
msgstr "Refine"
msgid "Loading..."
msgstr "Please wait..."
msgid "No results found"
msgstr "Nothing here yet"
```
--------------------------------
### Migrate Custom Theme Keys
Source: https://context7.com/sevenseacat/cinder/llms.txt
Run the `mix cinder.upgrade` task to migrate custom theme keys after a breaking upgrade, ensuring compatibility with new Cinder versions.
```bash
# Migrate custom theme keys after a breaking upgrade
# (e.g., filter_boolean_* → filter_radio_group_* in 0.9.1→0.10.0)
mix cinder.upgrade 0.9.1 0.10.0
```
--------------------------------
### Add Click Handler to Collection Rows
Source: https://github.com/sevenseacat/cinder/blob/main/docs/getting-started.md
Use the `click` attribute to make rows or items clickable. The function receives the record and returns a JS command. Rows with click handlers get automatic hover effects.
```heex
JS.navigate(~p"/users/#{user.id}") end}
>
<:col :let={user} field="name" filter sort>{user.name}
<:col :let={user} field="email">{user.email}
```
--------------------------------
### Define a Custom Slider Filter in Elixir
Source: https://github.com/sevenseacat/cinder/blob/main/docs/custom-filters.md
Implement a custom slider filter for numeric values. This example shows how to define the rendering logic, process input, validate values, set default options, and build queries for filtering.
```elixir
defmodule MyApp.Filters.Slider do
@moduledoc """
A range slider filter for numeric values.
Provides a visual slider interface for filtering numeric columns
with configurable min, max, and step values.
"""
use Cinder.Filter
@impl true
def render(column, current_value, theme, assigns) do
filter_options = Map.get(column, :filter_options, [])
min_value = get_option(filter_options, :min, 0)
max_value = get_option(filter_options, :max, 100)
step_value = get_option(filter_options, :step, 1)
current = current_value || min_value
assigns = %{
column: column,
current_value: current,
min_value: min_value,
max_value: max_value,
step_value: step_value,
theme: theme
}
~H"""
{@min_value}{@max_value}
"""
end
@impl true
def process(raw_value, column) when is_binary(raw_value) do
case Integer.parse(raw_value) do
{value, ""} ->
filter_options = Map.get(column, :filter_options, [])
operator = get_option(filter_options, :operator, :equals)
%{
type: :slider,
value: value,
operator: operator
}
_ -> nil
end
end
def process(_raw_value, _column), do: nil
@impl true
def validate(%{type: :slider, value: value, operator: operator})
when is_integer(value) and is_atom(operator) do
operator in [:equals, :greater_than, :less_than, :greater_than_or_equal, :less_than_or_equal]
end
def validate(_), do: false
@impl true
def default_options do
[
min: 0,
max: 100,
step: 1,
operator: :equals
]
end
@impl true
def empty?(value) do
case value do
nil -> true
%{value: nil} -> true
_ -> false
end
end
@impl true
def build_query(query, field, filter_value) do
%{type: :slider, value: value, operator: operator} = filter_value
# Handle relationship fields using dot notation
if String.contains?(field, ".") do
path_atoms = field |> String.split(".") |> Enum.map(&String.to_atom/1)
{rel_path, [field_atom]} = Enum.split(path_atoms, -1)
case operator do
:equals ->
Ash.Query.filter(query, exists(^rel_path, ^ref(field_atom) == ^value))
:greater_than ->
Ash.Query.filter(query, exists(^rel_path, ^ref(field_atom) > ^value))
:greater_than_or_equal ->
Ash.Query.filter(query, exists(^rel_path, ^ref(field_atom) >= ^value))
:less_than ->
Ash.Query.filter(query, exists(^rel_path, ^ref(field_atom) < ^value))
:less_than_or_equal ->
Ash.Query.filter(query, exists(^rel_path, ^ref(field_atom) <= ^value))
_ ->
query
end
else
# Direct field filtering
field_atom = String.to_atom(field)
case operator do
:equals ->
Ash.Query.filter(query, ^ref(field_atom) == ^value)
:greater_than ->
Ash.Query.filter(query, ^ref(field_atom) > ^value)
:greater_than_or_equal ->
Ash.Query.filter(query, ^ref(field_atom) >= ^value)
:less_than ->
Ash.Query.filter(query, ^ref(field_atom) < ^value)
:less_than_or_equal ->
Ash.Query.filter(query, ^ref(field_atom) <= ^value)
_ ->
query
end
end
end
end
```
--------------------------------
### Define Themed Bulk Actions
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Use `label` and `variant` to define automatically styled bulk action buttons that match your theme.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:bulk_action action={:archive} label="Archive ({count})" variant={:primary} />
<:bulk_action action={:export} label="Export" variant={:secondary} />
<:bulk_action action={:destroy} label="Delete" variant={:danger} confirm="Delete {count} users?" />
```
--------------------------------
### Grid Layout with Responsive Columns
Source: https://github.com/sevenseacat/cinder/blob/main/docs/getting-started.md
Define responsive column counts for a grid layout using `grid_columns` with a map of breakpoints and column numbers. Available breakpoints include `xs`, `sm`, `md`, `lg`, `xl`, `2xl`.
```heex
...
```
--------------------------------
### Setting All Theme Properties
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theming.md
This snippet demonstrates how to set various CSS class names for different UI components to customize their appearance. Use these properties to control spacing, colors, borders, and other visual aspects.
```elixir
set :bulk_actions_container_class, "p-4 bg-white border border-gray-200 rounded-lg shadow-sm flex gap-2 justify-end"
set :button_class, "px-3 py-1.5 text-sm font-medium rounded"
set :button_danger_class, "bg-red-600 text-white hover:bg-red-700"
set :button_disabled_class, "opacity-50 cursor-not-allowed"
set :button_primary_class, "bg-blue-600 text-white hover:bg-blue-700"
set :button_secondary_class, "border border-gray-300 text-gray-700 hover:bg-gray-50"
set :container_class, ""
set :controls_class, ""
set :empty_class, "text-center py-4"
set :error_container_class, "text-red-600 text-sm"
set :error_message_class, ""
set :filter_checkbox_container_class, ""
set :filter_checkbox_input_class, ""
set :filter_checkbox_label_class, ""
set :filter_clear_all_class, ""
set :filter_clear_button_class, ""
set :filter_container_class, ""
set :filter_count_class, ""
set :filter_date_input_class, ""
set :filter_header_class, ""
set :filter_input_wrapper_class, ""
set :filter_inputs_class, ""
set :filter_label_class, ""
set :filter_multicheckboxes_checkbox_class, ""
set :filter_multicheckboxes_container_class, ""
set :filter_multicheckboxes_label_class, ""
set :filter_multicheckboxes_option_class, ""
set :filter_multiselect_checkbox_class, ""
set :filter_multiselect_container_class, ""
set :filter_multiselect_dropdown_class, ""
set :filter_multiselect_empty_class, ""
set :filter_multiselect_label_class, ""
set :filter_multiselect_option_class, ""
set :filter_number_input_class, "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [-moz-appearance:textfield]"
set :filter_radio_group_container_class, ""
set :filter_radio_group_label_class, ""
set :filter_radio_group_option_class, ""
set :filter_radio_group_radio_class, ""
set :filter_range_container_class, ""
set :filter_range_input_group_class, ""
set :filter_range_separator_class, "flex items-center px-2 text-sm text-gray-500"
set :filter_select_arrow_class, "w-4 h-4 ml-2 flex-shrink-0"
set :filter_select_container_class, ""
set :filter_select_dropdown_class, ""
set :filter_select_empty_class, ""
set :filter_select_input_class, ""
set :filter_select_label_class, ""
set :filter_select_option_class, ""
set :filter_select_placeholder_class, "text-gray-400"
set :filter_text_input_class, ""
set :filter_title_class, ""
set :filter_toggle_class, "cursor-pointer select-none inline-flex items-center gap-1"
set :filter_toggle_icon_class, "w-4 h-4"
set :grid_container_class, "grid gap-4"
set :grid_item_class, "p-4 bg-white border border-gray-200 rounded-lg shadow-sm"
set :grid_item_clickable_class, "cursor-pointer hover:shadow-md transition-shadow"
set :grid_selection_overlay_class, "mb-2"
set :header_row_class, ""
set :list_container_class, "divide-y divide-gray-200"
set :list_item_class, "py-3 px-4 text-gray-900"
set :list_item_clickable_class, "cursor-pointer hover:bg-gray-50 transition-colors"
set :list_selection_container_class, "mb-2"
set :loading_container_class, ""
set :loading_overlay_class, ""
set :loading_spinner_circle_class, ""
set :loading_spinner_class, ""
set :loading_spinner_path_class, ""
set :page_size_container_class, ""
set :page_size_dropdown_class, ""
set :page_size_dropdown_container_class, ""
set :page_size_label_class, ""
set :page_size_option_class, ""
set :page_size_selected_class, ""
set :pagination_button_class, ""
set :pagination_container_class, ""
set :pagination_count_class, ""
set :pagination_current_class, ""
set :pagination_info_class, ""
set :pagination_nav_class, ""
set :pagination_wrapper_class, ""
set :row_class, ""
set :search_icon_class, "w-4 h-4"
set :search_input_class, "w-full px-3 py-2 border rounded"
set :selected_item_class, "ring-2 ring-blue-500"
set :selected_row_class, "bg-blue-50"
set :selection_checkbox_class, "w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
set :sort_arrow_wrapper_class, "inline-flex items-center"
set :sort_asc_icon, "↑"
set :sort_asc_icon_class, "w-3 h-3"
set :sort_asc_icon_name, "hero-chevron-up"
set :sort_button_active_class, "bg-blue-50 border-blue-300 text-blue-700"
set :sort_button_class, "px-3 py-1 text-sm border rounded transition-colors"
set :sort_button_inactive_class, "bg-white border-gray-300 hover:bg-gray-50"
set :sort_buttons_class, "flex gap-1"
set :sort_container_class, "bg-white border border-gray-200 rounded-lg shadow-sm mt-4"
set :sort_controls_class, "flex items-center gap-2 p-4"
set :sort_controls_label_class, "text-sm text-gray-600 font-medium"
set :sort_desc_icon, "↓"
set :sort_desc_icon_class, "w-3 h-3"
set :sort_desc_icon_name, "hero-chevron-down"
set :sort_icon_class, "ml-1"
set :sort_indicator_class, "ml-1 inline-flex items-center align-baseline"
set :sort_none_icon_class, "w-3 h-3 opacity-50"
set :sort_none_icon_name, "hero-chevron-up-down"
set :table_class, "w-full border-collapse"
set :table_wrapper_class, "overflow-x-auto"
set :tbody_class, ""
set :td_class, ""
```
--------------------------------
### Configure Fixed Page Size
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Set a fixed page size for collections using the `page_size` attribute.
```heex
...
```
--------------------------------
### Workflow for Updating Theme Properties
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theming.md
Illustrates a typical workflow using browser developer tools to identify a theme property via `data-key` and then update it in the theme configuration.
```bash
# 1. Inspect element in browser
# 2. Update your theme
set :filter_text_input_class, "w-full px-4 py-3 border-2 border-blue-500 rounded-lg"
# 3. Refresh to see changes
```
--------------------------------
### Define a Custom Cinder Theme Module
Source: https://github.com/sevenseacat/cinder/blob/main/docs/getting-started.md
Create a custom theme by defining a module that uses Cinder.Theme and setting various styling properties.
```elixir
defmodule MyApp.Theme.Corporate do
use Cinder.Theme
# Table
set :container_class, "bg-white shadow-lg rounded-lg border border-gray-200"
set :th_class, "px-6 py-4 bg-blue-50 text-left font-semibold text-blue-900"
set :td_class, "px-6 py-4 border-b border-gray-100"
set :row_class, "hover:bg-blue-50 transition-colors"
# Filters
set :filter_container_class, "bg-gray-50 p-4 rounded-lg mb-4"
set :filter_text_input_class, "w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500"
# Pagination
set :pagination_button_class, "px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
end
```
--------------------------------
### Define Custom Theme Module
Source: https://github.com/sevenseacat/cinder/blob/main/docs/theming.md
Create a custom theme by defining a module that uses `Cinder.Theme` and setting CSS classes with the `set` function. This allows for reusable and complex styling.
```elixir
defmodule MyApp.CustomTheme do
use Cinder.Theme
set :container_class, "bg-white shadow-lg rounded-lg border"
set :th_class, "px-6 py-4 bg-gray-50 font-semibold text-gray-900"
set :row_class, "hover:bg-gray-50 transition-colors"
end
```
--------------------------------
### Function Actions with Pre-filtered Queries
Source: https://github.com/sevenseacat/cinder/blob/main/docs/advanced.md
Employ Function actions to receive a pre-filtered query that matches specific code interface signatures.
```heex
<:bulk_action action={&MyApp.Users.archive/2}>Archive
```
--------------------------------
### Switch from Pastel Theme
Source: https://github.com/sevenseacat/cinder/blob/main/docs/upgrading.md
If you were using the removed `pastel` theme, switch to an available alternative like `modern` or create a custom theme with similar styling.
```elixir
# If you were using pastel, switch to another theme
theme="modern" # or any other available theme
```
--------------------------------
### Enable Selection and Bulk Actions in Cinder Collections
Source: https://github.com/sevenseacat/cinder/blob/main/usage-rules.md
Configure Cinder collections to be selectable and define bulk actions using themed or custom buttons. Themed buttons use `label` and `variant` for automatic styling.
```heex
<:col :let={user} field="name" filter sort>{user.name}
<:bulk_action action={:archive} label="Archive ({count})" variant={:primary} />
<:bulk_action action={:export} label="Export" variant={:secondary} />
<:bulk_action action={:destroy} label="Delete" variant={:danger} confirm="Delete {count}?" />
<:bulk_action action={&MyApp.Users.soft_delete/2} on_success={:deleted} :let={ctx}>
```
--------------------------------
### Enable Bookmarkable URL States with UrlSync
Source: https://github.com/sevenseacat/cinder/blob/main/usage-rules.md
Integrate Cinder.UrlSync into your LiveView to manage URL parameters for bookmarkable and shareable collection states.
```elixir
defmodule MyAppWeb.UsersLive do
use MyAppWeb, :live_view
use Cinder.UrlSync
def handle_params(params, uri, socket) do
socket = Cinder.UrlSync.handle_params(params, uri, socket)
{:noreply, socket}
end
def render(assigns) do
~H"""
<:col :let={user} field="name" filter sort>{user.name}
"""
end
end
```