vue-componentes/src/playground/App.vue

217 lines
7.2 KiB
Vue

<template>
<div style="display: flex; flex-direction: row; min-height: 100vh;">
<!-- Widget de Feedback flutuante -->
<EliFeedbackWidget />
<!-- Seção de Componentes -->
<div style="flex: 1; min-width: 0; overflow-y: auto;">
<v-container class="py-6">
<div class="d-flex align-center justify-space-between mb-4">
<h1 class="text-h5">Playground — eli-vue</h1>
<v-btn-toggle
v-model="temaAtual"
mandatory
density="compact"
color="primary"
@update:model-value="alternarTema"
>
<v-btn value="verde" prepend-icon="mdi-leaf" size="small">
Verde (e-licencie)
</v-btn>
<v-btn value="azul" prepend-icon="mdi-water" size="small">
Azul (Betha)
</v-btn>
</v-btn-toggle>
</div>
<v-tabs v-model="aba" color="primary" density="comfortable">
<v-tab value="botao">Botão</v-tab>
<v-tab value="indicador">Indicador</v-tab>
<v-tab value="cartao">Cartão</v-tab>
<v-tab value="entradas">Entradas</v-tab>
<v-tab value="data_hora">Data e hora</v-tab>
<v-tab value="tabela">Tabela</v-tab>
<v-tab value="ola_mundo">Demo</v-tab>
</v-tabs>
<v-divider class="my-4" />
<BotaoPlayground v-if="aba === 'botao'" />
<IndicadorPlayground v-else-if="aba === 'indicador'" />
<CartaoPlayground v-else-if="aba === 'cartao'" />
<EntradasPlayground v-else-if="aba === 'entradas'" />
<DataHoraPlayground v-else-if="aba === 'data_hora'" />
<TabelaPlayground v-else-if="aba === 'tabela'" />
<OlaMundoPlayground v-else />
</v-container>
</div>
<!-- Console Global do Playground -->
<div
class="playground-console"
style="width: 400px; flex-shrink: 0; background: #121212; color: #a3e635; padding: 24px 20px; border-left: 1px solid #333; display: flex; flex-direction: column; font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; font-size: 12px;"
>
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #333; padding-bottom: 12px; margin-bottom: 16px;">
<span style="font-weight: 700; color: #fff; text-transform: uppercase; letter-spacing: 1.5px; font-size: 11px; display: flex; align-items: center; gap: 8px;">
Console
<div style="width: 6px; height: 6px; border-radius: 50%; background-color: #22c55e; box-shadow: 0 0 8px #22c55e;"></div>
</span>
<button
@click="logsConsole = []"
style="font-size: 10px; cursor: pointer; color: #ef4444; background: rgba(239, 68, 68, 0.1); border: 1px solid rgba(239, 68, 68, 0.2); border-radius: 4px; padding: 2px 8px; font-family: inherit;"
>LIMPAR</button>
</div>
<div style="flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 8px;" class="playground-console-scroll">
<div v-if="logsConsole.length === 0" style="color: #52525b; font-size: 11px;">Nenhum log registrado ainda...</div>
<pre
v-for="(log, i) in logsConsole"
:key="i"
style="font-size: 11px; white-space: pre-wrap; word-break: break-all; color: #a1a1aa; border-left: 2px solid #52525b; padding-left: 8px; margin: 0;"
>{{ log }}</pre>
</div>
</div>
</div>
</template>
<style scoped>
.playground-console-scroll::-webkit-scrollbar {
width: 6px;
}
.playground-console-scroll::-webkit-scrollbar-track {
background: transparent;
}
.playground-console-scroll::-webkit-scrollbar-thumb {
background: #3f3f46;
border-radius: 3px;
}
.playground-console-scroll::-webkit-scrollbar-thumb:hover {
background: #52525b;
}
</style>
<script lang="ts">
import { defineComponent, provide, ref } from "vue"
import { useTheme } from "vuetify"
import { EliFeedbackWidget } from "../componentes/FeedbackWidget"
import { definirTemaAplicacao, type TipoTemaAplicacao } from "../temas"
import BotaoPlayground from "./botao.playground.vue"
import CartaoPlayground from "./cartao.playground.vue"
import DataHoraPlayground from "./data_hora.playground.vue"
import EntradasPlayground from "./entradas.playground.vue"
import IndicadorPlayground from "./indicador.playground.vue"
import OlaMundoPlayground from "./ola_mundo.playground.vue"
import { PLAYGROUND_CONSOLE_KEY, type PlaygroundConsole } from "./playgroundConsole"
import TabelaPlayground from "./tabela.playground.vue"
type AbaPlayground =
| "botao"
| "indicador"
| "cartao"
| "entradas"
| "data_hora"
| "tabela"
| "ola_mundo"
const mapaHashParaAba: Record<string, AbaPlayground> = {
botao: "botao",
indicador: "indicador",
cartao: "cartao",
entradas: "entradas",
"data-hora": "data_hora",
tabela: "tabela",
demo: "ola_mundo",
}
const mapaAbaParaHash: Record<AbaPlayground, string> = {
botao: "botao",
indicador: "indicador",
cartao: "cartao",
entradas: "entradas",
data_hora: "data-hora",
tabela: "tabela",
ola_mundo: "demo",
}
export default defineComponent({
name: "App",
components: {
EliFeedbackWidget,
BotaoPlayground,
IndicadorPlayground,
CartaoPlayground,
EntradasPlayground,
DataHoraPlayground,
TabelaPlayground,
OlaMundoPlayground,
},
setup() {
const logsConsole = ref<string[]>([])
/** Adiciona um log estruturado ao console global do playground */
function adicionarLog(acao: string, req: unknown, res: unknown) {
const time = new Date().toLocaleTimeString()
logsConsole.value.unshift(
`[${time}] 🌐 ${acao}\nReq: ${JSON.stringify(req, null, 2)}\nRes: ${JSON.stringify(res, null, 2)}`,
)
}
/** Adiciona uma mensagem simples ao console */
function logMensagem(mensagem: string) {
const time = new Date().toLocaleTimeString()
logsConsole.value.unshift(`[${time}] ${mensagem}`)
}
const consoleApi: PlaygroundConsole = { adicionarLog, logMensagem }
provide(PLAYGROUND_CONSOLE_KEY, consoleApi)
const theme = useTheme()
const temaAtual = ref<TipoTemaAplicacao>("verde")
function alternarTema(novoTema: TipoTemaAplicacao) {
temaAtual.value = novoTema
definirTemaAplicacao(novoTema, { vuetify: { theme } })
logMensagem(`🎨 Tema alterado para: ${novoTema}`)
}
return {
logsConsole,
aba: ref<AbaPlayground>("botao"),
temaAtual,
alternarTema,
}
},
mounted() {
this.sincronizarAbaComHash()
window.addEventListener("hashchange", this.sincronizarAbaComHash)
},
beforeUnmount() {
window.removeEventListener("hashchange", this.sincronizarAbaComHash)
},
watch: {
aba() {
this.sincronizarHashComAba()
},
},
methods: {
normalizarHash() {
const valor = window.location.hash.replace(/^#\/?/, "").trim()
return valor
},
sincronizarAbaComHash() {
const hash = this.normalizarHash()
const aba = mapaHashParaAba[hash] ?? "botao"
if (this.aba !== aba) {
this.aba = aba
}
this.sincronizarHashComAba()
},
sincronizarHashComAba() {
const destino = `#/${mapaAbaParaHash[this.aba]}`
if (window.location.hash !== destino) {
window.location.hash = destino
}
},
},
})
</script>