debugbar 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/debugbar/assets_controller.rb +1 -1
- data/build.sh +7 -0
- data/debugbar.gemspec +6 -1
- data/lib/debugbar/engine.rb +0 -8
- data/lib/debugbar/version.rb +1 -1
- data/lib/debugbar.rb +0 -7
- metadata +2 -54
- data/client/.gitignore +0 -25
- data/client/README.md +0 -0
- data/client/dist/.vite/manifest.json +0 -14
- data/client/dist/assets/debugbar-u5mP-5-z.js +0 -34
- data/client/dist/assets/ruby-logo-kn_8RniZ.svg +0 -946
- data/client/index.html +0 -78
- data/client/package-lock.json +0 -2393
- data/client/package.json +0 -32
- data/client/postcss.config.js +0 -6
- data/client/src/App.vue +0 -17
- data/client/src/AppDemo.vue +0 -29
- data/client/src/AppDev.vue +0 -20
- data/client/src/Debugbar.vue +0 -276
- data/client/src/assets/rails-logo.svg +0 -1
- data/client/src/assets/ruby-logo.svg +0 -946
- data/client/src/components/TabButton.vue +0 -32
- data/client/src/components/panels/CachePanel.vue +0 -41
- data/client/src/components/panels/JobsPanel.vue +0 -52
- data/client/src/components/panels/JsonPanel.vue +0 -15
- data/client/src/components/panels/LogsPanel.vue +0 -43
- data/client/src/components/panels/MessagesPanel.vue +0 -25
- data/client/src/components/panels/ModelsPanel.vue +0 -37
- data/client/src/components/panels/Panel.vue +0 -7
- data/client/src/components/panels/RequestPanel.vue +0 -98
- data/client/src/components/queries/QueriesPanel.vue +0 -17
- data/client/src/components/queries/QueryItem.vue +0 -65
- data/client/src/components/ui/Foldable.vue +0 -39
- data/client/src/components/ui/KeyValueTable.vue +0 -16
- data/client/src/components/ui/Row.vue +0 -14
- data/client/src/components/ui/logo-ruby.vue +0 -547
- data/client/src/demo.ts +0 -17
- data/client/src/dev.ts +0 -20
- data/client/src/main.ts +0 -17
- data/client/src/models/Config.ts +0 -27
- data/client/src/models/Request.ts +0 -183
- data/client/src/stores/RequestsStore.ts +0 -36
- data/client/src/stores/configStore.ts +0 -8
- data/client/src/style.css +0 -23
- data/client/src/types.d.ts +0 -9
- data/client/src/vite-env.d.ts +0 -1
- data/client/tailwind.config.js +0 -16
- data/client/tsconfig.json +0 -29
- data/client/tsconfig.node.json +0 -10
- data/client/vite.config.ts +0 -44
- data/fixtures/requests/1706607114--demo_post_list.json +0 -499
- data/fixtures/requests/1706607120--api_jobs.json +0 -176
- data/fixtures/requests/1706607123--api_jobs.json +0 -119
- data/fixtures/requests/1706607133--demo_slow_page.json +0 -130
- data/fixtures/requests/1706607136--demo_post.json +0 -164
- data/fixtures/requests/1706607136--demo_random_post.json +0 -106
- data/fixtures/requests/1706607141--api_errors.json +0 -73
- data/package-lock.json +0 -50
- data/package.json +0 -5
@@ -1,32 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
const props = defineProps<{
|
3
|
-
label: string
|
4
|
-
count?: number
|
5
|
-
isActive: boolean
|
6
|
-
}>()
|
7
|
-
</script>
|
8
|
-
|
9
|
-
<template>
|
10
|
-
<button
|
11
|
-
class="text-sm flex items-center space-x-1 px-3 py-2 border-0"
|
12
|
-
:class="{
|
13
|
-
'bg-stone-300 rounded-sm': props.isActive,
|
14
|
-
}"
|
15
|
-
>
|
16
|
-
<span :class="{ 'font-medium': props.isActive }"><slot /></span>
|
17
|
-
<span
|
18
|
-
v-if="props.count != undefined"
|
19
|
-
class="p-0.5 rounded-full text-xs"
|
20
|
-
:class="{
|
21
|
-
'px-1.5': props.count < 10,
|
22
|
-
hidden: props.count == 0,
|
23
|
-
'bg-stone-300': props.count > 0 && !props.isActive,
|
24
|
-
'bg-stone-400': props.count > 0 && props.isActive,
|
25
|
-
// '!bg-red-700 !text-white': props.count > 10, // TODO: Should be PER TAB (30 models is fine but 30 queries is a lot)
|
26
|
-
}"
|
27
|
-
v-text="props.count"
|
28
|
-
/>
|
29
|
-
</button>
|
30
|
-
</template>
|
31
|
-
|
32
|
-
<style scoped></style>
|
@@ -1,41 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import type { Cache } from "@/models/Request.ts"
|
3
|
-
import Panel from "@/components/panels/Panel.vue"
|
4
|
-
|
5
|
-
const props = defineProps<{
|
6
|
-
cache: Cache[]
|
7
|
-
}>()
|
8
|
-
</script>
|
9
|
-
|
10
|
-
<template>
|
11
|
-
<panel>
|
12
|
-
<div v-if="props.cache.length == 0">
|
13
|
-
<div class="text-gray-500">No cache used.</div>
|
14
|
-
</div>
|
15
|
-
|
16
|
-
<div class="space-y-3">
|
17
|
-
<div v-for="cache in props.cache" class="flex items-center space-x-8">
|
18
|
-
<div class="w-24 text-sm text-right text-gray-400">{{ cache.time }}</div>
|
19
|
-
<div class="w-16 text-right">
|
20
|
-
<span
|
21
|
-
class="px-1 py-0.5 rounded text-white text-xs font-mono font-medium bg-stone-400"
|
22
|
-
:class="{
|
23
|
-
'!bg-emerald-500': cache.label == 'hit',
|
24
|
-
'!bg-indigo-500': cache.label == 'write',
|
25
|
-
'!bg-amber-400': cache.label == 'read',
|
26
|
-
'!bg-red-400': cache.label == 'delete',
|
27
|
-
}"
|
28
|
-
>
|
29
|
-
{{ cache.label }}
|
30
|
-
</span>
|
31
|
-
</div>
|
32
|
-
<div class="text-gray-800">
|
33
|
-
<div class="font-medium" title="cache key">{{ cache.key }}</div>
|
34
|
-
<div class="text-xs text-gray-400" title="transaction_id">{{ cache.transaction_id }}</div>
|
35
|
-
</div>
|
36
|
-
</div>
|
37
|
-
</div>
|
38
|
-
</panel>
|
39
|
-
</template>
|
40
|
-
|
41
|
-
<style scoped></style>
|
@@ -1,52 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import { Job } from "@/models/Request.ts"
|
3
|
-
import Panel from "@/components/panels/Panel.vue"
|
4
|
-
|
5
|
-
const props = defineProps<{
|
6
|
-
jobs: Job[]
|
7
|
-
}>()
|
8
|
-
|
9
|
-
function formatTs(ts: number) {
|
10
|
-
if (ts == null) {
|
11
|
-
return "-"
|
12
|
-
}
|
13
|
-
return new Date(ts * 1000).toLocaleString()
|
14
|
-
}
|
15
|
-
</script>
|
16
|
-
|
17
|
-
<template>
|
18
|
-
<panel>
|
19
|
-
<div v-if="props.jobs.length == 0">
|
20
|
-
<div class="text-gray-500">No jobs enqueued.</div>
|
21
|
-
</div>
|
22
|
-
|
23
|
-
<table v-if="props.jobs.length > 0" class="my-4 mx-6 divide-y divide-stone-300">
|
24
|
-
<thead>
|
25
|
-
<tr>
|
26
|
-
<th scope="col" class="w-36 py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-stone-900 sm:pl-0">Job</th>
|
27
|
-
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-stone-900">Args</th>
|
28
|
-
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-stone-900">Logs</th>
|
29
|
-
</tr>
|
30
|
-
</thead>
|
31
|
-
<tbody class="divide-y divide-stone-200">
|
32
|
-
<tr v-for="(v, _k) in props.jobs" :key="v.id">
|
33
|
-
<td class="whitespace-nowrap p-4 pr-8 text-stone-900">
|
34
|
-
<div class="text-lg font-bold" v-text="v.class"></div>
|
35
|
-
<div class="text-stone-600 text-sm">
|
36
|
-
<div v-text="'Queue: ' + v.queue"></div>
|
37
|
-
<div v-text="'At: ' + formatTs(v.scheduled_at)"></div>
|
38
|
-
</div>
|
39
|
-
</td>
|
40
|
-
<td class="whitespace-nowrap px-3 p-4 pr-8 text-sm">
|
41
|
-
<highlightjs language="json" :code="JSON.stringify(v.args, null, 2)" />
|
42
|
-
</td>
|
43
|
-
<td class="whitespace-nowrap px-3 p-4 pr-8 text-sm text-stone-500">
|
44
|
-
<div v-for="(log, k) in v.logs" v-html="(k > 0 ? ' '.repeat(k) + '↳ ' : '') + log" class="" />
|
45
|
-
</td>
|
46
|
-
</tr>
|
47
|
-
</tbody>
|
48
|
-
</table>
|
49
|
-
</panel>
|
50
|
-
</template>
|
51
|
-
|
52
|
-
<style scoped></style>
|
@@ -1,15 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import type { BackendRequest } from "@/models/Request.ts"
|
3
|
-
|
4
|
-
const props = defineProps<{
|
5
|
-
currentRequest: BackendRequest
|
6
|
-
}>()
|
7
|
-
</script>
|
8
|
-
|
9
|
-
<template>
|
10
|
-
<div class="p-4 leading-8">
|
11
|
-
<highlightjs language="json" :code="JSON.stringify(props.currentRequest, null, 2)" />
|
12
|
-
</div>
|
13
|
-
</template>
|
14
|
-
|
15
|
-
<style scoped></style>
|
@@ -1,43 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import { Log } from "@/models/Request.ts"
|
3
|
-
import Panel from "@/components/panels/Panel.vue"
|
4
|
-
|
5
|
-
const props = defineProps<{
|
6
|
-
logs: Log[]
|
7
|
-
}>()
|
8
|
-
|
9
|
-
function message(log: Log): string {
|
10
|
-
const str = log.progname || log.message || ""
|
11
|
-
return str.replace(" ", " ")
|
12
|
-
}
|
13
|
-
</script>
|
14
|
-
|
15
|
-
<template>
|
16
|
-
<panel>
|
17
|
-
<div v-if="props.logs.length == 0">
|
18
|
-
<div class="text-gray-500">No logs to show. Are you using the correct minimum level in your config?</div>
|
19
|
-
</div>
|
20
|
-
|
21
|
-
<div v-for="log in props.logs" class="flex items-center space-y-1 space-x-3">
|
22
|
-
<div class="w-32 text-right text-gray-400">{{ log.time }}</div>
|
23
|
-
<div class="w-20 text-center">
|
24
|
-
<span
|
25
|
-
class="px-1 py-0.5 rounded text-white text-xs font-mono font-medium"
|
26
|
-
:class="{
|
27
|
-
'bg-stone-400': log.severity == 0,
|
28
|
-
'bg-blue-500': log.severity == 1,
|
29
|
-
'bg-amber-400': log.severity == 2,
|
30
|
-
'bg-red-400': log.severity == 2,
|
31
|
-
'bg-fuchsia-500': log.severity >= 3,
|
32
|
-
}"
|
33
|
-
:title="log.severity_label"
|
34
|
-
>
|
35
|
-
{{ log.severity_label }}
|
36
|
-
</span>
|
37
|
-
</div>
|
38
|
-
<div class="text-gray-800" v-html="message(log)"></div>
|
39
|
-
</div>
|
40
|
-
</panel>
|
41
|
-
</template>
|
42
|
-
|
43
|
-
<style scoped></style>
|
@@ -1,25 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import { Message } from "@/models/Request.ts"
|
3
|
-
import Panel from "@/components/panels/Panel.vue"
|
4
|
-
|
5
|
-
const props = defineProps<{
|
6
|
-
messages: Message[]
|
7
|
-
}>()
|
8
|
-
</script>
|
9
|
-
|
10
|
-
<template>
|
11
|
-
<panel>
|
12
|
-
<div class="flex flex-col space-y-8">
|
13
|
-
<!-- <div v-for="(msg, idx) in props.messages" v-text="msg.msg"></div>-->
|
14
|
-
<div v-for="(msg, _idx) in props.messages" class="space-y-3">
|
15
|
-
<div class="font-bold text-lg" v-text="msg.msg"></div>
|
16
|
-
<div class="ml-4">
|
17
|
-
<div v-if="!msg.extra">–</div>
|
18
|
-
<highlightjs v-if="msg.extra" language="json" :code="JSON.stringify(msg.extra)" />
|
19
|
-
</div>
|
20
|
-
</div>
|
21
|
-
</div>
|
22
|
-
</panel>
|
23
|
-
</template>
|
24
|
-
|
25
|
-
<style scoped></style>
|
@@ -1,37 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import Panel from "@/components/panels/Panel.vue"
|
3
|
-
|
4
|
-
const props = defineProps<{
|
5
|
-
models: { [key: string]: number }
|
6
|
-
count: number
|
7
|
-
}>()
|
8
|
-
</script>
|
9
|
-
|
10
|
-
<template>
|
11
|
-
<panel>
|
12
|
-
<div v-if="props.count == 0">
|
13
|
-
<div class="text-gray-500">No models were initialized.</div>
|
14
|
-
</div>
|
15
|
-
|
16
|
-
<table v-if="props.count > 0" class="divide-y divide-stone-300">
|
17
|
-
<thead>
|
18
|
-
<tr>
|
19
|
-
<th scope="col" class="w-36 py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-stone-900 sm:pl-0">
|
20
|
-
Model
|
21
|
-
</th>
|
22
|
-
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-stone-900">Count</th>
|
23
|
-
</tr>
|
24
|
-
</thead>
|
25
|
-
<tbody class="divide-y divide-stone-200">
|
26
|
-
<tr v-for="(v, k) in props.models" :key="k">
|
27
|
-
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-stone-900 sm:pl-0">
|
28
|
-
{{ k }}
|
29
|
-
</td>
|
30
|
-
<td class="whitespace-nowrap px-3 py-4 text-sm text-stone-500 text-center">{{ v }}</td>
|
31
|
-
</tr>
|
32
|
-
</tbody>
|
33
|
-
</table>
|
34
|
-
</panel>
|
35
|
-
</template>
|
36
|
-
|
37
|
-
<style scoped></style>
|
@@ -1,98 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import omit from "lodash/omit"
|
3
|
-
import Panel from "@/components/panels/Panel.vue"
|
4
|
-
import { BackendRequest } from "@/models/Request.ts"
|
5
|
-
import KeyValueTable from "@/components/ui/KeyValueTable.vue"
|
6
|
-
import Row from "@/components/ui/Row.vue"
|
7
|
-
import Foldable from "@/components/ui/Foldable.vue"
|
8
|
-
|
9
|
-
defineProps<{
|
10
|
-
request: BackendRequest
|
11
|
-
}>()
|
12
|
-
</script>
|
13
|
-
|
14
|
-
<template>
|
15
|
-
<div class="flex">
|
16
|
-
<div class="w-1/2">
|
17
|
-
<panel>
|
18
|
-
<h2 class="mt-0.5 mb-2 px-2 py-1 bg-stone-300 text-black tracking-wide text-xs uppercase font-bold rounded">
|
19
|
-
HTTP Request
|
20
|
-
</h2>
|
21
|
-
|
22
|
-
<key-value-table>
|
23
|
-
<row label="Method">{{ request.meta.method }}</row>
|
24
|
-
<row label="URL">{{ request.meta.path }}</row>
|
25
|
-
<row label="Params">
|
26
|
-
<highlightjs
|
27
|
-
class="text-sm"
|
28
|
-
language="json"
|
29
|
-
:code="JSON.stringify(omit(request.meta.params, ['controller', 'action']), null, 2)"
|
30
|
-
/>
|
31
|
-
</row>
|
32
|
-
<row label="Header: Version">
|
33
|
-
{{ request.request.headers["Version"] }}
|
34
|
-
</row>
|
35
|
-
<row label="Header: Cache-Control">
|
36
|
-
{{ request.request.headers["Cache-Control"] }}
|
37
|
-
</row>
|
38
|
-
</key-value-table>
|
39
|
-
|
40
|
-
<foldable class="py-4" label="All Headers">
|
41
|
-
<key-value-table>
|
42
|
-
<row v-for="(v, k) in request.request.headers" :key="k" :label="k as unknown as string">{{ v }}</row>
|
43
|
-
</key-value-table>
|
44
|
-
</foldable>
|
45
|
-
|
46
|
-
<div class="py-3 text-right italic text-sm text-stone-500">
|
47
|
-
What else would like to see here?
|
48
|
-
<a target="_blank" class="underline font-bold" href="https://github.com/julienbourdeau/debugbar/discussions"
|
49
|
-
>Tell me!</a
|
50
|
-
>
|
51
|
-
</div>
|
52
|
-
</panel>
|
53
|
-
</div>
|
54
|
-
|
55
|
-
<div class="w-1/2">
|
56
|
-
<panel>
|
57
|
-
<h2 class="mt-0.5 mb-2 px-2 py-1 bg-stone-300 text-black tracking-wide text-xs uppercase font-bold rounded">
|
58
|
-
Routing
|
59
|
-
</h2>
|
60
|
-
|
61
|
-
<key-value-table>
|
62
|
-
<row title="Controller"> {{ request.meta.controller }} > {{ request.meta.action }} </row>
|
63
|
-
</key-value-table>
|
64
|
-
</panel>
|
65
|
-
|
66
|
-
<panel>
|
67
|
-
<h2 class="mt-0.5 mb-2 px-2 py-1 bg-stone-300 text-black tracking-wide text-xs uppercase font-bold rounded">
|
68
|
-
HTTP Response
|
69
|
-
</h2>
|
70
|
-
|
71
|
-
<div v-if="!request.response?.status">
|
72
|
-
<div class="py-3 text-sm text-stone-500">
|
73
|
-
The response was not captured.
|
74
|
-
<a target="_blank" class="underline font-bold" href="https://debugbar.dev/docs/known-limitations/"
|
75
|
-
>Learn more</a
|
76
|
-
>
|
77
|
-
</div>
|
78
|
-
</div>
|
79
|
-
|
80
|
-
<div v-if="request.response?.status">
|
81
|
-
<key-value-table>
|
82
|
-
<row label="Status">{{ request.response.status }}</row>
|
83
|
-
<row label="Body">{{ request.response.body.substring(0, 140) }}</row>
|
84
|
-
<row label="Header: Content-Type">
|
85
|
-
{{ request.response.headers["Content-Type"] }}
|
86
|
-
</row>
|
87
|
-
</key-value-table>
|
88
|
-
|
89
|
-
<foldable class="py-4" label="All Headers">
|
90
|
-
<key-value-table>
|
91
|
-
<row v-for="(v, k) in request.response.headers" :key="k" :label="k as unknown as string">{{ v }}</row>
|
92
|
-
</key-value-table>
|
93
|
-
</foldable>
|
94
|
-
</div>
|
95
|
-
</panel>
|
96
|
-
</div>
|
97
|
-
</div>
|
98
|
-
</template>
|
@@ -1,17 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import type { BackendRequest } from "@/models/Request.ts"
|
3
|
-
import QueryItem from "@/components/queries/QueryItem.vue"
|
4
|
-
import Panel from "@/components/panels/Panel.vue"
|
5
|
-
|
6
|
-
const props = defineProps<{
|
7
|
-
currentRequest: BackendRequest
|
8
|
-
}>()
|
9
|
-
</script>
|
10
|
-
|
11
|
-
<template>
|
12
|
-
<panel>
|
13
|
-
<div class="flex flex-col space-y-8">
|
14
|
-
<query-item v-for="query in props.currentRequest.queries" :key="query.id" :query="query" />
|
15
|
-
</div>
|
16
|
-
</panel>
|
17
|
-
</template>
|
@@ -1,65 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import { format } from "sql-formatter"
|
3
|
-
import { ChevronDownIcon } from "@heroicons/vue/16/solid"
|
4
|
-
|
5
|
-
import { Query } from "@/models/Request.ts"
|
6
|
-
import { reactive } from "vue"
|
7
|
-
|
8
|
-
const props = defineProps<{
|
9
|
-
query: Query
|
10
|
-
}>()
|
11
|
-
|
12
|
-
const state = reactive({
|
13
|
-
isOpen: true,
|
14
|
-
isFormatted: false,
|
15
|
-
})
|
16
|
-
|
17
|
-
function copyToClipboard(text: string) {
|
18
|
-
const type = "text/plain"
|
19
|
-
const blob = new Blob([text], { type })
|
20
|
-
const data = [new ClipboardItem({ [type]: blob })]
|
21
|
-
navigator.clipboard.write(data)
|
22
|
-
}
|
23
|
-
</script>
|
24
|
-
|
25
|
-
<template>
|
26
|
-
<div>
|
27
|
-
<div class="flex items-center space-x-3">
|
28
|
-
<button class="flex items-center space-x-1" @click="state.isOpen = !state.isOpen">
|
29
|
-
<chevron-down-icon
|
30
|
-
class="size-4"
|
31
|
-
:class="{
|
32
|
-
'-rotate-90': !state.isOpen,
|
33
|
-
}"
|
34
|
-
/>
|
35
|
-
<span class="font-bold text-lg">{{ query.name }}</span>
|
36
|
-
</button>
|
37
|
-
<span v-if="props.query.cached" class="px-1 py-0.5 rounded text-xs bg-sky-600 text-white">cached</span>
|
38
|
-
<span v-if="props.query.async" class="px-1 py-0.5 rounded text-xs bg-emerald-600 text-white">async</span>
|
39
|
-
<div v-if="state.isOpen">
|
40
|
-
<span
|
41
|
-
@click="state.isFormatted = !state.isFormatted"
|
42
|
-
class="px-3 text-xs uppercase text-stone-400 cursor-pointer"
|
43
|
-
title="Format SQL query"
|
44
|
-
v-text="state.isFormatted ? 'unformat' : 'format'"
|
45
|
-
/>
|
46
|
-
<span
|
47
|
-
@click="copyToClipboard(query.sql)"
|
48
|
-
class="px-3 text-xs uppercase text-stone-400 cursor-pointer"
|
49
|
-
title="Copy SQL query to clipboard"
|
50
|
-
>copy</span
|
51
|
-
>
|
52
|
-
</div>
|
53
|
-
</div>
|
54
|
-
|
55
|
-
<div v-if="state.isOpen" class="mt-4 ml-4">
|
56
|
-
<div class="">
|
57
|
-
<highlightjs language="sql" :code="state.isFormatted ? format(query.sql) : query.sql" />
|
58
|
-
</div>
|
59
|
-
<div class="mt-3 text-stone-400 text-sm">
|
60
|
-
<div v-text="query.source[0]"></div>
|
61
|
-
<div v-if="query.source.length > 1" v-for="s in query.source.slice(1)" class="pl-4" v-text="'↳ ' + s"></div>
|
62
|
-
</div>
|
63
|
-
</div>
|
64
|
-
</div>
|
65
|
-
</template>
|
@@ -1,39 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
import { reactive } from "vue"
|
3
|
-
import { ChevronDownIcon } from "@heroicons/vue/16/solid"
|
4
|
-
|
5
|
-
const props = withDefaults(
|
6
|
-
defineProps<{
|
7
|
-
label: string
|
8
|
-
isOpen?: boolean
|
9
|
-
}>(),
|
10
|
-
{
|
11
|
-
isOpen: false,
|
12
|
-
}
|
13
|
-
)
|
14
|
-
|
15
|
-
const state = reactive({
|
16
|
-
isOpen: props.isOpen,
|
17
|
-
})
|
18
|
-
</script>
|
19
|
-
|
20
|
-
<template>
|
21
|
-
<div>
|
22
|
-
<div>
|
23
|
-
<button class="flex items-center space-x-1" @click="state.isOpen = !state.isOpen">
|
24
|
-
<chevron-down-icon
|
25
|
-
class="size-4"
|
26
|
-
:class="{
|
27
|
-
'-rotate-90': !state.isOpen,
|
28
|
-
}"
|
29
|
-
/>
|
30
|
-
<span class="font-medium">{{ props.label }}</span>
|
31
|
-
</button>
|
32
|
-
</div>
|
33
|
-
|
34
|
-
<div v-if="state.isOpen">
|
35
|
-
<slot />
|
36
|
-
</div>
|
37
|
-
</div>
|
38
|
-
</template>
|
39
|
-
<style scoped></style>
|
@@ -1,16 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
const props = defineProps<{
|
3
|
-
keyLabel?: string
|
4
|
-
valueLabel?: string
|
5
|
-
}>()
|
6
|
-
</script>
|
7
|
-
|
8
|
-
<template>
|
9
|
-
<table class="break-all w-full border-separate border-spacing-1">
|
10
|
-
<tr v-if="props.keyLabel || props.valueLabel">
|
11
|
-
<th v-text="props.keyLabel" class="bg-amber-50 w-40 px-3 py-1"></th>
|
12
|
-
<th v-text="props.valueLabel" class="bg-amber-50 px-3 py-1"></th>
|
13
|
-
</tr>
|
14
|
-
<slot />
|
15
|
-
</table>
|
16
|
-
</template>
|
@@ -1,14 +0,0 @@
|
|
1
|
-
<script setup lang="ts">
|
2
|
-
const props = defineProps<{
|
3
|
-
label?: string
|
4
|
-
}>()
|
5
|
-
</script>
|
6
|
-
|
7
|
-
<template>
|
8
|
-
<tr>
|
9
|
-
<td v-text="props.label" class="w-40 font-medium bg-stone-50 px-3 py-1"></td>
|
10
|
-
<td class="px-3 py-1"><slot /></td>
|
11
|
-
</tr>
|
12
|
-
</template>
|
13
|
-
|
14
|
-
<style scoped></style>
|