Skip to content

Commit ecadf17

Browse files
committed
UX: Replace "speed dial" in mobile toolbar with custom context menu
Signed-off-by: Michael Mayer <michael@photoprism.app>
1 parent e7136bd commit ecadf17

File tree

9 files changed

+291
-129
lines changed

9 files changed

+291
-129
lines changed

frontend/src/component/navigation.vue

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,57 +9,41 @@
99
<v-toolbar-title class="nav-title">
1010
<span :class="{'clickable': auth}" @click.stop.prevent="showNavigation()">{{ page.title }}</span>
1111
</v-toolbar-title>
12-
<v-speed-dial
13-
v-model="speedDial"
14-
direction="bottom"
15-
transition="slide-y-transition"
16-
class="mobile-dial"
17-
open-on-hover
18-
dark
12+
<v-btn
13+
fab dark :ripple="false"
14+
color="transparent"
15+
class="mobile-menu-trigger elevation-0"
16+
@click.stop.prevent="speedDial = true"
1917
>
20-
<template #activator>
21-
<v-btn
22-
v-model="speedDial"
23-
dark fab icon flat
24-
:ripple="false"
25-
class="nav-menu-trigger"
26-
>
27-
<v-icon>more_vert</v-icon>
28-
<v-icon>close</v-icon>
29-
</v-btn>
30-
</template>
31-
<v-btn
32-
v-if="!routeName('browse')" to="/browse" class="nav-menu-browse elevation-5 highlight"
33-
fab dark small
34-
>
35-
<v-icon>search</v-icon>
36-
</v-btn>
37-
<v-btn
38-
v-if="auth && !config.readonly && $config.feature('upload')" class="nav-menu-upload elevation-5 highlight"
39-
fab dark small
40-
@click.prevent="openUpload()"
41-
>
42-
<v-icon>cloud_upload</v-icon>
43-
</v-btn>
44-
<v-btn
45-
v-if="!config.disable.settings && !routeName('settings')" to="/settings" class="nav-menu-settings elevation-5"
46-
fab dark small
47-
>
48-
<v-icon>settings</v-icon>
49-
</v-btn>
50-
<v-btn
51-
v-if="auth && !isPublic" class="nav-menu-reload elevation-4"
52-
fab dark small
53-
@click.prevent="reloadApp">
54-
<v-icon>refresh</v-icon>
55-
</v-btn>
56-
<v-btn
57-
v-if="auth && !isPublic" class="nav-menu-logout elevation-4"
58-
fab dark small
59-
@click.prevent="logout">
60-
<v-icon>power_settings_new</v-icon>
61-
</v-btn>
62-
</v-speed-dial>
18+
<v-icon dark>more_vert</v-icon>
19+
</v-btn>
20+
<div id="mobile-menu" :class="{'active': speedDial}" @click.stop="speedDial = false">
21+
<div class="menu-content grow-top-right">
22+
<div class="menu-icons">
23+
<a v-if="auth && !isPublic" href="#" :title="$gettext('Logout')" @click.prevent="logout"><v-icon>power_settings_new</v-icon></a>
24+
<a href="#" :title="$gettext('Reload')" @click.prevent="reloadApp"><v-icon>refresh</v-icon></a>
25+
<router-link v-if="!auth && !isPublic" :to="{ name: 'login' }" :title="$gettext('Login')">
26+
<v-icon>login</v-icon>
27+
</router-link>
28+
<router-link v-if="auth && !routeName('library') && $config.feature('library')" :to="{ name: 'library_logs' }" :title="$gettext('Logs')"><v-icon>feed</v-icon></router-link>
29+
<router-link v-if="auth && !config.disable.settings && !routeName('settings')" to="/settings" :title="$gettext('Settings')">
30+
<v-icon>settings</v-icon>
31+
</router-link>
32+
<a v-if="auth && !config.readonly && $config.feature('upload')" href="#" :title="$gettext('Upload')" @click.prevent="openUpload()"><v-icon>cloud_upload</v-icon></a>
33+
</div>
34+
<div class="menu-actions">
35+
<div v-if="auth && !routeName('browse')" class="menu-action"><router-link to="/browse"><v-icon>search</v-icon> <translate>Search</translate></router-link></div>
36+
<div v-if="auth && !routeName('albums') && $config.feature('albums')" class="menu-action"><router-link to="/albums"><v-icon>bookmark</v-icon> <translate>Albums</translate></router-link></div>
37+
<div v-if="auth && !routeName('library') && $config.feature('library')" class="menu-action"><router-link :to="{ name: 'library' }"><v-icon>camera_roll</v-icon> <translate>Index</translate></router-link></div>
38+
<div v-if="auth && !routeName('files') && $config.feature('library')" class="menu-action"><router-link to="/library/files"><v-icon>folder</v-icon> <translate>Files</translate></router-link></div>
39+
<div v-if="auth && !config.disable.settings && !routeName('settings')" class="menu-action"><router-link :to="{ name: 'settings_sync' }"><v-icon>sync</v-icon> <translate>Connect</translate></router-link></div>
40+
<div v-if="auth && !config.disable.settings && !routeName('settings')" class="menu-action"><router-link :to="{ name: 'settings_account' }"><v-icon>person</v-icon> <translate>Account</translate></router-link></div>
41+
<div class="menu-action"><a href="https://link.photoprism.app/docs" target="_blank"><v-icon>auto_stories</v-icon> <translate>User Guide</translate></a></div>
42+
<div v-if="!isSponsor" class="menu-action"><a href="https://link.photoprism.app/membership" target="_blank"><v-icon>workspace_premium</v-icon> <translate>Become a sponsor</translate></a></div>
43+
<div v-if="config.imprintUrl" class="menu-action"><a :href="config.imprintUrl" target="_blank"><v-icon>info</v-icon> <translate>Legal Information</translate></a></div>
44+
</div>
45+
</div>
46+
</div>
6347
</v-toolbar>
6448
</template>
6549
<template v-else-if="visible && !auth">

frontend/src/css/effects.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,33 @@
100100
animation: stretch 1.5s ease-out 0s alternate infinite none running;
101101
}
102102

103+
@keyframes slide-left {
104+
0% {
105+
transform: translateX(105%);;
106+
}
107+
100% {
108+
transform: translateX(0%);
109+
}
110+
}
111+
112+
#photoprism .animate-slide-left {
113+
animation: slide-left 300ms ease-in-out forwards;
114+
}
115+
116+
@keyframes grow {
117+
0% {
118+
transform: scale(0);
119+
}
120+
100% {
121+
transform: scale(1);
122+
}
123+
}
124+
125+
#photoprism .grow-top-right {
126+
transform-origin: top right;
127+
animation: grow 200ms ease-in-out forwards;
128+
}
129+
103130
#photoprism .select-transition {
104131
-webkit-transition-duration: 15ms !important;
105132
-moz-transition-duration: 15ms !important;

frontend/src/css/navigation.css

Lines changed: 120 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,27 +158,135 @@ nav .v-list__tile__title.title {
158158
font-size: 19px;
159159
}
160160

161-
/* MOBILE NAV SPEED DIAL */
161+
/* Mobile Menu */
162162

163-
#photoprism .mobile-dial .v-btn.nav-menu-trigger {
163+
#photoprism #p-navigation .mobile-menu-trigger {
164164
width: 48px;
165+
padding: 0;
166+
margin: 0;
165167
}
166168

167-
#photoprism .mobile-dial .v-btn:after,
168-
#photoprism .mobile-dial .v-btn:before {
169+
#photoprism .v-btn.mobile-menu-trigger:after,
170+
#photoprism .v-btn.mobile-menu-trigger:before {
169171
display: none!important;
170172
}
171173

172-
#photoprism .mobile-dial .v-speed-dial__list .v-btn {
173-
color: white!important;
174-
background-color: #8916ff;
174+
#mobile-menu {
175+
display: none;
176+
position: fixed;
177+
overflow: hidden;
178+
z-index: 1;
179+
top: 0;
180+
right: 0;
181+
left: 0;
182+
bottom: 0;
183+
margin: 0;
184+
padding: 0;
185+
width: 0;
186+
height: 0;
187+
}
188+
189+
#mobile-menu.active {
190+
display: block;
191+
width: 100vw;
192+
height: 100vh;
193+
}
194+
195+
#mobile-menu .menu-content {
196+
display: block;
197+
position: fixed;
198+
top: 0;
199+
right: 0;
200+
left: auto;
201+
width: auto;
202+
height: auto;
203+
margin: 10px;
204+
overflow: hidden;
205+
background: #393a3c;
206+
border-radius: 8px;
207+
}
208+
209+
#mobile-menu .menu-icons {
210+
-ms-flex-pack: distribute;
211+
-webkit-box-orient: horizontal;
212+
-webkit-box-direction: normal;
213+
-webkit-box-align: stretch;
214+
-ms-flex-align: stretch;
215+
-ms-flex-flow: row nowrap;
216+
align-items: stretch;
217+
display: -webkit-box;
218+
display: -ms-flexbox;
219+
display: flex;
220+
flex-flow: row nowrap;
221+
justify-content: space-around;
222+
background: rgba(250, 250, 255,.1);
223+
padding: 0;
224+
margin: 0;
225+
text-align: center;
175226
}
176227

177-
#photoprism .mobile-dial .v-speed-dial__list .v-btn.highlight {
178-
background-color: #5f30fe;
228+
#mobile-menu .menu-icons a {
229+
fill: rgba(255,255,255,.8);
230+
color: rgba(255,255,255,.8);
231+
-webkit-box-flex: 1;
232+
-ms-flex-positive: 1;
233+
cursor: pointer;
234+
display: inline-block;
235+
flex-grow: 1;
236+
overflow: hidden;
237+
padding: 12px 11px 10px 11px;
238+
margin: 0;
239+
position: relative;
240+
text-align: center;
241+
vertical-align: middle;
242+
z-index: 1;
243+
text-decoration: none;
244+
font-weight: bold;
245+
}
246+
247+
#mobile-menu .menu-icons a:hover {
248+
background: rgba(250, 250, 255,.08);
249+
}
250+
251+
#mobile-menu .menu-icons a i {
252+
font-size: 22px;
253+
}
254+
255+
#mobile-menu .menu-actions {
256+
display: block;
257+
overflow-y: auto;
258+
padding: 0;
259+
margin: 0;
260+
}
261+
262+
#mobile-menu .menu-actions .menu-action {
263+
display: block;
264+
padding: 0;
265+
margin: 0;
266+
}
267+
268+
#mobile-menu .menu-actions .menu-action:hover {
269+
background: #3f4042;
270+
}
271+
272+
#mobile-menu .menu-actions .menu-action a {
273+
color: #c2c4c5;
274+
display: inline-block;
275+
min-width: 200px;
276+
font-size: 15px;
277+
line-height: 50px;
278+
text-decoration: none;
279+
padding: 0 20px;
280+
margin: 0;
281+
}
282+
283+
#mobile-menu .menu-actions .menu-action a i {
284+
padding: 0 16px 0 0;
285+
font-size: 20px;
179286
}
180287

181-
#photoprism .mobile-dial .v-speed-dial__list .v-btn:hover,
182-
#photoprism .mobile-dial .v-speed-dial__list .v-btn.highlight:hover {
183-
background-color: #6600cc;
288+
#mobile-menu .menu-icons a:hover i,
289+
#mobile-menu .menu-actions .menu-action:hover a,
290+
#mobile-menu .menu-actions .menu-action:hover a i{
291+
color: #ffffff;
184292
}

frontend/src/dialog/sponsor.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export default {
7070
this.$emit('close');
7171
},
7272
signUp() {
73-
window.open("https://photoprism.app/membership", "_blank");
73+
window.open("https://link.photoprism.app/membership", "_blank");
7474
this.$emit('close');
7575
},
7676
},

0 commit comments

Comments
 (0)