Skip to content

Commit 611bee3

Browse files
committed
WIP message docs improvement
1 parent 7487c89 commit 611bee3

File tree

2 files changed

+130
-20
lines changed

2 files changed

+130
-20
lines changed

src/components/CodeBlock.vue

Lines changed: 118 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@
22
- Open Bank Project - API Explorer II
33
- Copyright (C) 2023-2024, TESOBE GmbH
44
-
5-
- This program is free software: you can redistribute it and/or modify
5+
<div v-if="copyable" class="code-block-header">
6+
<button
7+
@click="copyToClipboard"
8+
class="copy-button"
9+
:class="{ 'copied': copied }"
10+
>
11+
<el-icon v-if="!copied" class="icon"><DocumentCopy /></el-icon>
12+
<el-icon v-else class="icon"><Check /></el-icon>
13+
<span v-if="!copied">Copy</span>
14+
<span v-else>Copied!</span>
15+
</button>
16+
</div>rogram is free software: you can redistribute it and/or modify
617
- it under the terms of the GNU Affero General Public License as published by
718
- the Free Software Foundation, either version 3 of the License, or
819
- (at your option) any later version.
@@ -27,6 +38,7 @@
2738

2839
<script setup lang="ts">
2940
import { ref, onMounted, onUpdated, nextTick } from 'vue'
41+
import { DocumentCopy, Check } from '@element-plus/icons-vue'
3042
3143
// Declare global hljs
3244
declare global {
@@ -40,13 +52,16 @@ declare global {
4052
interface Props {
4153
code: any
4254
language?: string
55+
copyable?: boolean
4356
}
4457
4558
const props = withDefaults(defineProps<Props>(), {
46-
language: 'json'
59+
language: 'json',
60+
copyable: false
4761
})
4862
4963
const codeBlockRef = ref<HTMLElement>()
64+
const copied = ref(false)
5065
5166
const highlight = async () => {
5267
await nextTick()
@@ -58,6 +73,18 @@ const highlight = async () => {
5873
}
5974
}
6075
76+
const copyToClipboard = async () => {
77+
try {
78+
await navigator.clipboard.writeText(formattedCode)
79+
copied.value = true
80+
setTimeout(() => {
81+
copied.value = false
82+
}, 2000)
83+
} catch (err) {
84+
console.error('Failed to copy: ', err)
85+
}
86+
}
87+
6188
onMounted(() => {
6289
highlight()
6390
})
@@ -73,7 +100,29 @@ const formattedCode = typeof props.code === 'string'
73100

74101
<template>
75102
<div ref="codeBlockRef" class="code-block">
76-
<pre><code :class="language">{{ formattedCode }}</code></pre>
103+
<div v-if="copyable" class="code-block-header">
104+
<button
105+
@click="copyToClipboard"
106+
class="copy-button"
107+
:class="{ 'copied': copied }"
108+
>
109+
<span v-if="!copied">
110+
<el-icon :size="10">
111+
<DocumentCopy />
112+
</el-icon>
113+
Copy
114+
</span>
115+
<span v-else>
116+
<el-icon :size="10">
117+
<Check />
118+
</el-icon>
119+
Copied!
120+
</span>
121+
</button>
122+
</div>
123+
<div class="code-container">
124+
<pre><code :class="language">{{ formattedCode }}</code></pre>
125+
</div>
77126
</div>
78127
</template>
79128

@@ -84,9 +133,52 @@ const formattedCode = typeof props.code === 'string'
84133
overflow: hidden;
85134
background: #1e1e1e;
86135
border: 1px solid #333;
136+
position: relative;
87137
}
88138
89-
.code-block pre {
139+
.code-block-header {
140+
background: #2d2d2d;
141+
padding: 0.5rem 1rem;
142+
border-bottom: 1px solid #333;
143+
display: flex;
144+
justify-content: flex-end;
145+
}
146+
147+
.copy-button {
148+
background: #444;
149+
border: 1px solid #666;
150+
color: #ddd;
151+
padding: 0.25rem 0.75rem;
152+
border-radius: 4px;
153+
cursor: pointer;
154+
font-size: 12px;
155+
transition: all 0.2s ease;
156+
display: flex;
157+
align-items: center;
158+
gap: 0.25rem;
159+
}
160+
161+
.copy-button .icon {
162+
font-size: 14px;
163+
}
164+
165+
.copy-button:hover {
166+
background: #555;
167+
border-color: #777;
168+
}
169+
170+
.copy-button.copied {
171+
background: #4caf50;
172+
border-color: #4caf50;
173+
color: white;
174+
}
175+
176+
.code-container {
177+
max-height: 500px;
178+
overflow-y: auto;
179+
}
180+
181+
.code-container pre {
90182
margin: 0;
91183
padding: 1.5rem;
92184
background: #1e1e1e;
@@ -99,7 +191,7 @@ const formattedCode = typeof props.code === 'string'
99191
word-wrap: break-word;
100192
}
101193
102-
.code-block code {
194+
.code-container code {
103195
background: transparent;
104196
padding: 0;
105197
border-radius: 0;
@@ -108,21 +200,38 @@ const formattedCode = typeof props.code === 'string'
108200
}
109201
110202
/* Custom scrollbar for code blocks */
111-
.code-block pre::-webkit-scrollbar {
203+
.code-container::-webkit-scrollbar {
204+
width: 8px;
205+
}
206+
207+
.code-container::-webkit-scrollbar-track {
208+
background: #2d2d2d;
209+
}
210+
211+
.code-container::-webkit-scrollbar-thumb {
212+
background: #555;
213+
border-radius: 4px;
214+
}
215+
216+
.code-container::-webkit-scrollbar-thumb:hover {
217+
background: #777;
218+
}
219+
220+
.code-container pre::-webkit-scrollbar {
112221
height: 8px;
113222
width: 8px;
114223
}
115224
116-
.code-block pre::-webkit-scrollbar-track {
225+
.code-container pre::-webkit-scrollbar-track {
117226
background: #2d2d2d;
118227
}
119228
120-
.code-block pre::-webkit-scrollbar-thumb {
229+
.code-container pre::-webkit-scrollbar-thumb {
121230
background: #555;
122231
border-radius: 4px;
123232
}
124233
125-
.code-block pre::-webkit-scrollbar-thumb:hover {
234+
.code-container pre::-webkit-scrollbar-thumb:hover {
126235
background: #777;
127236
}
128237

src/views/MessageDocsView.vue

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import CodeBlock from '../components/CodeBlock.vue';
3737
let connector = connectors[0]
3838
const route = useRoute()
3939
const groupedMessageDocs = ref(inject(obpGroupedMessageDocsKey)!)
40-
const messageDocs = ref({})
40+
const messageDocs = ref(null as any)
4141
4242
const activeNames = ref(['1', '2', '3', '4', '5', '6'])
4343
@@ -73,7 +73,7 @@ function showDependentEndpoints(value: any) {
7373
<SearchNav />
7474
</el-aside>
7575
<el-main>
76-
<el-container class="main">
76+
<el-container class="main" direction="vertical">
7777
<div v-for="(group, key) of messageDocs" :key="key">
7878
<div v-for="(value, key) of group" :key="value">
7979
<el-divider></el-divider>
@@ -88,27 +88,29 @@ function showDependentEndpoints(value: any) {
8888
<section class="topics">
8989
<div>
9090
<strong>Outbound Topic: </strong>
91-
<el-tag type="info" round>{{ value.outbound_topic }}</el-tag>
91+
<el-tag v-if="value.outbound_topic" type="info" round>{{ value.outbound_topic }}</el-tag>
92+
<el-tag v-else type="error" round>None</el-tag>
9293
</div>
9394
<div>
9495
<strong>Inbound Topic: </strong>
95-
<el-tag type="info" round>{{ value.inbound_topic }}</el-tag>
96+
<el-tag v-if="value.inbound_topic" type="info" round>{{ value.inbound_topic }}</el-tag>
97+
<el-tag v-else type="error" round>None</el-tag>
9698
</div>
9799
</section>
98100

99101
<section>
100102
<h3>Example Outbound Message</h3>
101-
<CodeBlock :code="value.example_outbound_message" />
103+
<CodeBlock :code="value.example_outbound_message" copyable />
102104
</section>
103105

104106
<section>
105107
<h3>Example Inbound Message</h3>
106-
<CodeBlock :code="value.example_inbound_message" />
108+
<CodeBlock :code="value.example_inbound_message" copyable />
107109
</section>
108110

109111
<section v-if="showRequiredFieldInfo(value.requiredFieldInfo)">
110112
<h3>Required Fields</h3>
111-
<CodeBlock :code="value.requiredFieldInfo" />
113+
<CodeBlock :code="value.requiredFieldInfo" copyable />
112114
</section>
113115

114116
<section v-if="showDependentEndpoints(value.dependent_endpoints)">
@@ -181,7 +183,8 @@ function showDependentEndpoints(value: any) {
181183
182184
.main {
183185
height: 100%;
184-
overflow: scroll;
186+
overflow-y: auto;
187+
flex-direction: column;
185188
}
186189
187190
.search-nav {
@@ -196,9 +199,7 @@ main {
196199
font-family: 'Roboto';
197200
}
198201
199-
span {
200-
font-size: 28px;
201-
}
202+
202203
203204
div {
204205
font-size: 14px;

0 commit comments

Comments
 (0)