Skip to content

Commit 119ff4b

Browse files
committed
feat: responsive device container
- provides a responsive window for previewing how the application appears on multiple browsers - dark mode needs work - state is not currently persisted
1 parent a7df7c0 commit 119ff4b

2 files changed

Lines changed: 469 additions & 16 deletions

File tree

src/core/SmileApp.vue

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { ref, computed } from 'vue'
1414
import DeveloperNavBar from '@/dev/developer_mode/DeveloperNavBar.vue'
1515
import DevConsoleBar from '@/dev/developer_mode/DevConsoleBar.vue'
1616
import DevSideBar from '@/dev/developer_mode/DevSideBar.vue'
17-
1817
/**
1918
* Presentation mode components
2019
* @requires PresentationNavBar Navigation bar for presentation mode
@@ -29,6 +28,8 @@ import PresentationNavBar from '@/dev/presentation_mode/PresentationNavBar.vue'
2928
import StatusBar from '@/builtins/navbars/StatusBar.vue'
3029
import WindowSizerView from '@/builtins/window_sizer/WindowSizerView.vue'
3130
31+
import ResponsiveDeviceContainer from '@/dev/developer_mode/ResponsiveDeviceContainer.vue'
32+
3233
/**
3334
* Import API and notification components
3435
* @requires useAPI SMILE API composable
@@ -64,13 +65,33 @@ const height_pct = computed(() => `${api.store.dev.consoleBarHeight}px`)
6465
const showStatusBar = computed(() => {
6566
return api.currentRouteName() !== 'data' && api.currentRouteName() !== 'recruit' && api.config.mode != 'presentation'
6667
})
68+
69+
/**
70+
* Computed property that determines whether to wrap content in ResponsiveDeviceContainer
71+
*
72+
* @returns {boolean} True if ResponsiveDeviceContainer should be used, false otherwise
73+
* - Returns false if current route is '/' (root route)
74+
* - Returns true otherwise
75+
*/
76+
const shouldUseResponsiveContainer = computed(() => {
77+
const routeName = api.currentRouteName()
78+
return routeName !== undefined && routeName !== 'recruit'
79+
})
80+
81+
/**
82+
* Computed property that determines if the app is still loading
83+
*
84+
* @returns {boolean} True if the route name is not yet available, false otherwise
85+
*/
86+
const isLoading = computed(() => {
87+
return api.currentRouteName() === undefined
88+
})
6789
</script>
6890
<template>
6991
<div class="app-container">
70-
<!-- Top toolbar - always visible, 30px tall, full width -->
92+
<!-- Top toolbar - always visible, 39px tall, full width -->
7193
<div class="toolbar">
72-
<DeveloperNavBar v-if="api.config.mode == 'development'"> </DeveloperNavBar>
73-
<PresentationNavBar v-if="api.config.mode == 'presentation'"> </PresentationNavBar>
94+
<DeveloperNavBar />
7495
</div>
7596

7697
<!-- Middle row - content and sidebar -->
@@ -81,14 +102,20 @@ const showStatusBar = computed(() => {
81102
<div class="content-and-console">
82103
<!-- Main content - scrollable -->
83104
<div class="main-content">
84-
<StatusBar v-if="showStatusBar" />
85-
<router-view />
105+
<div v-if="isLoading" class="loading-container">
106+
<div class="loading-spinner"></div>
107+
<p>Loading...</p>
108+
</div>
109+
<template v-else>
110+
<ResponsiveDeviceContainer v-if="shouldUseResponsiveContainer"><router-view /></ResponsiveDeviceContainer>
111+
<router-view v-else />
112+
</template>
86113
</div>
87114

88115
<!-- Bottom console - can be toggled -->
89116
<Transition name="console-slide">
90117
<div v-if="api.config.mode == 'development' && api.store.dev.showConsoleBar" class="console">
91-
<DevConsoleBar />
118+
<!--<DevConsoleBar />-->
92119
</div>
93120
</Transition>
94121
</div>
@@ -107,27 +134,29 @@ const showStatusBar = computed(() => {
107134
.router {
108135
height: 100vh;
109136
height: v-bind(total_height);
110-
background-color: var(--page-bg-color);
137+
background-color: var(--background);
111138
}
112139
113140
.app-container {
114141
display: flex;
115142
flex-direction: column;
116143
height: 100vh;
117-
width: 100vw;
144+
width: 100%;
118145
}
119146
120147
.toolbar {
121-
height: 33px;
122-
width: calc(100% - 14px); /* Account for typical scrollbar width */
123-
background-color: var(--dev-bar-light-grey);
148+
margin-top: auto;
149+
margin-bottom: auto;
150+
height: 36px;
151+
width: full; /* Account for typical scrollbar width */
152+
background-color: var(--dev-bar-bg);
124153
}
125154
126155
.content-wrapper {
127156
display: flex;
128157
flex: 1;
129158
overflow: hidden;
130-
width: calc(100% - 14px);
159+
width: 100%;
131160
}
132161
133162
.content-and-console {
@@ -150,14 +179,14 @@ const showStatusBar = computed(() => {
150179
flex: 0 0 280px;
151180
height: 100%;
152181
overflow-y: auto;
153-
border-left: var(--dev-bar-lines);
154-
background-color: var(--dev-bar-background);
182+
border-left: 1px solid var(--border);
183+
background-color: var(--dev-bg);
155184
}
156185
157186
.console {
158187
height: v-bind(height_pct);
159188
width: 100%;
160-
background-color: #6798c8;
189+
background-color: #adadad;
161190
overflow: hidden;
162191
overflow-x: hidden;
163192
}
@@ -185,4 +214,33 @@ const showStatusBar = computed(() => {
185214
.console-slide-leave-to {
186215
height: 0;
187216
}
217+
218+
/* Loading styles */
219+
.loading-container {
220+
display: flex;
221+
flex-direction: column;
222+
align-items: center;
223+
justify-content: center;
224+
height: 100%;
225+
min-height: 200px;
226+
}
227+
228+
.loading-spinner {
229+
width: 40px;
230+
height: 40px;
231+
border: 4px solid #f3f3f3;
232+
border-top: 4px solid #3498db;
233+
border-radius: 50%;
234+
animation: spin 1s linear infinite;
235+
margin-bottom: 16px;
236+
}
237+
238+
@keyframes spin {
239+
0% {
240+
transform: rotate(0deg);
241+
}
242+
100% {
243+
transform: rotate(360deg);
244+
}
245+
}
188246
</style>

0 commit comments

Comments
 (0)