routes-panel.html

67 lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
<!-- Routes Panel — standalone domain mapping section -->
<div class="panel-card">
    <div class="flex items-center justify-between px-4 pt-3 pb-1">
        <h3 class="text-[11px] font-semibold uppercase tracking-wider text-slate-400">Domains & Routes</h3>
        {{if dashboard.Routes}}
        <span class="text-[10px] font-mono text-slate-300 bg-slate-50 px-1.5 py-0.5 rounded">{{len dashboard.Routes}}</span>
        {{end}}
    </div>

    {{if dashboard.Routes}}
    <div class="px-1 pb-1">
        {{range $route := dashboard.Routes}}
        <div class="group/route">
            <div class="flex items-center gap-2.5 rounded-xl px-3 py-2 hover:bg-white/60 hover:shadow-sm hover:shadow-slate-200/50 transition-all duration-200">
                {{if $route.Active}}
                <span class="w-2 h-2 rounded-full bg-emerald-400 glow-emerald shrink-0"></span>
                {{else}}
                <span class="w-2 h-2 rounded-full bg-slate-300 shrink-0"></span>
                {{end}}
                <div class="flex-1 min-w-0">
                    <span class="text-[12px] text-slate-600 font-mono truncate block">{{$route.Host}}</span>
                    <span class="text-[10px] text-slate-400 font-mono truncate block">{{$route.Target}}:{{$route.Port}}</span>
                </div>
                {{if $route.System}}
                <span class="text-[9px] text-slate-300 border border-slate-200 rounded px-1.5 py-0.5 shrink-0">system</span>
                {{else}}
                <div class="flex items-center gap-0.5 opacity-0 group-hover/route:opacity-100 transition-opacity shrink-0">
                    <span hx-get="/routes/{{$route.ID}}/check" hx-trigger="click" hx-target="this" hx-swap="innerHTML"
                        class="w-5 h-5 inline-flex items-center justify-center rounded text-slate-300 hover:text-teal-500 hover:bg-teal-50 transition-colors cursor-pointer" title="Check DNS">
                        <svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" /></svg>
                    </span>
                    <button class="w-5 h-5 inline-flex items-center justify-center rounded text-slate-300 hover:text-slate-500 hover:bg-slate-100 transition-colors"
                        onclick="this.closest('.group\\/route').querySelector('.edit-form').classList.toggle('hidden')" title="Edit">
                        <svg xmlns="http://www.w3.org/2000/svg" class="w-2.5 h-2.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /></svg>
                    </button>
                    <button class="w-5 h-5 inline-flex items-center justify-center rounded text-slate-200 hover:text-red-400 hover:bg-red-50 transition-colors"
                        hx-post="/routes/{{$route.ID}}/delete" hx-confirm="Remove route for {{$route.Host}}?" hx-target="body" title="Delete">
                        <svg xmlns="http://www.w3.org/2000/svg" class="w-2.5 h-2.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
                    </button>
                </div>
                {{end}}
            </div>
            {{if not $route.System}}
            <form class="edit-form hidden flex items-center gap-1.5 px-3 py-1.5 mx-3 bg-slate-50 rounded-lg mt-0.5"
                hx-post="/routes/{{$route.ID}}/update" hx-target="body">
                <input type="text" name="host" value="{{$route.Host}}" required
                    class="flex-1 min-w-0 text-[11px] font-mono text-slate-600 bg-white border border-slate-200 rounded px-2 py-1 focus:outline-none focus:border-indigo-300" />
                <input type="text" name="target" value="{{$route.Target}}" required
                    class="w-20 text-[11px] font-mono text-slate-600 bg-white border border-slate-200 rounded px-2 py-1 focus:outline-none focus:border-indigo-300" />
                <input type="number" name="port" value="{{$route.Port}}" required min="1" max="65535"
                    class="w-16 text-[11px] font-mono text-slate-600 bg-white border border-slate-200 rounded px-2 py-1 focus:outline-none focus:border-indigo-300" />
                <button type="submit" class="text-[10px] font-medium text-indigo-600 hover:text-indigo-700 px-1.5">Save</button>
            </form>
            {{end}}
        </div>
        {{end}}
    </div>
    {{else}}
    <div class="text-center py-6 px-4">
        <div class="inline-flex items-center justify-center w-10 h-10 rounded-xl bg-slate-50 mb-3">
            <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-slate-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" /></svg>
        </div>
        <p class="text-[12px] text-slate-400 mb-1">No routes configured</p>
        <p class="text-[11px] text-slate-300">Set domains from each service's settings</p>
    </div>
    {{end}}
</div>