1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
<template>
<div class="header">
<mk-special-message/>
<div class="main" ref="main">
<div class="backdrop"></div>
<div class="main">
<p ref="welcomeback" v-if="$store.getters.isSignedIn">%i18n:@welcome-back%<b>{{ $store.state.i | userName }}</b>さん</p>
<div class="container" ref="mainContainer">
<div class="left">
<x-nav/>
</div>
<div class="right">
<x-search/>
<x-account v-if="$store.getters.isSignedIn"/>
<x-notifications v-if="$store.getters.isSignedIn"/>
<x-post v-if="$store.getters.isSignedIn"/>
<x-clock/>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as anime from 'animejs';
import XNav from './ui.header.nav.vue';
import XSearch from './ui.header.search.vue';
import XAccount from './ui.header.account.vue';
import XNotifications from './ui.header.notifications.vue';
import XPost from './ui.header.post.vue';
import XClock from './ui.header.clock.vue';
export default Vue.extend({
components: {
XNav,
XSearch,
XAccount,
XNotifications,
XPost,
XClock,
},
mounted() {
this.$store.commit('setUiHeaderHeight', 48);
if (this.$store.getters.isSignedIn) {
const ago = (new Date().getTime() - new Date(this.$store.state.i.lastUsedAt).getTime()) / 1000;
const isHisasiburi = ago >= 3600;
this.$store.state.i.lastUsedAt = new Date();
if (isHisasiburi) {
(this.$refs.welcomeback as any).style.display = 'block';
(this.$refs.main as any).style.overflow = 'hidden';
anime({
targets: this.$refs.welcomeback,
top: '0',
opacity: 1,
delay: 1000,
duration: 500,
easing: 'easeOutQuad'
});
anime({
targets: this.$refs.mainContainer,
opacity: 0,
delay: 1000,
duration: 500,
easing: 'easeOutQuad'
});
setTimeout(() => {
anime({
targets: this.$refs.welcomeback,
top: '-48px',
opacity: 0,
duration: 500,
complete: () => {
(this.$refs.welcomeback as any).style.display = 'none';
(this.$refs.main as any).style.overflow = 'initial';
},
easing: 'easeInQuad'
});
anime({
targets: this.$refs.mainContainer,
opacity: 1,
duration: 500,
easing: 'easeInQuad'
});
}, 2500);
}
}
}
});
</script>
<style lang="stylus" scoped>
root(isDark)
position -webkit-sticky
position sticky
top 0
z-index 1000
width 100%
box-shadow 0 1px 1px rgba(#000, 0.075)
> .main
height 48px
> .backdrop
position absolute
top 0
z-index 1000
width 100%
height 48px
background isDark ? #313543 : #f7f7f7
> .main
z-index 1001
margin 0
padding 0
background-clip content-box
font-size 0.9rem
user-select none
> p
display none
position absolute
top 48px
width 100%
line-height 48px
margin 0
text-align center
color isDark ? #fff : #888
opacity 0
> .container
display flex
width 100%
max-width 1300px
margin 0 auto
&:before
content ""
position absolute
top 0
left 0
display block
width 100%
height 48px
background-image isDark ? url('/assets/desktop/header-icon.dark.svg') : url('/assets/desktop/header-icon.light.svg')
background-size 24px
background-position center
background-repeat no-repeat
opacity 0.3
> .left
margin 0 auto 0 0
height 48px
> .right
margin 0 0 0 auto
height 48px
> *
display inline-block
vertical-align top
@media (max-width 1100px)
> .mk-ui-header-search
display none
.header[data-darkmode]
root(true)
.header:not([data-darkmode])
root(false)
</style>
|