@esershnr/artalk-sidebar 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +16 -0
  2. package/auto-imports.d.ts +76 -0
  3. package/components.d.ts +31 -0
  4. package/env.d.ts +2 -0
  5. package/index.html +15 -0
  6. package/package.json +32 -0
  7. package/public/favicon.png +0 -0
  8. package/public/robots.txt +2 -0
  9. package/src/App.vue +89 -0
  10. package/src/artalk.ts +82 -0
  11. package/src/assets/favicon.png +0 -0
  12. package/src/assets/icon-darkmode-off.svg +1 -0
  13. package/src/assets/icon-darkmode-on.svg +1 -0
  14. package/src/assets/icon-eye-off.svg +1 -0
  15. package/src/assets/icon-eye-on.svg +1 -0
  16. package/src/assets/nav-icon-comments.svg +1 -0
  17. package/src/assets/nav-icon-pages.svg +1 -0
  18. package/src/assets/nav-icon-search.svg +1 -0
  19. package/src/assets/nav-icon-settings.svg +1 -0
  20. package/src/assets/nav-icon-sites.svg +1 -0
  21. package/src/assets/nav-icon-transfer.svg +1 -0
  22. package/src/assets/nav-icon-users.svg +1 -0
  23. package/src/components/AppHeader.vue +235 -0
  24. package/src/components/AppNavigation.vue +11 -0
  25. package/src/components/AppNavigationDesktop.vue +176 -0
  26. package/src/components/AppNavigationMenu.ts +152 -0
  27. package/src/components/AppNavigationMobile.vue +187 -0
  28. package/src/components/AppNavigationSearch.vue +137 -0
  29. package/src/components/FileUploader.vue +149 -0
  30. package/src/components/ItemTextEditor.vue +130 -0
  31. package/src/components/LoadingLayer.vue +37 -0
  32. package/src/components/LogTerminal.vue +89 -0
  33. package/src/components/PageEditor.vue +171 -0
  34. package/src/components/Pagination.vue +253 -0
  35. package/src/components/PreferenceArr.vue +105 -0
  36. package/src/components/PreferenceGrp.vue +153 -0
  37. package/src/components/PreferenceItem.vue +159 -0
  38. package/src/components/SiteCreate.vue +96 -0
  39. package/src/components/SiteEditor.vue +138 -0
  40. package/src/components/SiteSwitcher.vue +184 -0
  41. package/src/components/UserEditor.vue +229 -0
  42. package/src/global.ts +62 -0
  43. package/src/hooks/MobileWidth.ts +27 -0
  44. package/src/i18n/fr.ts +103 -0
  45. package/src/i18n/ja.ts +100 -0
  46. package/src/i18n/ko.ts +99 -0
  47. package/src/i18n/ru.ts +102 -0
  48. package/src/i18n/tr.ts +102 -0
  49. package/src/i18n/zh-CN.ts +97 -0
  50. package/src/i18n/zh-TW.ts +97 -0
  51. package/src/i18n-en.ts +99 -0
  52. package/src/i18n.ts +37 -0
  53. package/src/lib/promise-polyfill.ts +9 -0
  54. package/src/lib/settings-option.ts +186 -0
  55. package/src/lib/settings-sensitive.ts +44 -0
  56. package/src/lib/settings.ts +94 -0
  57. package/src/main.ts +65 -0
  58. package/src/pages/comments.vue +110 -0
  59. package/src/pages/index.vue +33 -0
  60. package/src/pages/login.vue +245 -0
  61. package/src/pages/pages.vue +309 -0
  62. package/src/pages/settings.vue +181 -0
  63. package/src/pages/sites.vue +353 -0
  64. package/src/pages/transfer.vue +204 -0
  65. package/src/pages/users.vue +271 -0
  66. package/src/stores/nav.ts +114 -0
  67. package/src/stores/user.ts +48 -0
  68. package/src/style/_extends.scss +100 -0
  69. package/src/style/_variables.scss +18 -0
  70. package/src/style.scss +245 -0
  71. package/src/vue-i18n.d.ts +7 -0
  72. package/tsconfig.json +40 -0
  73. package/tsconfig.node.json +11 -0
  74. package/typed-router.d.ts +30 -0
  75. package/vite.config.ts +71 -0
@@ -0,0 +1,176 @@
1
+ <script lang="ts" setup>
2
+ /**
3
+ * The part of the navigation bar that is displayed on desktop
4
+ */
5
+ import { useNavigationMenu } from './AppNavigationMenu'
6
+
7
+ const nav = useNavigationMenu()
8
+ const { t } = useI18n()
9
+
10
+ const getIconCSSAttribute = (icon: string) => `url('${icon.replace(/'/g, "\\'")}')`
11
+ </script>
12
+
13
+ <template>
14
+ <div class="sidebar-navigation">
15
+ <div
16
+ v-for="(page, pageName) in nav.pages"
17
+ :key="pageName"
18
+ class="item"
19
+ :class="{ active: pageName === nav.curtPage }"
20
+ @click="nav.goPage(pageName as string)"
21
+ >
22
+ <span class="icon" :style="{ backgroundImage: getIconCSSAttribute(page.icon) }"></span>
23
+ {{ t(page.label) }}
24
+ </div>
25
+ </div>
26
+
27
+ <div v-if="!!Object.keys(nav.tabs).length" class="top-tabbar-wrap atk-sidebar-container">
28
+ <div class="top-tabbar">
29
+ <div
30
+ v-for="(tabLabel, tabName) in nav.tabs"
31
+ :key="tabName"
32
+ class="item-wrap"
33
+ :class="{ active: nav.curtTab === tabName }"
34
+ @click="nav.goTab(tabName as string)"
35
+ >
36
+ <div class="item">{{ t(tabLabel) }}</div>
37
+ </div>
38
+
39
+ <div v-if="nav.isSearchEnabled" class="item-wrap search-btn" @click="nav.showSearch()">
40
+ <div class="item">
41
+ <div class="icon"></div>
42
+ </div>
43
+ </div>
44
+ </div>
45
+
46
+ <AppNavigationSearch v-if="!nav.isMobile" :state="nav.searchState" />
47
+ </div>
48
+ </template>
49
+
50
+ <style lang="scss" scoped>
51
+ $colorMain: #8ecee2;
52
+
53
+ .sidebar-navigation {
54
+ z-index: 10;
55
+ width: 280px;
56
+ position: fixed;
57
+ left: 0;
58
+ top: 61px;
59
+ height: calc(100vh - 61px - 41px);
60
+ padding: 20px;
61
+ background: var(--at-color-bg);
62
+ border-right: 1px solid var(--at-color-border);
63
+
64
+ @media (max-width: 1023px) {
65
+ display: none;
66
+ }
67
+
68
+ .item {
69
+ position: relative;
70
+ display: flex;
71
+ align-items: center;
72
+ padding: 6px 12px;
73
+ font-size: 15px;
74
+ border-radius: 6px;
75
+ cursor: pointer;
76
+ user-select: none;
77
+ transition: background 0.2s;
78
+
79
+ &:not(:last-child) {
80
+ margin-bottom: 4px;
81
+ }
82
+
83
+ &.active {
84
+ font-weight: bold;
85
+ color: var(--at-color-deep);
86
+
87
+ &::before {
88
+ content: '';
89
+ display: block;
90
+ position: absolute;
91
+ left: -8px;
92
+ top: 5%;
93
+ background: $colorMain;
94
+ height: 90%;
95
+ width: 4px;
96
+ border-radius: 1000px;
97
+ }
98
+ }
99
+
100
+ &:hover,
101
+ &.active {
102
+ background: var(--at-color-bg-grey-transl);
103
+ }
104
+
105
+ .icon {
106
+ width: 20px;
107
+ height: 20px;
108
+ margin-right: 10px;
109
+ background-size: contain;
110
+ background-repeat: no-repeat;
111
+ }
112
+ }
113
+ }
114
+
115
+ .top-tabbar-wrap {
116
+ @media (max-width: 1023px) {
117
+ display: none;
118
+ }
119
+ }
120
+
121
+ .top-tabbar {
122
+ display: flex;
123
+ align-items: center;
124
+ height: 50px;
125
+ margin: 0 auto;
126
+ padding: 0 8px;
127
+ border-bottom: 1px solid var(--at-color-border);
128
+
129
+ .item-wrap {
130
+ margin-bottom: -2px;
131
+ display: flex;
132
+ align-items: center;
133
+ justify-content: center;
134
+ font-size: 14px;
135
+ height: 100%;
136
+ padding: 0;
137
+ cursor: pointer;
138
+ user-select: none;
139
+ border-bottom: 2px solid transparent;
140
+
141
+ &.active {
142
+ font-weight: bold;
143
+ border-color: $colorMain;
144
+ }
145
+
146
+ &:not(:last-child) {
147
+ margin-right: 7px;
148
+ }
149
+
150
+ &:hover .item {
151
+ background: var(--at-color-bg-grey-transl);
152
+ }
153
+
154
+ &.search-btn {
155
+ margin-left: auto;
156
+
157
+ .icon {
158
+ background-image: url('@/assets/nav-icon-search.svg');
159
+ }
160
+ }
161
+
162
+ .item {
163
+ border-radius: 4px;
164
+ padding: 5px 16px;
165
+ transition: background 0.2s;
166
+
167
+ .icon {
168
+ width: 20px;
169
+ height: 20px;
170
+ background-size: contain;
171
+ background-repeat: no-repeat;
172
+ }
173
+ }
174
+ }
175
+ }
176
+ </style>
@@ -0,0 +1,152 @@
1
+ import { storeToRefs } from 'pinia'
2
+ import { RouteLocation } from 'vue-router'
3
+ import CommentsIcon from '@/assets/nav-icon-comments.svg'
4
+ import PagesIcon from '@/assets/nav-icon-pages.svg'
5
+ import UsersIcon from '@/assets/nav-icon-users.svg'
6
+ import SitesIcon from '@/assets/nav-icon-sites.svg'
7
+ import TransferIcon from '@/assets/nav-icon-transfer.svg'
8
+ import SettingsIcon from '@/assets/nav-icon-settings.svg'
9
+ import { useUserStore } from '@/stores/user'
10
+ import { useNavStore } from '@/stores/nav'
11
+
12
+ export type PageItem = { label: string; link: string; hideOnMobile?: boolean; icon: string }
13
+
14
+ /**
15
+ * Pages for admin
16
+ */
17
+ export const AdminPages: Record<string, PageItem> = {
18
+ comments: {
19
+ label: 'comment',
20
+ link: '/comments',
21
+ icon: CommentsIcon,
22
+ },
23
+ pages: {
24
+ label: 'page',
25
+ link: '/pages',
26
+ icon: PagesIcon,
27
+ },
28
+ users: {
29
+ label: 'user',
30
+ link: '/users',
31
+ icon: UsersIcon,
32
+ },
33
+ sites: {
34
+ label: 'site',
35
+ link: '/sites',
36
+ hideOnMobile: true,
37
+ icon: SitesIcon,
38
+ },
39
+ transfer: {
40
+ label: 'transfer',
41
+ link: '/transfer',
42
+ hideOnMobile: true,
43
+ icon: TransferIcon,
44
+ },
45
+ settings: {
46
+ label: 'settings',
47
+ link: '/settings',
48
+ icon: SettingsIcon,
49
+ },
50
+ }
51
+
52
+ /**
53
+ * Pages for user
54
+ */
55
+ export const UserPages: Record<string, PageItem> = {
56
+ comments: {
57
+ // Only show comments page for user
58
+ ...AdminPages.comments,
59
+ },
60
+ }
61
+
62
+ export interface NavigationStoreProps {
63
+ onGoPage?: (pageName: string) => void
64
+ onGoTab?: (tabName: string) => void
65
+ }
66
+
67
+ export interface SearchStateApi {
68
+ show: boolean
69
+ value: string
70
+ updateValue: (val: string) => void
71
+ showSearch: () => void
72
+ hideSearch: () => void
73
+ }
74
+
75
+ /**
76
+ * Navigation menu hook only use for AppNavigation component
77
+ *
78
+ * (do not expose to other components, others should call `useNavStore`)
79
+ */
80
+ export const useNavigationMenu = (props: NavigationStoreProps = {}) => {
81
+ const router = useRouter()
82
+ const { is_admin: isAdmin } = storeToRefs(useUserStore())
83
+ const { tabs, curtPage, curtTab, isMobile, isSearchEnabled } = storeToRefs(useNavStore())
84
+
85
+ /**
86
+ * Pages for current user
87
+ */
88
+ const pages = computed((): Record<string, PageItem> => (isAdmin.value ? AdminPages : UserPages))
89
+
90
+ /**
91
+ * State for search input
92
+ */
93
+ const searchState = reactive<SearchStateApi>({
94
+ show: false,
95
+ value: '',
96
+ updateValue(val: string) {
97
+ searchState.value = val
98
+ },
99
+ showSearch() {
100
+ searchState.show = true
101
+ },
102
+ hideSearch() {
103
+ searchState.show = false
104
+ },
105
+ })
106
+
107
+ /**
108
+ * Navigate to page
109
+ */
110
+ const goPage = (pageName: string) => {
111
+ props.onGoPage?.(pageName)
112
+ router.replace(pages.value[pageName].link)
113
+ }
114
+
115
+ /**
116
+ * Navigate to tab
117
+ */
118
+ const goTab = (tabName: string) => {
119
+ props.onGoTab?.(tabName)
120
+ curtTab.value = tabName
121
+ }
122
+
123
+ /**
124
+ * Sync current page name from route
125
+ */
126
+ const syncCurtPage = (to?: RouteLocation) =>
127
+ (curtPage.value = String((to || useRoute()).name).replace(/^\//, ''))
128
+
129
+ onMounted(() => {
130
+ syncCurtPage()
131
+ })
132
+
133
+ router.afterEach((to, from, failure) => {
134
+ syncCurtPage(to)
135
+ searchState.value = ''
136
+ searchState.hideSearch()
137
+ })
138
+
139
+ return reactive({
140
+ pages,
141
+ tabs,
142
+ curtPage,
143
+ curtTab,
144
+ goPage,
145
+ goTab,
146
+ isMobile,
147
+ isSearchEnabled,
148
+ searchState,
149
+ showSearch: searchState.showSearch,
150
+ hideSearch: searchState.hideSearch,
151
+ })
152
+ }
@@ -0,0 +1,187 @@
1
+ <script lang="ts" setup>
2
+ /**
3
+ * The part of the navigation bar that is displayed on mobile devices and the sidebar
4
+ */
5
+ import { useNavigationMenu } from './AppNavigationMenu'
6
+
7
+ const { t } = useI18n()
8
+
9
+ const indicatorState = ref<'pages' | 'tabs'>('tabs')
10
+ const tabListEl = ref<HTMLElement | null>(null)
11
+ const nav = useNavigationMenu({
12
+ onGoPage: () => {
13
+ indicatorState.value = 'tabs'
14
+ },
15
+ })
16
+
17
+ /**
18
+ * For tab list for horizontal scroll
19
+ */
20
+ const wheelHandler = (evt: WheelEvent) => {
21
+ evt.preventDefault()
22
+ tabListEl.value && (tabListEl.value!.scrollLeft += evt.deltaY)
23
+ }
24
+ onMounted(() => tabListEl.value!.addEventListener('wheel', wheelHandler))
25
+ onUnmounted(() => tabListEl.value!.removeEventListener('wheel', wheelHandler))
26
+
27
+ /**
28
+ * Toggle indicator
29
+ */
30
+ function toggleIndicator() {
31
+ indicatorState.value = indicatorState.value !== 'tabs' ? 'tabs' : 'pages'
32
+ }
33
+ </script>
34
+
35
+ <template>
36
+ <div class="top-navigation">
37
+ <div class="page" @click="toggleIndicator()">
38
+ <div class="icon" :class="indicatorState === 'tabs' ? 'menu' : 'arrow'"></div>
39
+ <div v-if="nav.pages[nav.curtPage]?.label" class="text">
40
+ {{ t(nav.pages[nav.curtPage].label) }}
41
+ </div>
42
+ </div>
43
+
44
+ <div ref="tabListEl" class="tab-list">
45
+ <!-- Tabs -->
46
+ <template v-if="indicatorState === 'tabs'">
47
+ <div
48
+ v-for="(tabLabel, tabName) in nav.tabs"
49
+ :key="tabName"
50
+ class="item"
51
+ :class="{ active: nav.curtTab === tabName }"
52
+ @click="nav.goTab(tabName as string)"
53
+ >
54
+ {{ t(tabLabel) }}
55
+ </div>
56
+
57
+ <div v-if="nav.isSearchEnabled" class="item search-btn" @click="nav.showSearch()"></div>
58
+ </template>
59
+
60
+ <!-- Pages -->
61
+ <template v-if="indicatorState === 'pages'">
62
+ <div
63
+ v-for="(page, pageName) in nav.pages"
64
+ v-show="!page.hideOnMobile"
65
+ :key="pageName"
66
+ class="item"
67
+ :class="{ active: pageName === nav.curtPage }"
68
+ @click="nav.goPage(pageName as string)"
69
+ >
70
+ {{ t(page.label) }}
71
+ </div>
72
+ </template>
73
+ </div>
74
+
75
+ <AppNavigationSearch v-if="nav.isMobile" :state="nav.searchState" />
76
+ </div>
77
+ </template>
78
+
79
+ <style lang="scss" scoped>
80
+ .top-navigation {
81
+ position: relative;
82
+ display: flex;
83
+ flex-direction: row;
84
+ align-items: center;
85
+ border-bottom: 1px solid var(--at-color-border);
86
+ height: 41px;
87
+
88
+ @media (min-width: 1024px) {
89
+ display: none;
90
+ }
91
+
92
+ .icon {
93
+ width: 17px;
94
+ height: 100%;
95
+ background-color: var(--at-color-deep);
96
+ background-size: contain;
97
+ background-repeat: no-repeat;
98
+ mask-repeat: no-repeat;
99
+ -webkit-mask-repeat: no-repeat;
100
+ mask-position: center;
101
+ -webkit-mask-position: center;
102
+ mask-size: 100%;
103
+ -webkit-mask-size: 100%;
104
+
105
+ &.menu {
106
+ $menuImg: url("data:image/svg+xml,%3Csvg width='50' height='50' viewBox='0 0 50 50' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M5 9H44V11.8182H5V9ZM5 23.0909H44V25.9091H5V23.0909ZM44 37.1818H5V40H44V37.1818Z' fill='black'/%3E%3C/svg%3E%0A");
107
+ mask-image: $menuImg;
108
+ -webkit-mask-image: $menuImg;
109
+ }
110
+
111
+ &.arrow {
112
+ $arrowImg: url("data:image/svg+xml,%3Csvg width='50' height='50' viewBox='0 0 50 50' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M32.1433 7L15 24.4999L15.4676 24.9773L32.1433 42L34 40.1047L18.7133 24.5001L34 8.89529L32.1433 7Z' fill='black'/%3E%3C/svg%3E%0A");
113
+ mask-image: $arrowImg;
114
+ -webkit-mask-image: $arrowImg;
115
+ }
116
+ }
117
+
118
+ .page {
119
+ display: flex;
120
+ align-items: center;
121
+ height: 100%;
122
+ padding: 0 20px;
123
+ border-right: 1px solid var(--at-color-border);
124
+ cursor: pointer;
125
+ user-select: none;
126
+ white-space: nowrap;
127
+
128
+ .icon {
129
+ margin-right: 10px;
130
+ }
131
+
132
+ .text {
133
+ color: var(--at-color-deep);
134
+ }
135
+ }
136
+
137
+ .tab-list {
138
+ position: relative;
139
+ flex: auto;
140
+ height: 100%;
141
+ display: flex;
142
+ flex-direction: row;
143
+ overflow-y: auto;
144
+
145
+ &::-webkit-scrollbar {
146
+ width: 0;
147
+ height: 0;
148
+ background: transparent;
149
+ }
150
+ }
151
+
152
+ .item {
153
+ padding: 0 20px;
154
+ color: var(--at-color-sub);
155
+ display: flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ height: 100%;
159
+ cursor: pointer;
160
+ white-space: nowrap;
161
+
162
+ &.active {
163
+ color: var(--at-color-deep);
164
+ }
165
+
166
+ &:hover {
167
+ background: var(--at-color-bg-grey);
168
+ }
169
+
170
+ &.search-btn {
171
+ margin-left: auto;
172
+ padding: 0 20px;
173
+ border-left: 1px solid var(--at-color-border);
174
+
175
+ &::after {
176
+ display: inline-block;
177
+ content: '';
178
+ height: 15px;
179
+ width: 15px;
180
+ background-repeat: no-repeat;
181
+ background-position: center;
182
+ background-image: url("data:image/svg+xml,%3Csvg width='15' height='15' viewBox='0 0 15 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9.89266 3.70572C8.18412 1.99718 5.41402 1.99718 3.70548 3.70572C1.99694 5.41427 1.99694 8.18436 3.70548 9.89291C5.41402 11.6015 8.18412 11.6015 9.89266 9.89291C11.6012 8.18436 11.6012 5.41427 9.89266 3.70572ZM2.8216 2.82184C5.0183 0.625142 8.57985 0.625142 10.7765 2.82184C12.8239 4.86916 12.9631 8.10202 11.1942 10.3106L13.4282 12.5446L12.5443 13.4284L10.3103 11.1945C8.10177 12.9633 4.86892 12.8241 2.8216 10.7768C0.624897 8.58009 0.624897 5.01854 2.8216 2.82184Z' fill='%23757575'/%3E%3C/svg%3E");
183
+ }
184
+ }
185
+ }
186
+ }
187
+ </style>
@@ -0,0 +1,137 @@
1
+ <script lang="ts" setup>
2
+ import type { SearchStateApi } from './AppNavigationMenu'
3
+ import { useNavStore } from '@/stores/nav'
4
+
5
+ const { t } = useI18n()
6
+ const nav = useNavStore()
7
+ const inputEl = ref<HTMLInputElement | null>(null)
8
+
9
+ const props = defineProps<{
10
+ state: SearchStateApi
11
+ }>()
12
+
13
+ watch(
14
+ () => props.state.show,
15
+ (show) => {
16
+ if (show) {
17
+ nextTick(() => {
18
+ inputEl.value?.focus()
19
+ })
20
+ } else {
21
+ props.state.updateValue('')
22
+ nav.searchResetEvent?.()
23
+ }
24
+ },
25
+ )
26
+
27
+ const onSearchSubmit = (evt: Event) => {
28
+ const { value } = props.state
29
+ if (value.trim() === '') {
30
+ inputEl.value?.focus()
31
+ return
32
+ }
33
+
34
+ nav.searchEvent?.(value.trim())
35
+ }
36
+ </script>
37
+
38
+ <template>
39
+ <form v-if="props.state.show" class="search-layer atk-fade-in" @submit.prevent="onSearchSubmit">
40
+ <div class="item back-btn" @click="props.state.hideSearch()">
41
+ <div class="icon arrow"></div>
42
+ </div>
43
+ <input
44
+ ref="inputEl"
45
+ :value="props.state.value"
46
+ type="text"
47
+ :placeholder="t('searchHint')"
48
+ required
49
+ @input="props.state.updateValue(($event.target as HTMLInputElement).value)"
50
+ />
51
+ <button type="submit" class="item search-btn"></button>
52
+ </form>
53
+ </template>
54
+
55
+ <style lang="scss" scoped>
56
+ .search-layer {
57
+ z-index: 100;
58
+ position: absolute;
59
+ height: 100%;
60
+ width: 100%;
61
+ top: 0;
62
+ background: var(--at-color-bg);
63
+ display: flex;
64
+ flex-direction: row;
65
+
66
+ .back-btn {
67
+ padding: 0 20px;
68
+ border-right: 1px solid var(--at-color-border);
69
+ }
70
+
71
+ input {
72
+ flex: 1;
73
+ border: 0;
74
+ outline: none;
75
+ padding: 0 20px;
76
+ font-size: 15px;
77
+ background: transparent;
78
+ }
79
+
80
+ .search-btn {
81
+ cursor: pointer;
82
+ border: none;
83
+ background: transparent;
84
+ }
85
+
86
+ .icon {
87
+ width: 17px;
88
+ height: 100%;
89
+ background-color: var(--at-color-deep);
90
+ background-size: contain;
91
+ background-repeat: no-repeat;
92
+ mask-repeat: no-repeat;
93
+ mask-position: center;
94
+ mask-size: 100%;
95
+
96
+ &.arrow {
97
+ $arrowImg: url("data:image/svg+xml,%3Csvg width='50' height='50' viewBox='0 0 50 50' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M32.1433 7L15 24.4999L15.4676 24.9773L32.1433 42L34 40.1047L18.7133 24.5001L34 8.89529L32.1433 7Z' fill='black'/%3E%3C/svg%3E%0A");
98
+ mask-image: $arrowImg;
99
+ }
100
+ }
101
+
102
+ .item {
103
+ padding: 0 20px;
104
+ color: var(--at-color-sub);
105
+ display: flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ height: 100%;
109
+ cursor: pointer;
110
+ white-space: nowrap;
111
+
112
+ &.active {
113
+ color: var(--at-color-deep);
114
+ }
115
+
116
+ &:hover {
117
+ background: var(--at-color-bg-grey);
118
+ }
119
+
120
+ &.search-btn {
121
+ margin-left: auto;
122
+ padding: 0 20px;
123
+ border-left: 1px solid var(--at-color-border);
124
+
125
+ &::after {
126
+ display: inline-block;
127
+ content: '';
128
+ height: 15px;
129
+ width: 15px;
130
+ background-repeat: no-repeat;
131
+ background-position: center;
132
+ background-image: url("data:image/svg+xml,%3Csvg width='15' height='15' viewBox='0 0 15 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9.89266 3.70572C8.18412 1.99718 5.41402 1.99718 3.70548 3.70572C1.99694 5.41427 1.99694 8.18436 3.70548 9.89291C5.41402 11.6015 8.18412 11.6015 9.89266 9.89291C11.6012 8.18436 11.6012 5.41427 9.89266 3.70572ZM2.8216 2.82184C5.0183 0.625142 8.57985 0.625142 10.7765 2.82184C12.8239 4.86916 12.9631 8.10202 11.1942 10.3106L13.4282 12.5446L12.5443 13.4284L10.3103 11.1945C8.10177 12.9633 4.86892 12.8241 2.8216 10.7768C0.624897 8.58009 0.624897 5.01854 2.8216 2.82184Z' fill='%23757575'/%3E%3C/svg%3E");
133
+ }
134
+ }
135
+ }
136
+ }
137
+ </style>