Skip to main content

Infrastructure

Forge Deploy Script Editor code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/forge-deploy-script-editor.blade.php

@props([
    'name' => 'deploy_script',
    'value' => '',
    'macros' => ['$CREATE_RELEASE()', 'cd $FORGE_RELEASE_DIRECTORY', '$ACTIVATE_RELEASE()', '$RESTART_QUEUES()'],
    'rows' => 12,
])

@php
    /*
    | Deploy script textarea with quick insert buttons for Forge deployment
    | macros. Useful for standard and zero-downtime deployment settings panels.
    |
    | Usage:
    |   <x-ui.forge-deploy-script-editor :value="$script" />
    */
@endphp

<section
    x-data="{
        script: @js($value),
        escapeHtml(value) {
            return String(value)
                .replaceAll('&', '&amp;')
                .replaceAll('<', '&lt;')
                .replaceAll('>', '&gt;')
                .replaceAll('&quot;', '&amp;quot;');
        },
        highlight(value) {
            return this.escapeHtml(value || '')
                .split('\n')
                .map((line) => {
                    if (line.trim().startsWith('#')) {
                        return '<span class=&quot;tok-com&quot;>' + line + '</span>';
                    }

                    return line
                        .replace(/(\$[A-Z_]+(?:\(\))?)/g, '<span class=&quot;tok-var&quot;>$1</span>')
                        .replace(/(^|\s)(php|composer|npm|git|sudo|cd|echo|curl|forge)(?=\s|$)/g, '$1<span class=&quot;tok-fn&quot;>$2</span>')
                        .replace(/(\s--?[A-Za-z0-9][A-Za-z0-9-]*)/g, '<span class=&quot;tok-key&quot;>$1</span>')
                        .replace(/(\b\d+(?:\.\d+)?\b)/g, '<span class=&quot;tok-num&quot;>$1</span>');
                })
                .join('\n');
        },
        insert(text) {
            const textarea = this.$refs.script;
            const start = textarea.selectionStart ?? this.script.length;
            const end = textarea.selectionEnd ?? this.script.length;
            const before = this.script.slice(0, start);
            const after = this.script.slice(end);
            const prefix = before.length && ! before.endsWith('\n') ? '\n' : '';
            const suffix = after.length && ! after.startsWith('\n') ? '\n' : '';

            this.script = before + prefix + text + suffix + after;

            this.$nextTick(() => {
                textarea.focus();
                const cursor = (before + prefix + text).length;
                textarea.setSelectionRange(cursor, cursor);
            });
        },
    }"
    {{ $attributes->merge(['class' => 'min-w-0 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900']) }}
>
    <div class="flex flex-col gap-3 border-b border-gray-200 px-4 py-3 dark:border-gray-800 lg:flex-row lg:items-center lg:justify-between">
        <div class="min-w-0">
            <h3 class="text-sm font-semibold text-gray-900 dark:text-white">Deploy script</h3>
            <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Insert Forge macros without leaving the editor.</p>
        </div>

        <div class="flex flex-wrap gap-2">
            @foreach ($macros as $macro)
                <button
                    type="button"
                    class="rounded-md border border-gray-200 bg-white px-2.5 py-1.5 font-mono text-xs font-medium text-gray-700 transition hover:border-brand-300 hover:text-brand-700 dark:border-gray-700 dark:bg-gray-950 dark:text-gray-300 dark:hover:border-brand-700 dark:hover:text-brand-300"
                    @click="insert(@js($macro))"
                >
                    {{ $macro }}
                </button>
            @endforeach
        </div>
    </div>

    <textarea
        x-ref="script"
        x-model="script"
        name="{{ $name }}"
        rows="{{ $rows }}"
        spellcheck="false"
        class="block w-full resize-y border-0 bg-gray-950 px-3 py-4 font-mono text-[12px] leading-6 text-gray-100 outline-none focus:ring-0 sm:px-4 sm:text-[13px]"
    ></textarea>

    <div class="border-t border-gray-800 bg-gray-950 px-3 py-3 sm:px-4">
        <div class="mb-2 text-xs font-medium text-gray-500">
            Highlighted preview
        </div>
        <pre class="max-h-56 overflow-auto rounded-lg border border-gray-800 bg-gray-900/70 p-3 font-mono text-[12px] leading-6 text-gray-200 sm:text-[13px] [&_.tok-key]:text-brand-300 [&_.tok-fn]:text-amber-300 [&_.tok-str]:text-green-300 [&_.tok-com]:text-gray-500 [&_.tok-com]:italic [&_.tok-num]:text-amber-200 [&_.tok-var]:text-gray-100"><code x-html="highlight(script)"></code></pre>
    </div>
</section>