new magic bar
This commit is contained in:
parent
fe189da30f
commit
63a2e69cc6
@ -59,10 +59,10 @@ static public function validated()
|
||||
return Server::where('team_id', session('currentTeam')->id)->whereRelation('settings', 'is_validated', true)->get();
|
||||
}
|
||||
|
||||
static public function destinations(string|null $server_uuid = null)
|
||||
static public function destinations(string|null $server_id = null)
|
||||
{
|
||||
if ($server_uuid) {
|
||||
$server = Server::where('team_id', session('currentTeam')->id)->where('uuid', $server_uuid)->firstOrFail();
|
||||
if ($server_id) {
|
||||
$server = Server::where('team_id', session('currentTeam')->id)->where('id', $server_id)->firstOrFail();
|
||||
$standaloneDocker = collect($server->standaloneDockers->all());
|
||||
$swarmDocker = collect($server->swarmDockers->all());
|
||||
return $standaloneDocker->concat($swarmDocker);
|
||||
|
@ -3,7 +3,7 @@
|
||||
@tailwind utilities;
|
||||
|
||||
.scrollbar {
|
||||
@apply scrollbar-thumb-coollabs-100 scrollbar-track-coolgray-200 scrollbar-w-1;
|
||||
@apply scrollbar-thumb-coollabs-100 scrollbar-track-coolgray-200 scrollbar-w-1;
|
||||
}
|
||||
|
||||
html {
|
||||
@ -11,10 +11,10 @@ html {
|
||||
}
|
||||
|
||||
body {
|
||||
@apply scrollbar min-h-screen bg-coolgray-100 text-neutral-400 antialiased ;
|
||||
@apply scrollbar min-h-screen bg-coolgray-100 text-neutral-400 antialiased;
|
||||
}
|
||||
main {
|
||||
@apply px-32 xl:px-14 mx-auto max-w-screen-xl pt-10;
|
||||
@apply px-32 xl:px-14 mx-auto max-w-screen-xl;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
@ -23,10 +23,14 @@ input[type="checkbox"] {
|
||||
input {
|
||||
@apply input input-sm h-7 outline-none placeholder:text-neutral-700 text-white rounded-none;
|
||||
}
|
||||
input[type="text"],[type="number"],[type="email"],[type="password"] {
|
||||
input[type="text"],
|
||||
[type="number"],
|
||||
[type="email"],
|
||||
[type="password"] {
|
||||
@apply read-only:opacity-40;
|
||||
}
|
||||
.label-text, label {
|
||||
.label-text,
|
||||
label {
|
||||
@apply text-neutral-400 text-sm;
|
||||
}
|
||||
|
||||
@ -104,33 +108,32 @@ .magic-item-focused {
|
||||
@apply bg-coolgray-400 text-white;
|
||||
}
|
||||
|
||||
|
||||
.lds-heart {
|
||||
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
}
|
||||
@keyframes lds-heart {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
5% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
39% {
|
||||
transform: scale(0.85);
|
||||
}
|
||||
45% {
|
||||
transform: scale(1);
|
||||
}
|
||||
60% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
100% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
5% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
39% {
|
||||
transform: scale(0.85);
|
||||
}
|
||||
45% {
|
||||
transform: scale(1);
|
||||
}
|
||||
60% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
100% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
.bg-coollabs-gradient {
|
||||
@apply text-transparent bg-clip-text bg-gradient-to-r from-purple-500 via-pink-500 to-red-500;
|
||||
@apply text-transparent bg-clip-text bg-gradient-to-r from-purple-500 via-pink-500 to-red-500;
|
||||
}
|
||||
.text-helper {
|
||||
@apply inline-block font-bold text-warning
|
||||
}
|
||||
@apply inline-block font-bold text-warning;
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import Alpine from "alpinejs";
|
||||
// import { createApp } from "vue";
|
||||
// import MagicSearchBar from "./components/MagicSearchBar.vue";
|
||||
|
||||
import { createApp } from "vue";
|
||||
import MagicBar from "./components/MagicBar.vue";
|
||||
window.Alpine = Alpine;
|
||||
Alpine.start();
|
||||
|
||||
// const app = createApp({});
|
||||
// app.component('magic-search-bar', MagicSearchBar);
|
||||
// app.mount('#vue');
|
||||
const app = createApp({});
|
||||
app.component("magic-bar", MagicBar);
|
||||
app.mount("#vue");
|
||||
|
199
resources/js/components/MagicBar.vue
Normal file
199
resources/js/components/MagicBar.vue
Normal file
@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<Transition name="fade">
|
||||
<div class="z-10 mt-2">
|
||||
<div class="overflow-hidden transition-all transform" v-if="!showCommandPalette"
|
||||
@click="showCommandPalette = true">
|
||||
<div class="overflow-hidden transition-all transform bg-coolgray-200 ring-1 ring-black ring-opacity-5 ">
|
||||
<div class="relative">
|
||||
<svg class="absolute w-5 h-5 text-gray-400 pointer-events-none left-3 top-2.5" viewBox="0 0 20 20"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
<input type="text" v-model="search"
|
||||
class="w-full h-10 pr-4 text-white bg-transparent border-0 pl-11 placeholder:text-neutral-700 focus:ring-0 sm:text-sm"
|
||||
placeholder=" Search..." role="combobox" aria-expanded="false" aria-controls="options">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative" role="dialog" aria-modal="true" v-if="showCommandPalette"
|
||||
@keyup.esc="showCommandPalette = false">
|
||||
<div class="fixed inset-0 transition-opacity bg-opacity-75 bg-coolgray-100"></div>
|
||||
<div class="fixed inset-0 p-4 overflow-y-auto sm:p-6 md:px-20">
|
||||
<div class="overflow-hidden transition-all transform bg-coolgray-200 ring-1 ring-black ring-opacity-5 ">
|
||||
<div class="relative">
|
||||
<svg class="absolute w-5 h-5 text-gray-400 pointer-events-none left-3 top-2.5"
|
||||
viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
<input type="text" v-model="search"
|
||||
class="w-full h-10 pr-4 text-white bg-transparent border-0 pl-11 placeholder:text-neutral-700 focus:ring-0 sm:text-sm"
|
||||
autofocus placeholder=" Search..." role="combobox" aria-expanded="false"
|
||||
aria-controls="options">
|
||||
</div>
|
||||
<ul class="p-4 pb-2 space-y-4 overflow-y-auto max-h-80 scroll-py-10 scroll-pb-2 scrollbar"
|
||||
id="options" role="listbox">
|
||||
<li>
|
||||
<h2 class="text-xs font-semibold text-white">{{ state.title }}</h2>
|
||||
<ul class="mt-2 -mx-4 text-sm text-white">
|
||||
<li class="flex items-center px-4 py-2 cursor-pointer select-none group hover:bg-coolgray-400"
|
||||
id="option-1" role="option" tabindex="-1" v-for="action, index in state.data"
|
||||
@click="next(state.next ?? action.next, index)">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 icon" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<template v-if="action.icon === 'git' || state.icon === 'git'">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M16 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
|
||||
<path d="M12 8m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
|
||||
<path d="M12 16m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
|
||||
<path d="M12 15v-6" />
|
||||
<path d="M15 11l-2 -2" />
|
||||
<path d="M11 7l-1.9 -1.9" />
|
||||
<path
|
||||
d="M13.446 2.6l7.955 7.954a2.045 2.045 0 0 1 0 2.892l-7.955 7.955a2.045 2.045 0 0 1 -2.892 0l-7.955 -7.955a2.045 2.045 0 0 1 0 -2.892l7.955 -7.955a2.045 2.045 0 0 1 2.892 0z" />
|
||||
</template>
|
||||
<template v-if="action.icon === 'server' || state.icon === 'server'">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z" />
|
||||
<path d="M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12" />
|
||||
<path d="M7 8v.01" />
|
||||
<path d="M7 16v.01" />
|
||||
<path d="M20 15l-2 3h3l-2 3" />
|
||||
</template>
|
||||
<template v-if="action.icon === 'destination' || state.icon === 'destination'">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z" />
|
||||
<path d="M5 10h3v3h-3z" />
|
||||
<path d="M8 10h3v3h-3z" />
|
||||
<path d="M11 10h3v3h-3z" />
|
||||
<path d="M8 7h3v3h-3z" />
|
||||
<path d="M11 7h3v3h-3z" />
|
||||
<path d="M11 4h3v3h-3z" />
|
||||
<path d="M4.571 18c1.5 0 2.047 -.074 2.958 -.78" />
|
||||
<path d="M10 16l0 .01" />
|
||||
</template>
|
||||
<template v-if="action.icon === 'project' || state.icon === 'project'">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M9 4h3l2 2h5a2 2 0 0 1 2 2v7a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-9a2 2 0 0 1 2 -2" />
|
||||
<path d="M17 17v2a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-9a2 2 0 0 1 2 -2h2" />
|
||||
</template>
|
||||
<template v-if="action.icon === 'environment' || state.icon === 'environment'">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M16 5l3 3l-2 1l4 4l-3 1l4 4h-9" />
|
||||
<path d="M15 21l0 -3" />
|
||||
<path d="M8 13l-2 -2" />
|
||||
<path d="M8 12l2 -2" />
|
||||
<path d="M8 21v-13" />
|
||||
<path
|
||||
d="M5.824 16a3 3 0 0 1 -2.743 -3.69a3 3 0 0 1 .304 -4.833a3 3 0 0 1 4.615 -3.707a3 3 0 0 1 4.614 3.707a3 3 0 0 1 .305 4.833a3 3 0 0 1 -2.919 3.695h-4z" />
|
||||
</template>
|
||||
</svg>
|
||||
<span class="flex-auto ml-3 truncate">{{ action.name }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import axios from "axios";
|
||||
|
||||
const showCommandPalette = ref(false)
|
||||
const baseUrl = '/magic2'
|
||||
let selected = {};
|
||||
|
||||
const actions = [{
|
||||
name: 'Public Repository',
|
||||
tags: 'application,public,repository,github,gitlab,bitbucket,git',
|
||||
icon: 'git',
|
||||
next: 'server'
|
||||
},
|
||||
{
|
||||
name: 'Private Repository (with GitHub Apps)',
|
||||
tags: 'application,private,repository,github,gitlab,bitbucket,git',
|
||||
icon: 'git',
|
||||
next: 'server'
|
||||
},
|
||||
{
|
||||
name: 'Private Repository (with Deploy Key)',
|
||||
tags: 'application,private,repository,github,gitlab,bitbucket,git',
|
||||
icon: 'git',
|
||||
next: 'server'
|
||||
}]
|
||||
const state = ref({
|
||||
title: 'New',
|
||||
icon: null,
|
||||
next: null,
|
||||
current: null,
|
||||
data: actions
|
||||
})
|
||||
|
||||
async function next(nextAction, index) {
|
||||
if (state.value.current) selected[state.value.current] = state.value.data[index].id
|
||||
else selected['action'] = index
|
||||
|
||||
console.log(selected)
|
||||
|
||||
switch (nextAction) {
|
||||
case 'server':
|
||||
await getServers()
|
||||
state.value.title = 'Select a Server'
|
||||
state.value.icon = 'server'
|
||||
break;
|
||||
case 'destination':
|
||||
await getDestinations(state.value.data[index].id)
|
||||
state.value.title = 'Select a Destination'
|
||||
state.value.icon = 'destination'
|
||||
break;
|
||||
case 'project':
|
||||
await getProjects()
|
||||
state.value.title = 'Select a Project'
|
||||
state.value.icon = 'project'
|
||||
break;
|
||||
case 'environment':
|
||||
await getEnvironments(state.value.data[index].id)
|
||||
state.value.title = 'Select an Environment'
|
||||
state.value.icon = 'environment'
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
async function getServers() {
|
||||
const { data } = await axios.get(`${baseUrl}/servers`);
|
||||
state.value.data = data.servers
|
||||
state.value.current = 'server'
|
||||
state.value.next = 'destination'
|
||||
}
|
||||
async function getDestinations(serverId) {
|
||||
const { data } = await axios.get(`${baseUrl}/destinations?server_id=${serverId}`);
|
||||
state.value.data = data.destinations
|
||||
state.value.current = 'destination'
|
||||
state.value.next = 'project'
|
||||
}
|
||||
async function getProjects() {
|
||||
const { data } = await axios.get(`${baseUrl}/projects`);
|
||||
state.value.data = data.projects
|
||||
state.value.current = 'project'
|
||||
state.value.next = 'environment'
|
||||
}
|
||||
async function getEnvironments(projectId) {
|
||||
const { data } = await axios.get(`${baseUrl}/environments?project_id=${projectId}`);
|
||||
state.value.data = data.environments
|
||||
state.value.current = 'environment'
|
||||
state.value.next = 'server'
|
||||
}
|
||||
</script>
|
@ -29,8 +29,9 @@
|
||||
@auth
|
||||
<x-navbar />
|
||||
@endauth
|
||||
<div class="flex justify-center w-full pt-4 min-h-12">
|
||||
<x-magic-bar />
|
||||
<div class="flex justify-center w-full min-h-12" id="vue">
|
||||
{{-- <x-magic-bar /> --}}
|
||||
<magic-bar></magic-bar>
|
||||
</div>
|
||||
<main>
|
||||
{{ $slot }}
|
||||
|
@ -27,7 +27,35 @@
|
||||
|
||||
|
||||
|
||||
Route::prefix('magic2')->middleware(['auth'])->group(function () {
|
||||
Route::get('/servers', function () {
|
||||
$id = session('currentTeam')->id;
|
||||
return response()->json([
|
||||
'servers' => Server::where('team_id', $id)->get()->sortBy('name')
|
||||
]);
|
||||
});
|
||||
Route::get('/destinations', function () {
|
||||
$server_id = request()->query('server_id');
|
||||
return response()->json([
|
||||
'destinations' => Server::destinations($server_id)->sortBy('name')
|
||||
]);
|
||||
});
|
||||
Route::get('/projects', function () {
|
||||
$id = session('currentTeam')->id;
|
||||
return response()->json([
|
||||
'projects' => Project::where('team_id', $id)->get()->sortBy('name')
|
||||
]);
|
||||
});
|
||||
Route::get('/environments', function () {
|
||||
$id = session('currentTeam')->id;
|
||||
$project_id = request()->query('project_id');
|
||||
return response()->json([
|
||||
'environments' => Project::where('team_id', $id)->where('id', $project_id)->first()->environments
|
||||
]);
|
||||
});
|
||||
});
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
|
||||
Route::get('/magic', function () {
|
||||
try {
|
||||
$id = session('currentTeam')->id;
|
||||
|
Loading…
Reference in New Issue
Block a user