# GitHub Copilot Instructions - Bongo Asset Package

## Project Context

This is a Laravel-based frontend asset package that provides compiled JavaScript, CSS, and Vue.js components for the admin section of Bongo applications. It centralizes all frontend assets used across 30+ Bongo packages.

**Package**: `bongo/asset`
**Namespace**: `Bongo\Asset`
**Purpose**: Centralized frontend asset compilation and distribution

## Key Technologies

- Laravel Mix 5.x (webpack)
- Vue 2.5.17
- TailwindCSS 1.4.6
- Redactor WYSIWYG
- Axios, jQuery, Moment.js, SweetAlert2

## Architecture Overview

### Service Provider

```php
namespace Bongo\Asset;

use Illuminate\Support\ServiceProvider;

class AssetServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // Publishes compiled assets to Laravel's public directory
        $this->publishes([__DIR__.'/public/' => public_path()], 'bongo:assets');
    }
}
```

**Note**: Unlike other Bongo packages, this does NOT extend `AbstractServiceProvider` - it's a pure asset package.

### Vue Application Entry

**File**: `src/resources/js/backend.js`

```javascript
// Global dependencies
window.$ = window.jQuery = require('jquery');
window._ = require('lodash');
window.moment = require('moment');
window.axios = require('axios');
window.swal = require('sweetalert2');

// Global event bus
window.EventBus = new Vue();

// Global filters, directives, components registered
// Single Vue instance mounted to #app
const app = new Vue({ el: '#app' });
```

## Component Patterns

### Builder Component Pattern

All builder components follow this structure:

```vue
<!-- ParentBuilder.vue -->
<template>
    <div class="builder" v-cloak>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
            <div class="col-span-1">
                <builder-form :current-item="currentItem" :mode="mode"></builder-form>
            </div>
            <div class="col-span-1">
                <div v-if="items && items.length" :class="['has-items', state]">
                    <draggable :list="items" @update="updateSortOrder">
                        <transition-group name="list" tag="div">
                            <builder-item v-for="item in items" :key="item.id" :item="item"></builder-item>
                        </transition-group>
                    </draggable>
                </div>
                <div v-else :class="['no-items', state]">
                    <v-card>
                        <div class="message text-center">{{ message }}</div>
                    </v-card>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import BuilderForm from "./BuilderForm";
import BuilderItem from "./BuilderItem";
import Draggable from 'vuedraggable';

export default {
    components: { BuilderForm, BuilderItem, Draggable },
    props: { endpoint: { type: String, required: true } },
    data() {
        return {
            items: [],
            currentItem: null,
            mode: 'create',
            state: 'loading',
            message: 'Loading...'
        };
    },
    mounted() {
        this.fetchItems();
        EventBus.$on('newItem', this.newItem);
        EventBus.$on('saveItem', this.saveItem);
        EventBus.$on('editItem', this.editItem);
        EventBus.$on('deleteItem', this.deleteItem);
    }
};
</script>
```

**States**: `loading`, `has-items`, `no-items`, `no-results`

**Events**: `newItem`, `saveItem`, `editItem`, `deleteItem`, `updateSortOrder`

### DataTable Component Pattern

```vue
<data-table :endpoint="endpoint" v-slot="{ items, editUrl, viewUrl }">
    <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-3">
        <v-card v-for="item in items" :key="item.id">
            <template slot="left">
                <a :href="viewUrl(item)">{{ item.name }}</a>
            </template>
            <template slot="right">
                <v-button :link="editUrl(item)">Edit</v-button>
            </template>
        </v-card>
    </div>
</data-table>
```

## Global Filters (Use Everywhere)

```javascript
{{ date | date }}                    // "Jan 19th 2026"
{{ 0.15 | percent }}                 // "15%"
{{ 1234.56 | currency }}             // "1,234.56"
{{ text | truncate(50, '...') }}     // Truncate with suffix
{{ text | uppercase }}               // UPPERCASE
{{ text | lowercase }}               // lowercase
{{ text | ucwords }}                 // Title Case
{{ text | plaintext }}               // Replace - and _ with spaces
```

## Global Directives (Form Inputs)

```vue
<input v-uppercase>                  <!-- Force uppercase -->
<input v-alpha>                      <!-- Letters only -->
<input v-numeric>                    <!-- Numbers/decimals only -->
<input v-alphanumeric>               <!-- Letters, numbers, !, *, % -->
<input v-currency>                   <!-- Currency format -->
<input v-date>                       <!-- MM/DD/YYYY format -->
<input v-maxnumber="100">            <!-- Max numeric value -->
<input v-maxchars="50">              <!-- Max character length -->
```

## Global Components

### Layout Components

```vue
<v-container>
    <v-header></v-header>
    <v-sidebar></v-sidebar>
    <v-main>
        <!-- Page content -->
    </v-main>
</v-container>
```

### UI Components

```vue
<v-alert type="success">Message saved!</v-alert>
<v-button link="/url">Click Me</v-button>
<v-card>Content here</v-card>
<v-combobox :options="options" v-model="selected"></v-combobox>
<v-colorpicker v-model="color"></v-colorpicker>
<v-datepicker v-model="date"></v-datepicker>
<v-error :errors="errors" field="name"></v-error>
<v-label>Field Label</v-label>

<dropdown>
    <template slot="trigger">Click Me</template>
    <template slot="content">Dropdown content</template>
</dropdown>

<tabs>
    <tab name="Tab 1">Content 1</tab>
    <tab name="Tab 2">Content 2</tab>
</tabs>
```

### Feature Components

```vue
<!-- Data table with filtering/pagination -->
<data-table endpoint="/api/items"></data-table>

<!-- WYSIWYG editor -->
<editor v-model="content"></editor>

<!-- Code editors -->
<css-editor v-model="css"></css-editor>
<js-editor v-model="js"></js-editor>
<schema-editor v-model="schema"></schema-editor>

<!-- Builders -->
<form-builder endpoint="/api/forms"></form-builder>
<menu-builder endpoint="/api/menus"></menu-builder>
<gallery-builder endpoint="/api/galleries"></gallery-builder>
<image-manager endpoint="/api/images"></image-manager>
<document-manager endpoint="/api/documents"></document-manager>
<estimate-plan-builder endpoint="/api/plans"></estimate-plan-builder>

<!-- File upload -->
<file-uploader endpoint="/api/upload"></file-uploader>

<!-- Preview -->
<preview :url="previewUrl"></preview>
```

## TailwindCSS Custom Theme

### Custom Colors

```javascript
// Primary brand color (green-yellow)
'primary-500'         // #BED62F
'primary-100'         // Lighter
'primary-900'         // Darker

// Greys
'light-500'           // #EEEEEE (very light)
'medium-500'          // #888888 (medium grey)
'dark-500'            // #222222 (very dark)
'dark-alpha'          // rgba(0, 0, 0, 0.8)

// Use throughout for consistency:
bg-primary-500
text-dark-500
border-light-500
```

### Custom Utilities

```css
min-h-0
min-h-1/4
min-h-1/2
min-h-3/4
min-h-full
```

### Font

```css
font-sans  /* Inter var */
```

## Code Style Templates

### New Vue Component

```vue
<template>
    <div class="component-name">
        <!-- Use Tailwind utilities, avoid custom CSS -->
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: "ComponentName",
    props: {
        propName: { type: String, required: false, default: 'default' }
    },
    data() {
        return {
            localState: null
        };
    },
    mounted() {
        // Component initialization
    },
    methods: {
        methodName() {
            // Method implementation
        }
    }
};
</script>
```

### New Global Filter

```javascript
// In src/resources/js/backend.js
Vue.filter('filterName', function (value, arg1, arg2) {
    if (!value) return '';
    // Transform value
    return transformedValue;
});

// Usage
{{ someValue | filterName(arg1, arg2) }}
```

### New Global Directive

```javascript
// In src/resources/js/backend.js
Vue.directive('directiveName', {
    bind: function (el, binding, vnode) {
        el.addEventListener("input", (e) => {
            // Transform input value
            e.target.value = transformedValue;
        });
    }
});

// Usage
<input v-directiveName>
```

### Axios Request Pattern

```javascript
// CSRF and API tokens auto-configured in backend.js
axios.get(endpoint)
    .then(response => {
        this.items = response.data.data;
        this.state = this.items.length ? 'has-items' : 'no-items';
    })
    .catch(error => {
        console.error(error);
        this.state = 'error';
        this.message = 'Failed to load items';
    });
```

### Event Bus Communication

```javascript
// Emit event
EventBus.$emit('eventName', data);

// Listen to event
EventBus.$on('eventName', (data) => {
    // Handle event
});

// Listen once
EventBus.$once('eventName', callback);

// Stop listening
EventBus.$off('eventName', callback);
```

## Build Commands

```bash
# Development
npm run dev          # Single build
npm run watch        # Watch mode

# Production
npm run production   # Optimized build

# Install dependencies
npm install
```

**Note**: Uses `NODE_OPTIONS=--openssl-legacy-provider` for compatibility.

## Testing

```bash
# PHP tests (minimal - mostly frontend)
vendor/bin/phpunit

# Code style
vendor/bin/pint
vendor/bin/pint --test
```

## File Locations

| Purpose | Location |
|---------|----------|
| Service Provider | `src/AssetServiceProvider.php` |
| Vue Entry | `src/resources/js/backend.js` |
| Sass Entry | `src/resources/sass/backend.scss` |
| Build Config | `src/webpack.mix.js` |
| Tailwind Config | `src/tailwind.config.js` |
| Compiled CSS | `src/public/css/backend.css` |
| Compiled JS | `src/public/js/backend.js` |
| Vue Components | `src/resources/js/components/` |
| Layout Components | `src/resources/js/layout/` |
| Vendor JS | `src/resources/js/vendor/` |
| Sass Components | `src/resources/sass/components/` |
| Tests | `tests/` |

## Common Patterns

### Loading Data from API

```javascript
data() {
    return {
        items: [],
        state: 'loading',
        message: 'Loading items...'
    };
},
mounted() {
    this.fetchItems();
},
methods: {
    fetchItems() {
        axios.get(this.endpoint)
            .then(response => {
                this.items = response.data.data;
                this.state = this.items.length ? 'has-items' : 'no-items';
                this.message = this.items.length ? '' : 'No items found';
            })
            .catch(error => {
                this.state = 'error';
                this.message = 'Failed to load items';
            });
    }
}
```

### Saving Data to API

```javascript
saveItem(item) {
    const method = this.mode === 'create' ? 'post' : 'put';
    const url = this.mode === 'create'
        ? this.endpoint
        : `${this.endpoint}/${item.id}`;

    axios[method](url, item)
        .then(response => {
            swal.fire('Success', 'Item saved!', 'success');
            this.fetchItems();
            this.resetForm();
        })
        .catch(error => {
            swal.fire('Error', 'Failed to save item', 'error');
        });
}
```

### Drag and Drop Reordering

```javascript
updateSortOrder() {
    const sortedIds = this.items.map(item => item.id);
    axios.post(`${this.endpoint}/reorder`, { ids: sortedIds })
        .then(() => {
            swal.fire('Success', 'Order updated!', 'success');
        })
        .catch(() => {
            swal.fire('Error', 'Failed to update order', 'error');
        });
}
```

## Naming Conventions

- **Components**: PascalCase (`MenuBuilder.vue`)
- **Props**: camelCase (`currentItem`)
- **Events**: kebab-case or camelCase (`newItem`, `save-item`)
- **CSS classes**: Tailwind utilities (kebab-case)
- **Methods**: camelCase (`fetchItems`)
- **Variables**: camelCase (`currentItem`)

## Notes for Copilot

1. **Always use Tailwind utilities** - avoid custom CSS unless absolutely necessary
2. **Use global components** - `v-button`, `v-card`, etc. are available everywhere
3. **Use global filters** - `{{ date | date }}`, `{{ price | currency }}`
4. **Event Bus for cross-component communication** - `EventBus.$emit()` and `EventBus.$on()`
5. **Builder pattern for lists** - Parent → Form → Item components
6. **Draggable for reordering** - `vuedraggable` is available
7. **SweetAlert2 for alerts** - `swal.fire()` available globally
8. **Axios for HTTP** - Pre-configured with CSRF and API tokens
9. **jQuery available** - `$` is global, but prefer Vue methods
10. **Mobile tooltips disabled** - v-tooltip doesn't work on mobile (≤768px)

## Related Documentation

- **Architecture**: See `ARCHITECTURE.md` for detailed component diagrams
- **Project Guide**: See `CLAUDE.md` for quick reference
- **Cursor Rules**: See `.cursorrules` for development guidelines
