Skip to content

Commit c35e394

Browse files
tomolopolisTom Searle
andauthored
Trainer new header (#179)
* CU-869avhnrn: medcattrainer: feat: new app header style * logo for new app header * fix frontend test --------- Co-authored-by: Tom Searle <[email protected]>
1 parent a5b2bfa commit c35e394

File tree

5 files changed

+214
-46
lines changed

5 files changed

+214
-46
lines changed

medcat-trainer/webapp/frontend/package-lock.json

Lines changed: 0 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

medcat-trainer/webapp/frontend/src/App.vue

Lines changed: 202 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,46 @@
11
<template>
22
<div class="full-height">
3-
<nav class="navbar">
4-
<router-link class="app-name" to="/">Med<img class="icon" src="./assets/cat-logo.png" >AT</router-link>
5-
<router-link class="navbar-brand" to="/">Projects</router-link>
6-
<router-link class="navbar-brand" to="/metrics-reports">Metrics</router-link>
7-
<router-link class="navbar-brand" to="/model-explore">Concepts</router-link>
8-
<router-link class="navbar-brand" to="/demo">Try Model</router-link>
9-
<span class="version-id">{{ version }}</span>
10-
<a class="navbar-brand ml-auto small">
11-
<span v-if="!uname" class="link" @click="openLogin">Login</span>
12-
<span v-else>
13-
<span class="link">
14-
({{ uname }}) <font-awesome-icon icon="user"></font-awesome-icon>
15-
</span>
16-
<span class="link logout" @click="logout">logout</span>
17-
</span>
18-
</a>
19-
</nav>
20-
<router-view/>
3+
<header class="header-gradient">
4+
<div class="header-container">
5+
<div class="header-content">
6+
<!-- CogStack Branding and App Name -->
7+
<div class="branding-section">
8+
<div class="logo-container">
9+
<img src="./assets/brand-logo.png" alt="CogStack Logo" class="brand-logo" />
10+
</div>
11+
<div class="divider"></div>
12+
<h1 class="app-title" @click="navigateToHome">
13+
Med<img src="./assets/cat-logo.png" alt="MedCAT Logo" class="cat-logo" />AT
14+
</h1>
15+
<span class="version-id">{{ version }}</span>
16+
17+
<!-- Navigation Links -->
18+
<div class="navigation-links">
19+
<router-link class="nav-link" to="/">Projects</router-link>
20+
<router-link class="nav-link" to="/metrics-reports">Metrics</router-link>
21+
<router-link class="nav-link" to="/model-explore">Concepts</router-link>
22+
<router-link class="nav-link" to="/demo">Try Model</router-link>
23+
</div>
24+
</div>
25+
26+
27+
28+
<!-- Action Buttons -->
29+
<div class="action-buttons">
30+
<div class="user-section">
31+
<span v-if="!uname" class="login-link" @click="openLogin">Login</span>
32+
<span v-else class="user-info">
33+
<span class="username">({{ uname }}) <font-awesome-icon icon="user"></font-awesome-icon></span>
34+
<span class="logout-link" @click="logout">logout</span>
35+
</span>
36+
</div>
37+
</div>
38+
</div>
39+
</div>
40+
</header>
41+
<main class="main-content">
42+
<router-view/>
43+
</main>
2144
<login v-if="!useOidc && loginModal"
2245
@login:success="loginSuccessful"
2346
:closable="true"
@@ -43,6 +66,10 @@ export default {
4366
}
4467
},
4568
methods: {
69+
navigateToHome () {
70+
this.$router.push('/')
71+
},
72+
4673
openLogin () {
4774
if (!this.useOidc) {
4875
this.loginModal = true
@@ -115,6 +142,162 @@ export default {
115142
</script>
116143

117144
<style scoped lang="scss">
145+
.full-height {
146+
min-height: 100vh;
147+
}
148+
149+
.header-gradient {
150+
background: linear-gradient(135deg, #126cad 0%, #3d0372 50%, #8e1b73 100%);
151+
position: fixed;
152+
top: 0;
153+
left: 0;
154+
right: 0;
155+
z-index: 50;
156+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
157+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
158+
}
159+
160+
.header-container {
161+
width: 100%;
162+
padding: 0 24px;
163+
}
164+
165+
.header-content {
166+
display: flex;
167+
align-items: center;
168+
justify-content: space-between;
169+
padding: 16px 0;
170+
min-height: 60px;
171+
}
172+
173+
.main-content {
174+
padding-top: 81px;
175+
height: 100vh; /* Account for header height (60px + 32px padding) */
176+
}
177+
178+
.branding-section {
179+
display: flex;
180+
align-items: center;
181+
gap: 16px;
182+
}
183+
184+
.logo-container {
185+
display: flex;
186+
align-items: center;
187+
}
188+
189+
.brand-logo {
190+
height: 48px;
191+
width: auto;
192+
}
193+
194+
.divider {
195+
height: 24px;
196+
width: 1px;
197+
background-color: rgba(255, 255, 255, 0.3);
198+
}
199+
200+
.app-title {
201+
font-size: 24px;
202+
font-weight: bold;
203+
color: white;
204+
display: flex;
205+
align-items: center;
206+
gap: 4px;
207+
cursor: pointer;
208+
margin: 0;
209+
text-decoration: none;
210+
211+
&:hover {
212+
color: white;
213+
text-decoration: none;
214+
}
215+
}
216+
217+
.cat-logo {
218+
height: 32px;
219+
width: 32px;
220+
}
221+
222+
.navigation-links {
223+
display: flex;
224+
gap: 20px;
225+
}
226+
227+
.nav-link {
228+
color: white;
229+
text-decoration: none;
230+
padding: 8px 0;
231+
border-bottom: 1px solid transparent;
232+
transition: all 0.2s ease;
233+
234+
&:hover {
235+
color: white;
236+
border-bottom: 1px solid white;
237+
text-decoration: none;
238+
}
239+
240+
&:focus {
241+
color: white
242+
}
243+
244+
&.router-link-active {
245+
border-bottom: 1px solid white;
246+
}
247+
}
248+
249+
.action-buttons {
250+
display: flex;
251+
gap: 8px;
252+
align-items: center;
253+
}
254+
255+
.user-section {
256+
display: flex;
257+
align-items: center;
258+
gap: 16px;
259+
margin-left: 16px;
260+
}
261+
262+
.login-link {
263+
color: white;
264+
cursor: pointer;
265+
font-size: 14px;
266+
267+
&:hover {
268+
opacity: 0.8;
269+
}
270+
}
271+
272+
.user-info {
273+
display: flex;
274+
align-items: center;
275+
gap: 16px;
276+
color: white;
277+
font-size: 14px;
278+
}
279+
280+
.username {
281+
display: flex;
282+
align-items: center;
283+
gap: 4px;
284+
}
285+
286+
.logout-link {
287+
cursor: pointer;
288+
289+
&:hover {
290+
opacity: 0.8;
291+
}
292+
}
293+
294+
.version-id {
295+
font-size: 10px;
296+
color: rgba(255, 255, 255, 0.7);
297+
margin-left: 16px;
298+
}
299+
300+
// Legacy styles for backward compatibility
118301
.right {
119302
float: right;
120303
}
@@ -160,7 +343,7 @@ export default {
160343
}
161344
162345
.link {
163-
display:inline-block;
346+
display: inline-block;
164347
height: 25px;
165348
cursor: pointer;
166349
@@ -179,12 +362,4 @@ export default {
179362
bottom: 7px;
180363
}
181364
182-
.version-id {
183-
display: inline-block;
184-
float: right;
185-
font-size: 10px;
186-
padding: 0 20px;
187-
color: $color-2;
188-
}
189-
190365
</style>
90.9 KB
Loading

medcat-trainer/webapp/frontend/src/tests/App.spec.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe('App.vue', () => {
3636
$cookies: {
3737
get: vi.fn((key) => key === 'username' ? 'testUser' : null),
3838
remove: vi.fn()
39-
}
39+
}
4040
},
4141
stubs: ['login', 'font-awesome-icon', 'router-view']
4242
}
@@ -49,12 +49,11 @@ describe('App.vue', () => {
4949

5050
// Check that router-link stubs exist with correct props
5151
const links = wrapper.findAllComponents({ name: 'RouterLink' })
52-
expect(links.length).toBeGreaterThanOrEqual(5)
52+
expect(links.length).toBeGreaterThanOrEqual(4)
5353
expect(links[0].props('to')).toBe('/')
54-
expect(links[1].props('to')).toBe('/')
55-
expect(links[2].props('to')).toBe('/metrics-reports')
56-
expect(links[3].props('to')).toBe('/model-explore')
57-
expect(links[4].props('to')).toBe('/demo')
54+
expect(links[1].props('to')).toBe('/metrics-reports')
55+
expect(links[2].props('to')).toBe('/model-explore')
56+
expect(links[3].props('to')).toBe('/demo')
5857
})
5958

6059

@@ -84,9 +83,9 @@ describe('App.vue', () => {
8483
mocks: {
8584
$http: { get: mockGet },
8685
$cookies: {
87-
get: vi.fn((key) => key === 'username' ? 'testUser' : null),
88-
remove: vi.fn()
89-
}
86+
get: vi.fn((key) => key === 'username' ? 'testUser' : null),
87+
remove: vi.fn()
88+
}
9089
},
9190
stubs: ['login', 'font-awesome-icon', 'router-link', 'router-view']
9291
},
@@ -102,6 +101,6 @@ describe('App.vue', () => {
102101
await flushPromises()
103102

104103
expect(wrapper.text()).toContain('testUser');
105-
expect(wrapper.find('.logout').exists()).toBe(true);
106-
});
107-
});
104+
expect(wrapper.find('.logout-link').exists()).toBe(true);
105+
});
106+
});

medcat-trainer/webapp/frontend/src/views/TrainAnnotations.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ $app-header-height: 60px;
906906
907907
.app-container {
908908
display: flex;
909-
height: calc(100% - #{$app-header-height});
909+
height: 100%;
910910
flex-direction: column;
911911
padding: 5px;
912912
}

0 commit comments

Comments
 (0)