WIP: panel management uix

This commit is contained in:
Jesse Malotaux 2025-04-05 23:23:51 +02:00
parent 0d3fb09310
commit 58de6eb976
5 changed files with 276 additions and 3 deletions

128
fe/build_panel_styles.js Normal file
View file

@ -0,0 +1,128 @@
import chokidar from 'chokidar'
import { resolve, join, dirname, normalize, posix } from 'path'
import { fileURLToPath } from 'url'
import { spawn } from 'child_process'
import { existsSync, writeFileSync } from 'fs'
// import { posix } from 'path/posix'
// Get the directory of the current script
const __dirname = dirname(fileURLToPath(import.meta.url))
const panelsDir = join(__dirname, '../panels')
// Store active Tailwind processes
const tailwindProcesses = new Map()
// Function to stop an existing Tailwind process
const stopTailwind = (dir) => {
if (tailwindProcesses.has(dir)) {
// console.log(`Stopping Tailwind for ${dir}...`)
const process = tailwindProcesses.get(dir)
process.kill('SIGTERM') // Graceful stop
tailwindProcesses.delete(dir)
return true
}
return false
}
// Function to start Tailwind
const startTailwind = (filePath) => {
let dir = dirname(filePath).replaceAll('\\', '/')
dir = dir.replace(/^.*\/panels/, '../panels')
const fileExt = filePath.split('.').pop()
// console.log(dir)
if (fileExt !== 'html') return
const panelName = dir
.split(/[\/\\]/)
.pop()
.replace('_', ' ')
// Create a CSS and config file for Tailwind
const cssFile = createTailwindStyling(dir)
const configFile = createTailwindConfig(dir)
const outputFile = dir + '/styles.css'
// Restart Tailwind if it's already running
if (!stopTailwind(dir)) {
console.log(`Starting Tailwind for panel: ${panelName}`)
} else {
console.log(`Restarting Tailwind for panel: ${panelName}`)
}
// console.log(configFile)
// console.log(outputFile)
// Spawn a new Tailwind process
const tailwindProcess = spawn(
'npx',
[
'tailwindcss',
'--output',
outputFile,
'--config',
`${configFile}`,
'--content',
dir + '/index.html',
'--watch',
],
{
stdio: 'inherit',
shell: true,
},
)
tailwindProcesses.set(dir, tailwindProcess)
}
const createTailwindStyling = (dir) => {
const cssFile = dir + '/tailwind.css'
const cssContent = `@tailwind base; @tailwind components; @tailwind utilities;`
createFile(cssFile, cssContent)
return cssFile
}
const createTailwindConfig = (dir) => {
const configPath = dir + '/tailwind.config.js'
// Create a basic tailwind.config.js with purge setup
const configContent = `
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default {
content: [path.resolve(__dirname, "index.html")],
theme: { extend: {} },
plugins: [],
mode: "jit",
};
`
createFile(configPath, configContent)
return configPath
}
const createFile = (filepath, content) => {
if (existsSync(filepath)) return
writeFileSync(filepath, content.trim())
// console.log(`Created ${filepath}`)
}
// Watch for changes to `index.html` files
const watcher = chokidar.watch(`${panelsDir}/`, {
persistent: true,
ignoreInitial: false,
ignored: '*.json, *.css, *.jpg, *.jpeg, *.png, *.webp',
})
// Start or restart Tailwind when a file is added or modified
watcher.on('change', (file) => {
startTailwind(file)
})

View file

@ -0,0 +1,59 @@
<template>
<div></div>
</template>
<script setup>
import { appUrl } from '@/services/ApiService'
import axios from 'axios'
import { nextTick, onMounted, reactive, ref } from 'vue'
const panel = reactive({
style: '',
styleEl: null,
html: '',
})
const testPanel = ref()
onMounted(() => {
axios.post(appUrl() + '/panel/get').then(async (data) => {
// console.log(data.data.html)
if (data.data) {
setPanelStyle(data.data.css)
panel.html = data.data.html
await nextTick()
addButtonEventListeners()
}
})
})
const setPanelStyle = (styleStr) => {
const styleEl = document.createElement('style')
styleEl.setAttribute('custom_panel_style', true)
styleEl.innerHTML = styleStr
document.head.appendChild(styleEl)
panel.styleEl = styleEl
}
const addButtonEventListeners = () => {
testPanel.value.querySelectorAll('[mcrm__button]').forEach((button) => {
button.addEventListener('click', () => {
console.log(button.id)
if (button.id == 'button_1') {
axios.post(appUrl() + '/macro/play', { macro: 'task_manager' })
}
})
})
}
</script>
<style>
@reference "@/assets/main.css";
[mcrm__button] {
@apply cursor-pointer;
}
</style>

View file

@ -0,0 +1,48 @@
<template>
<div id="panels-overview">
<!-- <AlertComp v-if="Object.keys(panels.list).length == 0" type="info">No panels found</AlertComp> -->
<div class="panel-list">
<div class="panel-item" v-for="(panel, i) in panels.list" :key="i">
<!-- <router-link :to="'/panel/' + panel.id"> -->
<div class="panel-item__content">
<img :src="panel.thumb" alt="" />
<h4>{{ panel.name }}</h4>
<p>{{ panel.description }}</p>
</div>
<!-- </router-link> -->
</div>
</div>
</div>
</template>
<script setup>
import { usePanelStore } from '@/stores/panel'
import { onMounted, reactive } from 'vue'
import AlertComp from '../base/AlertComp.vue'
const panel = usePanelStore()
const panels = reactive({
list: {},
})
onMounted(async () => {
const panelList = await panel.getPanels()
console.log(panelList)
panels.list = panelList
})
</script>
<style scoped>
@reference "@/assets/main.css";
.panel-list {
@apply grid
grid-cols-2
md:grid-cols-4
lg:grid-cols-6
gap-4
size-full;
}
</style>

24
fe/src/stores/panel.js Normal file
View file

@ -0,0 +1,24 @@
import { appUrl } from '@/services/ApiService'
import axios from 'axios'
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const usePanelStore = defineStore('panel', () => {
const list = ref([])
const getPanels = async () => {
console.log(list.value.length)
if (list.value.length > 0) return list.value
const resp = await axios.post(appUrl() + '/panel/list')
list.value = resp.data.data
return list.value
}
return {
list,
getPanels,
}
})

View file

@ -1,7 +1,21 @@
<template> <template>
<div></div> <div id="macros" class="panel">
<h1 class="panel__title">
Panels <span class="text-sm">{{ isLocal() ? 'remote' : 'servers' }}</span>
</h1>
<div class="panel__content !p-0">
<div class="macro-panel__content">
<PanelsOverview />
</div>
</div>
</div>
</template> </template>
<script setup></script> <script setup>
import PanelsOverview from '@/components/panels/PanelsOverview.vue'
import { isLocal } from '@/services/ApiService'
</script>
<style lang="scss" scoped></style> <style scoped>
@reference "@/assets/main.css";
</style>