MoonShine Admin Panel

repository·4.x·Indexed 23 days ago

https://github.com/moonshine-software/moonshine

An AI-enhanced administration panel for Laravel (10+) and PHP (8.2+). It features a framework-agnostic core, deep design customization with 20+ themes, and mobile integration via a Telegram Mini App. Key tools include Forty-Five for AI-generated CRUD pages and MoonVibe for panel generation. The system provides a comprehensive set of CRUD routes, a marketplace of 50+ solutions, and a flexible component system for building reusable UI elements and custom dashboard layouts.

Tokens
63.2K
Snippets
139
Records
228
Agent score
79%

What's inside MoonShine

  1. Overview of MoonShine Admin Panel

    4.x

    MoonShine is a modern administration panel designed for the Laravel framework, though its core CRUD logic is decoupled from the framework, allowing for potential use with Symfony, Yii, or other systems. It is built to be highly customizable, AI-assisted, and mobile-friendly.

    Key Features:

    • AI-Assisted Development: Uses tools like Forty-Five (AI assistant for generating CRUD pages via prompts) and MoonVibe (admin panel generator).
    • Design Flexibility: Supports 20+ ready-made themes and a palette generator to match any brand identity.
    • Mobile Management: Includes a Telegram Mini App that provides a native-app experience for managing projects via Telegram.
    • Extensibility: Offers a marketplace with 50+ ready-made solutions such as file managers, role systems, two-factor authentication, and visual editors.
    • Layout Freedom: Allows for significant UI adjustments, including multiple sidebars and custom dashboard layouts.
  2. Build MoonShine admin panel UI with Blade components

    4.x

    MoonShine provides a library of Blade components to build admin interfaces, including tables, forms, cards, modals, navigation, and page layouts. These components are designed to work with Laravel and require the MoonShine 4.x package to be installed.

    Core Implementation Rules

    • Layout Entry Point: Always start your Blade files with <x-moonshine::layout>. Do not use standard HTML tags like <!DOCTYPE html>.
    • Avoid HTML Duplication: MoonShine components generate their own HTML structure; do not wrap them in redundant tags that duplicate their internal structure.
    • CSS Wrappers: Every component requires specific CSS wrapper classes to render correctly. Always refer to the component documentation for the required wrapper.
    • Assets: Ensure MoonShine assets are included in your project for proper styling and functionality.
  3. Understand Field Contexts: FormBuilder vs TableBuilder

    4.x

    MoonShine fields automatically switch between two modes depending on where they are used:

    FormBuilder (Default Mode)

    Used in interactive forms where users enter data. The field renders as an input element (e.g., <input>, <select>). The value used here is determined by resolveValue().

    TableBuilder (Preview Mode)

    Used in read-only tables to display data. The field renders formatted values, badges, or images. The display is determined by resolvePreview().

    By implementing both methods, you control how the field behaves during data entry versus how it looks in a list view.

  4. How MoonShine components work

    4.x

    MoonShine components are used for display and UI decoration only. Unlike Fields, components do not save data, do not have input modes (default/preview/raw), and do not receive automatic system data.

    Use components for:

    • Dashboard widgets and stats cards
    • UI decoration (headers, footers, alerts, badges)
    • Layout elements (breadcrumbs, menus)
    • Grouping other components

    Use Fields when:

    • User input is required
    • Data needs to be saved to a database
  5. How to use MoonShine icons

    4.x

    MoonShine uses Heroicons for all icon displays. You can find the full list of available icons at https://heroicons.com/.

    To use an icon, pass the name to the icon attribute using the following naming conventions to select the style:

    • Outline (Default): Use the name as-is (e.g., icon="users").
    • Solid: Prefix with s. (e.g., icon="s.users").
    • Mini: Prefix with m. (e.g., icon="m.users").
    • Micro: Prefix with c. (e.g., icon="c.users").
  6. Handle multiple instances of the same field on one page

    4.x

    To prevent ID conflicts and script initialization errors when multiple fields of the same type appear on a single page (e.g., in a list or complex form), follow these principles:

    1. Generate Unique IDs: Use uniqid() or the field's actual id attribute to create unique identifiers for DOM elements.
    2. Pass Config to Alpine: Instead of relying on global state, pass configuration (including the unique ID) directly into the Alpine.js component via x-data.
    3. Instance-based Initialization: Ensure each field instance manages its own state and DOM elements using the unique ID.
    <div
        x-data="yandexMap({
            lat: {{ $value['lat'] ?? $defaultLat }},
            lng: {{ $value['lng'] ?? $defaultLng }},
            fieldId: '{{ $attributes->get('id', 'field-' . uniqid()) }}'
        })"
        {{ $attributes->except(['name']) }}
        x-init="initMap()"
    >
        <div :id="fieldId" class="map-container"></div>
        <input type="hidden" {{ $attributes->only(['name']) }} x-model="coordinates" />
    </div>
  7. Customize mobile navigation with MobileBar

    4.x

    The <x-moonshine::layout.mobile-bar> component allows you to define a custom dropdown menu specifically for mobile devices. This is useful if your mobile navigation should differ from your desktop TopBar or Sidebar.

    Rules for MobileBar:

    • Placement: Must be placed above the Sidebar and TopBar in the layout structure.
    • Structure: Uses the same CSS wrappers as TopBar (menu-logo, menu menu--horizontal, menu-actions, menu-burger).
    • Burger: The <x-moonshine::layout.burger> component inside a MobileBar must have the mobile-bar attribute.
    • Default Behavior: If omitted, the mobile menu will simply duplicate the content of the TopBar or Sidebar.
    <x-moonshine::layout.mobile-bar>
        <x-moonshine::layout.div class="menu-logo">
            <x-moonshine::layout.logo href="/" logo="/logo.svg"/>
        </x-moonshine::layout.div>
    
        <x-moonshine::layout.div class="menu menu--horizontal">
            <x-moonshine::layout.menu
                :elements="[
                    ['label' => 'Home', 'url' => '/'],
                    ['label' => 'Mobile-Only Menu', 'url' => '/mobile']
                ]"
            />
        </x-moonshine::layout.div>
    
        <x-moonshine::layout.div class="menu-burger">
            <x-moonshine::layout.burger mobile-bar />
        </x-moonshine::layout.div>
    </x-moonshine::layout.mobile-bar>
  8. Maintain the Required MoonShine Layout Structure

    4.x

    MoonShine requires a specific nested wrapper structure for proper CSS positioning, sidebar functionality, and mobile responsiveness. Never skip or modify this hierarchy.

    Required Hierarchy

    1. <x-moonshine::layout.wrapper>
    2. <x-moonshine::layout.sidebar> (Optional)
    3. <x-moonshine::layout.div class="layout-main"> (Required)
    4. <x-moonshine::layout.div class="layout-page"> (Required)
    5. <x-moonshine::layout.header> and <x-moonshine::layout.content>

    Common Implementation Patterns

    Sidebar Layout (Standard): Use this when you want a vertical navigation menu.

    TopBar Layout (No Sidebar): Use this when you want navigation at the top of the page instead of a sidebar.

    {{-- Sidebar Layout --}}
    <x-moonshine::layout.wrapper>
        <x-moonshine::layout.sidebar>
            <!-- Sidebar navigation -->
        </x-moonshine::layout.sidebar>
    
        <x-moonshine::layout.div class="layout-main">
            <x-moonshine::layout.div class="layout-page">
                <x-moonshine::layout.header>
                    <x-moonshine::breadcrumbs :items="['/' => 'Home']" />
                </x-moonshine::layout.header>
                <x-moonshine::layout.content>
                    <!-- Content -->
                </x-moonshine::layout.content>
            </x-moonshine::layout.div>
        </x-moonshine::layout.div>
    </x-moonshine::layout.wrapper>
    
    {{-- TopBar Layout --}}
    <x-moonshine::layout.wrapper>
        <x-moonshine::layout.top-bar>
            <!-- Top navigation -->
        </x-moonshine::layout.top-bar>
    
        <x-moonshine::layout.div class="layout-main">
            <x-moonshine::layout.div class="layout-page">
                <x-moonshine::layout.header>
                    <!-- Page header -->
                </x-moonshine::layout.header>
                <x-moonshine::layout.content>
                    <!-- Content -->
                </x-moonshine::layout.content>
            </x-moonshine::layout.div>
        </x-moonshine::layout.div>
    </x-moonshine::layout.wrapper>
  9. Component Class Anatomy

    4.x

    A standard MoonShine component class consists of:

    • protected string $view: The path to the Blade template.
    • __construct(): Initializes properties with default values.
    • Fluent methods: Methods that set properties and return static.
    • viewData(): Returns an associative array of data to be used in the Blade view.
    • prepareBeforeRender(): (Optional) Used to perform logic or prepare data before the view is rendered.
  10. Configure Sidebar, TopBar, and MobileBar navigation

    4.x

    MoonShine layouts use specific component structures for different navigation types.

    A Sidebar must include the following components in order:

    • menu-header
    • menu-logo
    • menu-actions
    • menu-burger
    • menu with the attribute menu--vertical

    TopBar Requirements

    A TopBar must include:

    • menu-logo
    • menu with the attribute menu--horizontal (or :top="true")
    • menu-actions
    • menu-burger

    MobileBar Requirements

    The MobileBar is optional and follows the same structure as the TopBar. It must be placed above the Sidebar or TopBar in the layout hierarchy.

  11. Use the `value()` helper for Closure support

    4.x

    When a component property can accept either a raw value or a Closure (e.g., for dynamic data like fn() => User::count()), you must wrap the property in the value() helper within your viewData() method. This ensures the closure is executed and the resulting value is passed to the Blade template.

    use function MoonShine\UI\Components\Layout\value;
    
    // Inside your MoonShineComponent class
    protected function viewData(): array
    {
        return [
            'text' => value($this->text),
        ];
    }