Skip to content

Commit a68d676

Browse files
committed
layout update
1 parent fabac2c commit a68d676

6 files changed

Lines changed: 347 additions & 42 deletions

File tree

web/public/trail_dataset/FLAURA_results.csv

Lines changed: 130 additions & 0 deletions
Large diffs are not rendered by default.

web/src/Main.vue

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<template>
2-
<div>
2+
<div class="page">
33
<Banner @home="activeView = 'home'" />
4-
<div class="container">
4+
<div class="content">
55
<HomeView v-if="activeView === 'home'" @start="activeView = 'step'" />
66
<StepView v-else-if="activeView === 'step'" @result="onStepResult" />
77
<ResultView v-else-if="activeView === 'result'" :result="resultPayload" />
88
</div>
99
</div>
10+
1011
</template>
1112

1213
<script setup>
@@ -25,9 +26,31 @@ function onStepResult(payload) {
2526
</script>
2627

2728
<style scoped>
28-
.container {
29+
.page {
30+
--page-bg: rgb(241, 245, 259); /* page background color */
31+
--content-gap: 32px; /* ≈ 1rem: outer spacing around card */
32+
--card-radius: 12px; /* card border radius */
33+
--card-padding: 16px; /* inner padding inside card */
34+
35+
min-height: 100vh;
36+
background-color: var(--page-bg);
37+
display: flex;
38+
flex-direction: column;
39+
}
40+
41+
.content {
42+
max-width: 1600px;
2943
margin: 0 auto;
30-
padding: 2rem;
31-
text-align: center;
44+
padding: var(--content-gap);
45+
width: 100%;
46+
flex: 1;
47+
display: block;
48+
}
49+
50+
@media (min-width: 1440px) {
51+
.content {
52+
padding-left: calc(var(--content-gap) * 0.75);
53+
padding-right: calc(var(--content-gap) * 0.75);
54+
}
3255
}
3356
</style>

web/src/components/Banner.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="banner" @click="$emit('home')">
33
<h1 class="banner-title">
4-
<font-awesome-icon :icon="['fas', 'route']" />
4+
<font-awesome-icon :icon="['fas', 'route']" style="color: #1ca40a;" />
55
TrialMap
66
</h1>
77
</div>
@@ -14,18 +14,18 @@ defineEmits(['home'])
1414

1515
<style scoped>
1616
.banner {
17-
height: 96px;
18-
background-color: #e7fff2;
17+
height: 64px;
18+
background-color: #ffffff;
1919
display: flex;
2020
align-items: center;
2121
padding: 0 48px;
2222
justify-content: space-between;
23-
color: rgb(0, 0, 0);
24-
border-bottom: 2px solid #0b8538;
23+
border-bottom: 1px solid #e5e7eb;
2524
}
2625
.banner-title {
27-
font-size: 32px;
26+
font-size: 24px;
2827
font-weight: 600;
28+
color: #1ca40a;
2929
cursor: pointer;
3030
}
3131
</style>

web/src/views/HomeView.vue

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
<template>
2-
<div class="container">
3-
<h1>Welcome to TrialMap!</h1>
4-
<p>TrialMap is an end-to-end machine learning framework for optimizing trial eligibility criteria using real-world data.</p>
5-
<img src="../imgs/homepage_demo.png" alt="TrialMap" class="homepage-demo"/>
6-
<Button label="Start Your Journey Now !" @click="$emit('start')"/>
2+
<div class="home-card">
3+
<div class="container">
4+
<h1>Welcome to TrialMap!</h1>
5+
<p>TrialMap is an end-to-end machine learning framework for optimizing trial eligibility criteria using real-world data.</p>
6+
<img src="../imgs/homepage_demo.png" alt="TrialMap" class="homepage-demo"/>
7+
<Button label="Start Your Journey Now !" @click="$emit('start')"/>
8+
</div>
79
</div>
10+
811
</template>
912

1013
<script setup>
1114
defineEmits(['start'])
1215
</script>
1316

1417
<style scoped>
18+
.home-card {
19+
background: #ffffff;
20+
border: 1px solid #e5e7eb;
21+
border-radius: 12px;
22+
min-height: calc(100vh - 64px - 64px);
23+
display: flex;
24+
align-items: center;
25+
justify-content: center;
26+
}
1527
.container {
1628
margin: 0 auto;
1729
display: flex;
1830
flex-direction: column;
1931
align-items: center;
2032
justify-content: center;
21-
padding: 2rem;
33+
padding: 1rem; /* inner spacing; outer spacing handled by parent card */
2234
text-align: center;
2335
}
2436
.homepage-demo {

web/src/views/ResultView.vue

Lines changed: 134 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,147 @@
11
<template>
22
<div class="result">
3-
<h2>Selected Summary</h2>
4-
<ul>
5-
<li><strong>Cancer Type</strong>: {{ result?.selectedCancerType || '-' }}</li>
6-
<li><strong>Treatment</strong>: {{ result?.selectedTreatment || '-' }}</li>
7-
<li><strong>Endpoint</strong>: {{ result?.selectedEndpoint || '-' }}</li>
8-
<li><strong>Criteria (names)</strong>: {{ result?.selectedCriteria?.join(', ') || '-' }}</li>
9-
</ul>
3+
<div class="result-layout">
4+
<div class="col-left">
5+
<div class="row-2">
6+
<div class="r-card">
7+
<h3 class="r-title">Cancer</h3>
8+
<div class="r-value">{{ result?.selectedCancerType || '-' }}</div>
9+
</div>
10+
<div class="r-card">
11+
<h3 class="r-title">Line of Therapy</h3>
12+
<div class="r-value">{{ resultRelatedMetadata.lineOfTherapy ?? '-' }}</div>
13+
</div>
14+
</div>
15+
16+
<div class="r-card">
17+
<h3 class="r-title">Regimens</h3>
18+
<DataTable :value="regimenRows" tableStyle="min-width: 16rem" class="small-table">
19+
<Column field="label" header="name" />
20+
<Column field="value" header="value" />
21+
</DataTable>
22+
</div>
23+
24+
<div class="r-card">
25+
<h3 class="r-title">Endpoint</h3>
26+
<div class="r-value">{{ result?.selectedEndpoint || '-' }}</div>
27+
</div>
28+
29+
<div class="r-card">
30+
<h3 class="r-title">Criteria</h3>
31+
<DataTable :value="criteriaTableRows" tableStyle="min-width: 24rem" class="criteria-table">
32+
<Column header="#" :style="{width:'40px'}">
33+
<template #body="{ index }">{{ index + 1 }}</template>
34+
</Column>
35+
<Column field="type" header="type" :style="{width:'90px'}" />
36+
<Column field="criteria_description" header="criteria">
37+
<template #body="{ data }">
38+
<div class="criteria-desc">{{ data.criteria_description }}</div>
39+
</template>
40+
</Column>
41+
<Column header="must have" :style="{width:'90px', textAlign:'center'}">
42+
<template #body="{ data }">
43+
<div style="display:flex;justify-content:center;">
44+
<i v-if="selectedSet.has(data.criteria_name)" class="pi pi-check" style="color:#16a34a;"></i>
45+
</div>
46+
</template>
47+
</Column>
48+
</DataTable>
49+
</div>
50+
</div>
51+
52+
<div class="col-right">
53+
<div class="r-card" style="min-height: 240px;"></div>
54+
</div>
55+
</div>
1056
</div>
1157
</template>
1258

1359
<script setup>
60+
import {ref, onMounted, computed} from 'vue'
61+
import * as XLSX from 'xlsx'
62+
import DataTable from 'primevue/datatable'
63+
import Column from 'primevue/column'
1464
const props = defineProps({
1565
result: { type: Object, default: () => ({}) }
1666
})
67+
68+
const resultRelatedMetadata = ref({})
69+
const trailResult = ref([])
70+
const resultColumns = ref([])
71+
const regimenRows = ref([])
72+
const criteriaTableRows = ref([])
73+
const selectedSet = computed(() => new Set(props.result.selectedCriteria || []))
74+
75+
onMounted(async () => {
76+
const url = new URL('../../public/data/meta_data.xlsx', import.meta.url)
77+
const res = await fetch(url)
78+
const ab = await res.arrayBuffer()
79+
const wb = XLSX.read(ab, { type: 'array' })
80+
81+
const wsMetadata = wb.Sheets[wb.SheetNames[0]]
82+
const wsTrialCriteria = wb.Sheets[wb.SheetNames[1]]
83+
const wsCriteria = wb.Sheets[wb.SheetNames[2]]
84+
85+
const metaRows = XLSX.utils.sheet_to_json(wsMetadata, { defval: null })
86+
const trialCriteriaRows = XLSX.utils.sheet_to_json(wsTrialCriteria, { defval: null })
87+
const criteriaRows = XLSX.utils.sheet_to_json(wsCriteria, { defval: null })
88+
89+
const metaRow = metaRows.find(r => r.trial_name === props.result.selectedTreatment)
90+
const criteriaNames = new Set(
91+
trialCriteriaRows
92+
.filter(r => r.trial_name === props.result.selectedTreatment)
93+
.map(r => r.criteria_name)
94+
)
95+
const selectedCriteriaRows = criteriaRows.filter(r => criteriaNames.has(r.criteria_name))
96+
97+
resultRelatedMetadata.value = {
98+
cancerType: props.result.selectedCancerType,
99+
trail: props.result.selectedTreatment,
100+
lineOfTherapy: metaRow?.line_of_therapy ?? null,
101+
treatment: metaRow?.treatment ?? props.result.selectedTreatment,
102+
control: metaRow?.control ?? null,
103+
endpoint: props.result.selectedEndpoint,
104+
criteria: selectedCriteriaRows,
105+
selectedCriteria: props.result.selectedCriteria
106+
}
107+
regimenRows.value = [
108+
{ label: 'treatment', value: resultRelatedMetadata.value.treatment || '-' },
109+
{ label: 'control', value: resultRelatedMetadata.value.control || '-' }
110+
]
111+
criteriaTableRows.value = resultRelatedMetadata.value.criteria || []
112+
const filepath = `../../public/trail_dataset/${props.result.selectedTreatment}_results.csv`
113+
const fileUrl = new URL(filepath, import.meta.url)
114+
const fileRes = await fetch(fileUrl)
115+
if (fileRes.status === 200) {
116+
const fileAb = await fileRes.arrayBuffer()
117+
const fileWb = XLSX.read(fileAb, { type: 'array' })
118+
const fileSheet = fileWb.SheetNames[0]
119+
const fileWs = fileWb.Sheets[fileSheet]
120+
trailResult.value = XLSX.utils.sheet_to_json(fileWs, { defval: null })
121+
resultColumns.value = trailResult.value.length ? Object.keys(trailResult.value[0]) : []
122+
console.log('Loaded CSV rows:', trailResult.value.length)
123+
} else {
124+
console.error('File not found:', filepath)
125+
}
126+
})
17127
</script>
18128
19129
<style scoped>
20-
.result { padding: 16px; text-align: left; }
21-
.result ul { list-style: none; padding: 0; }
22-
.result li { margin: 6px 0; }
130+
.result { padding: 0; text-align: left; }
131+
.result-layout { display: grid; grid-template-columns: 2fr 3fr; gap: 12px; }
132+
.col-left, .col-right { display: flex; flex-direction: column; gap: 16px; }
133+
.row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
134+
.r-card { background: #ffffff; border: 1px solid #e5e7eb; border-radius: 10px; padding: 8px; }
135+
.r-title { margin: 0 0 4px 0; font-size: 13px; font-weight: 600; }
136+
.r-value { color: #111827; font-size: 13px; }
137+
.small-table :deep(.p-datatable) { font-size: 12px; }
138+
.criteria-table :deep(.p-datatable) { font-size: 11px; table-layout: fixed; }
139+
.criteria-table :deep(.p-datatable .p-datatable-thead > tr > th) { padding: 3px 6px; }
140+
.criteria-table :deep(.p-datatable .p-datatable-tbody > tr > td) { padding: 3px 6px; }
141+
.criteria-desc {
142+
display: -webkit-box;
143+
-webkit-line-clamp: 2;
144+
-webkit-box-orient: vertical;
145+
overflow: hidden;
146+
}
23147
</style>

web/src/views/StepView.vue

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,22 @@
5050
<StepPanel>
5151
<div class="panel-content">
5252
<h3 style="margin: 0 0 12px 0;">Select the eligibility criteria:</h3>
53-
<DataTable :value="filteredCriteria" tableStyle="min-width: 40rem">
54-
<Column header="#">
55-
<template #body="{ index }">{{ index + 1 }}</template>
56-
</Column>
57-
<Column field="type" header="type" />
58-
<Column field="criteria_description" header="criteria" />
59-
<Column header="Must apply" style="width: 8rem; text-align:center;">
60-
<template #body="{ data, index }">
61-
<div style="display:flex;justify-content:center;">
62-
<Checkbox v-model="selectedCriteria" :value="data.criteria_name" :inputId="`crit-${index}`" />
63-
</div>
64-
</template>
65-
</Column>
66-
</DataTable>
53+
<div class="table-card">
54+
<DataTable :value="filteredCriteria" tableStyle="min-width: 40rem">
55+
<Column header="#">
56+
<template #body="{ index }">{{ index + 1 }}</template>
57+
</Column>
58+
<Column field="type" header="type" />
59+
<Column field="criteria_description" header="criteria" />
60+
<Column header="Must apply" style="width: 8rem; text-align:center;">
61+
<template #body="{ data, index }">
62+
<div style="display:flex;justify-content:center;">
63+
<Checkbox v-model="selectedCriteria" :value="data.criteria_name" :inputId="`crit-${index}`" />
64+
</div>
65+
</template>
66+
</Column>
67+
</DataTable>
68+
</div>
6769
</div>
6870
<div style="display:flex; gap:8px; margin-top:12px;">
6971
<Button label="Undo" severity="secondary" @click="onclickUndoButton('4')" />
@@ -109,6 +111,7 @@ const selectedCriteria = ref([])
109111
onMounted(async () => {
110112
try {
111113
// Resolve the asset URL via Vite
114+
flushAll()
112115
const url = new URL('../../public/data/meta_data.xlsx', import.meta.url)
113116
const res = await fetch(url)
114117
const ab = await res.arrayBuffer()
@@ -188,7 +191,7 @@ function goResult() {
188191
selectedEndpoint: selectedEndpoint.value,
189192
selectedCriteria: selectedCriteria.value
190193
})
191-
flushAll()
194+
192195
}
193196
194197
function flushAll() {
@@ -204,6 +207,19 @@ function flushAll() {
204207
width: 100%;
205208
margin: 0 auto;
206209
padding: 16px;
210+
background: #ffffff;
211+
border: 1px solid #e5e7eb;
212+
border-radius: 12px;
213+
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 1px 3px rgba(16, 24, 40, 0.10);
214+
}
215+
.table-card {
216+
width: 100%;
217+
background: #ffffff;
218+
border: 1px solid #e5e7eb;
219+
border-radius: 12px;
220+
padding: 12px;
221+
display: flex;
222+
justify-content: center; /* center DataTable horizontally */
207223
}
208224
.panel-content {
209225
display: flex;

0 commit comments

Comments
 (0)