@kompasid/lit-web-components 0.9.19 → 0.9.21
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.
- package/dist/src/components/kompasid-menu-side-bar/KompasMenuSideBar.d.ts +22 -61
- package/dist/src/components/kompasid-menu-side-bar/KompasMenuSideBar.js +261 -475
- package/dist/src/components/kompasid-menu-side-bar/KompasMenuSideBar.js.map +1 -1
- package/dist/src/components/kompasid-menu-side-bar/SidebarDataController.d.ts +32 -0
- package/dist/src/components/kompasid-menu-side-bar/SidebarDataController.js +72 -0
- package/dist/src/components/kompasid-menu-side-bar/SidebarDataController.js.map +1 -0
- package/dist/tailwind/tailwind.js +9 -0
- package/dist/tailwind/tailwind.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/components/kompasid-menu-side-bar/KompasMenuSideBar.ts +299 -607
- package/src/components/kompasid-menu-side-bar/SidebarDataController.ts +113 -0
- package/tailwind/tailwind.ts +9 -0
|
@@ -1,70 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
import { html, css, LitElement } from 'lit'
|
|
1
|
+
import { LitElement, html, css } from 'lit'
|
|
3
2
|
import { customElement, property, state } from 'lit/decorators.js'
|
|
3
|
+
import { repeat } from 'lit/directives/repeat.js'
|
|
4
4
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js'
|
|
5
5
|
import { TWStyles } from '../../../tailwind/tailwind.js'
|
|
6
6
|
import { getFontAwesomeIcon } from '../../utils/fontawesome-setup.js'
|
|
7
7
|
import { decodeSpecialChars } from '../../utils/decodeSpecialChars.js'
|
|
8
8
|
import { timedContent } from '../../utils/timedContent.js'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface dataType {
|
|
21
|
-
href: string
|
|
22
|
-
external?: boolean
|
|
23
|
-
icon: object | null
|
|
24
|
-
iconify: string | null
|
|
25
|
-
name: string
|
|
26
|
-
slug: string
|
|
27
|
-
redDot: [
|
|
28
|
-
{
|
|
29
|
-
start: string
|
|
30
|
-
end: string
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
children: [
|
|
34
|
-
{
|
|
35
|
-
href: string
|
|
36
|
-
external: boolean
|
|
37
|
-
icon: string
|
|
38
|
-
iconify: string | null
|
|
39
|
-
name: string
|
|
40
|
-
slug: string
|
|
41
|
-
redDot: [
|
|
42
|
-
{
|
|
43
|
-
start: string
|
|
44
|
-
end: string
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
}
|
|
50
|
-
interface DataSideBarLink {
|
|
51
|
-
feature: dataType[]
|
|
52
|
-
category: dataType[]
|
|
53
|
-
lainnya: dataType[]
|
|
54
|
-
}
|
|
10
|
+
// Importing the data fetch functions
|
|
11
|
+
import {
|
|
12
|
+
fetchExternalLinks,
|
|
13
|
+
fetchSidebarData,
|
|
14
|
+
DataExternalLink,
|
|
15
|
+
DataSideBarLink,
|
|
16
|
+
DataSideBarItem,
|
|
17
|
+
} from './SidebarDataController.js'
|
|
55
18
|
|
|
56
19
|
@customElement('kompasid-menu-side-bar')
|
|
57
20
|
export class KompasMenuSideBar extends LitElement {
|
|
58
|
-
hasSlotContent = false
|
|
59
|
-
shadowRoot: any
|
|
60
|
-
|
|
61
|
-
firstUpdated() {
|
|
62
|
-
const slot = this.shadowRoot?.querySelector('slot')
|
|
63
|
-
const assignedNodes = slot!.assignedNodes({ flatten: true })
|
|
64
|
-
|
|
65
|
-
this.hasSlotContent = assignedNodes.length > 0
|
|
66
|
-
}
|
|
67
|
-
|
|
68
21
|
static styles = [
|
|
69
22
|
css`
|
|
70
23
|
.slide-side-enter-active,
|
|
@@ -86,228 +39,107 @@ export class KompasMenuSideBar extends LitElement {
|
|
|
86
39
|
.menu-menu-sidebar::-webkit-scrollbar {
|
|
87
40
|
width: 4px;
|
|
88
41
|
}
|
|
89
|
-
|
|
90
42
|
.menu-menu-sidebar::-webkit-scrollbar-track {
|
|
91
43
|
background: white;
|
|
92
44
|
}
|
|
93
|
-
|
|
94
45
|
.menu-menu-sidebar::-webkit-scrollbar-thumb {
|
|
95
46
|
background-color: #00557d; /* Replace with your brand color */
|
|
96
47
|
border-radius: 8px;
|
|
97
48
|
}
|
|
98
|
-
|
|
99
49
|
.menu-menu-sidebar::-webkit-scrollbar-button,
|
|
100
50
|
.menu-menu-sidebar::-webkit-scrollbar-corner {
|
|
101
51
|
background-color: white;
|
|
102
52
|
}
|
|
53
|
+
/* existing styles */
|
|
103
54
|
`,
|
|
104
55
|
TWStyles,
|
|
105
56
|
]
|
|
106
|
-
@property({ type: Array }) dataExternal: DataExternalLink[] = []
|
|
107
|
-
@property({ type: Boolean }) isDark = false
|
|
108
57
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
} catch (error) {
|
|
114
|
-
this.handleFetchError(error)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
58
|
+
/**
|
|
59
|
+
* Props
|
|
60
|
+
* property kompasProSubscription untuk menghandle apakah user sudah login atau belum
|
|
61
|
+
*/
|
|
117
62
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
alert(`Terjadi kesalahan: ${errorMessage}`)
|
|
122
|
-
}
|
|
63
|
+
@property({ type: Boolean }) isDark = false
|
|
64
|
+
@property({ type: Boolean }) isProductionMode = false
|
|
65
|
+
@property({ type: String }) subscriptionPackage = ''
|
|
123
66
|
|
|
124
|
-
|
|
67
|
+
@state() dataExternal: DataExternalLink[] = []
|
|
68
|
+
@state() dataSidebar: DataSideBarLink = {
|
|
69
|
+
bundles: [],
|
|
125
70
|
feature: [],
|
|
126
71
|
category: [],
|
|
127
72
|
lainnya: [],
|
|
128
73
|
}
|
|
74
|
+
@state() showNavBar = false
|
|
75
|
+
@state() expandedSlug: string | null = null
|
|
76
|
+
hasSlotContent = false
|
|
129
77
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
'Content-Type': 'application/json',
|
|
136
|
-
},
|
|
137
|
-
})
|
|
138
|
-
const resultExternal = await response.json()
|
|
139
|
-
// eslint-disable-next-line no-undef
|
|
140
|
-
if (!resultExternal || !Array.isArray(resultExternal)) {
|
|
141
|
-
console.error(
|
|
142
|
-
'Error: resultExternal.result is undefined or not an array',
|
|
143
|
-
resultExternal
|
|
144
|
-
)
|
|
145
|
-
this.dataExternal = [] // Ensure dataExternal is an empty array instead of undefined
|
|
146
|
-
} else {
|
|
147
|
-
this.dataExternal = resultExternal.map(
|
|
148
|
-
(externalLink: Partial<DataExternalLink>) => ({
|
|
149
|
-
external: externalLink.external ?? false,
|
|
150
|
-
gtmClass: externalLink.gtmClass ?? '',
|
|
151
|
-
icon: externalLink.icon ?? null,
|
|
152
|
-
iconify: externalLink.iconify ?? null,
|
|
153
|
-
isNew: externalLink.isNew ?? false,
|
|
154
|
-
name: externalLink.name ?? '',
|
|
155
|
-
url: externalLink.url ?? '',
|
|
156
|
-
})
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Sidebar
|
|
161
|
-
const endpointSidebar = `https://cdn-dev-www.kompas.id/assets/json/ApiMenuSideV3.json`
|
|
162
|
-
const responseSidebar = await fetch(endpointSidebar, {
|
|
163
|
-
headers: {
|
|
164
|
-
'Content-Type': 'application/json',
|
|
165
|
-
},
|
|
166
|
-
})
|
|
167
|
-
const resultSidebar = await responseSidebar.json()
|
|
168
|
-
// Validate the structure of the response
|
|
169
|
-
if (!resultSidebar || typeof resultSidebar !== 'object') {
|
|
170
|
-
console.error('Invalid response format:', resultSidebar)
|
|
171
|
-
return
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Convert object to an array
|
|
175
|
-
const sidebarArray = Object.values(resultSidebar)
|
|
176
|
-
const [featureArray, categoryArray, othersArray] = sidebarArray as [
|
|
177
|
-
any[],
|
|
178
|
-
any[],
|
|
179
|
-
any[]
|
|
180
|
-
]
|
|
181
|
-
const features: dataType[] =
|
|
182
|
-
featureArray?.map((item: any) => ({
|
|
183
|
-
href: item?.href ?? '',
|
|
184
|
-
external: item?.external ?? false,
|
|
185
|
-
icon: item?.icon ?? null,
|
|
186
|
-
iconify: item?.iconify ?? null,
|
|
187
|
-
name: item?.name ?? '',
|
|
188
|
-
slug: item?.slug ?? '',
|
|
189
|
-
redDot: [
|
|
190
|
-
{
|
|
191
|
-
start: item?.redDot?.start ?? '',
|
|
192
|
-
end: item?.redDot?.end ?? '',
|
|
193
|
-
},
|
|
194
|
-
],
|
|
195
|
-
children: Array.isArray(item?.children)
|
|
196
|
-
? item.children.map((child: any) => ({
|
|
197
|
-
href: child?.href ?? '',
|
|
198
|
-
external: child?.external ?? false,
|
|
199
|
-
icon: child?.icon ?? '',
|
|
200
|
-
iconify: child?.iconify ?? '',
|
|
201
|
-
name: child?.name ?? '',
|
|
202
|
-
slug: child?.slug ?? '',
|
|
203
|
-
redDot: [
|
|
204
|
-
{
|
|
205
|
-
start: child?.redDot?.start ?? '',
|
|
206
|
-
end: child?.redDot?.end ?? '',
|
|
207
|
-
},
|
|
208
|
-
],
|
|
209
|
-
}))
|
|
210
|
-
: [],
|
|
211
|
-
})) ?? []
|
|
78
|
+
// Fetch data when the component is connected to the DOM
|
|
79
|
+
async connectedCallback() {
|
|
80
|
+
super.connectedCallback()
|
|
81
|
+
await this.loadData()
|
|
82
|
+
}
|
|
212
83
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
icon: item?.icon ?? null,
|
|
219
|
-
iconify: item?.iconify ?? null,
|
|
220
|
-
name: item?.name ?? '',
|
|
221
|
-
slug: item?.slug ?? '',
|
|
222
|
-
redDot: [
|
|
223
|
-
{
|
|
224
|
-
start: item?.redDot?.start ?? '',
|
|
225
|
-
end: item?.redDot?.end ?? '',
|
|
226
|
-
},
|
|
227
|
-
],
|
|
228
|
-
children: Array.isArray(item?.children)
|
|
229
|
-
? item.children.map((child: any) => ({
|
|
230
|
-
href: child?.href ?? '',
|
|
231
|
-
external: child?.external ?? false,
|
|
232
|
-
icon: child?.icon ?? '',
|
|
233
|
-
iconify: child?.iconify ?? '',
|
|
234
|
-
name: child?.name ?? '',
|
|
235
|
-
slug: child?.slug ?? '',
|
|
236
|
-
redDot: [
|
|
237
|
-
{
|
|
238
|
-
start: child?.redDot?.start ?? '',
|
|
239
|
-
end: child?.redDot?.end ?? '',
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
|
-
}))
|
|
243
|
-
: [],
|
|
244
|
-
})) ?? []
|
|
84
|
+
private hasKompasOnePackage(): boolean {
|
|
85
|
+
return this.subscriptionPackage
|
|
86
|
+
?.split(' ')
|
|
87
|
+
.some(pkg => pkg.includes('kompas-one'))
|
|
88
|
+
}
|
|
245
89
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
icon: item?.icon ?? null,
|
|
252
|
-
iconify: item?.iconify ?? null,
|
|
253
|
-
name: item?.name ?? '',
|
|
254
|
-
slug: item?.slug ?? '',
|
|
255
|
-
redDot: [
|
|
256
|
-
{
|
|
257
|
-
start: item?.redDot?.start ?? '',
|
|
258
|
-
end: item?.redDot?.end ?? '',
|
|
259
|
-
},
|
|
260
|
-
],
|
|
261
|
-
children: Array.isArray(item?.children)
|
|
262
|
-
? item.children.map((child: any) => ({
|
|
263
|
-
href: child?.href ?? '',
|
|
264
|
-
external: child?.external ?? false,
|
|
265
|
-
icon: child?.icon ?? '',
|
|
266
|
-
iconify: child?.iconify ?? '',
|
|
267
|
-
name: child?.name ?? '',
|
|
268
|
-
slug: child?.slug ?? '',
|
|
269
|
-
redDot: [
|
|
270
|
-
{
|
|
271
|
-
start: child?.redDot?.start ?? '',
|
|
272
|
-
end: child?.redDot?.end ?? '',
|
|
273
|
-
},
|
|
274
|
-
],
|
|
275
|
-
}))
|
|
276
|
-
: [],
|
|
277
|
-
})) ?? []
|
|
90
|
+
private hasKompasProPackage(): boolean {
|
|
91
|
+
return this.subscriptionPackage
|
|
92
|
+
?.split(' ')
|
|
93
|
+
.some(pkg => pkg.includes('kompas-pro'))
|
|
94
|
+
}
|
|
278
95
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
96
|
+
private filterBundles(bundles: DataSideBarItem[]): DataSideBarItem[] {
|
|
97
|
+
return bundles
|
|
98
|
+
.filter(b => b.isShow)
|
|
99
|
+
.map(b => {
|
|
100
|
+
if (b.name === 'Kompas One') {
|
|
101
|
+
return {
|
|
102
|
+
...b,
|
|
103
|
+
children: this.hasKompasOnePackage() ? b.children : [],
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (b.name === 'Kompas Pro') {
|
|
107
|
+
return {
|
|
108
|
+
...b,
|
|
109
|
+
children: this.hasKompasProPackage() ? b.children : [],
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return b
|
|
113
|
+
})
|
|
285
114
|
}
|
|
286
115
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
return chips
|
|
116
|
+
// Function to load the data using async API calls
|
|
117
|
+
private async loadData() {
|
|
118
|
+
try {
|
|
119
|
+
const [extData, sbData] = await Promise.all([
|
|
120
|
+
fetchExternalLinks(this.isProductionMode),
|
|
121
|
+
fetchSidebarData(this.isProductionMode),
|
|
122
|
+
])
|
|
123
|
+
|
|
124
|
+
this.dataExternal = extData
|
|
125
|
+
this.dataSidebar = {
|
|
126
|
+
...sbData,
|
|
127
|
+
bundles: this.filterBundles(sbData.bundles),
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('Error loading data:', error)
|
|
131
|
+
}
|
|
304
132
|
}
|
|
305
133
|
|
|
306
|
-
|
|
307
|
-
|
|
134
|
+
private toggleNavSidebar(e: Event) {
|
|
135
|
+
e.stopPropagation()
|
|
136
|
+
this.showNavBar = !this.showNavBar
|
|
308
137
|
}
|
|
309
138
|
|
|
310
|
-
rubricClicked(
|
|
139
|
+
private rubricClicked(
|
|
140
|
+
item: { name: string; href?: string },
|
|
141
|
+
event?: Event
|
|
142
|
+
): void {
|
|
311
143
|
if (event) {
|
|
312
144
|
event.stopPropagation() // Prevent parent click event
|
|
313
145
|
}
|
|
@@ -318,62 +150,191 @@ export class KompasMenuSideBar extends LitElement {
|
|
|
318
150
|
// add data layer here
|
|
319
151
|
}
|
|
320
152
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
153
|
+
private hasChildren(item: DataSideBarItem): boolean {
|
|
154
|
+
return Array.isArray(item.children) && item.children.length > 0
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private toggleChildren(item: DataSideBarItem) {
|
|
324
158
|
this.expandedSlug = this.expandedSlug === item.slug ? null : item.slug
|
|
325
159
|
}
|
|
326
160
|
|
|
327
|
-
|
|
328
|
-
|
|
161
|
+
private renderItem(item: any, padClass: string) {
|
|
162
|
+
return html`
|
|
163
|
+
<div class="w-full font-sans text-black">
|
|
164
|
+
<div
|
|
165
|
+
class="flex items-center justify-between text-sm font-medium ${padClass} transition-all cursor-pointer"
|
|
166
|
+
role="button"
|
|
167
|
+
tabindex="0"
|
|
168
|
+
@click=${(e: Event) => this.rubricClicked(item, e)}
|
|
169
|
+
@keydown=${(e: KeyboardEvent) => {
|
|
170
|
+
if (e.key === 'Enter') this.rubricClicked(item, e)
|
|
171
|
+
}}
|
|
172
|
+
>
|
|
173
|
+
<div
|
|
174
|
+
class="w-[216px] hover:bg-[#f3f4f6] rounded h-12 flex items-center space-x-3"
|
|
175
|
+
>
|
|
176
|
+
${item.iconSrc
|
|
177
|
+
? html`<div class="flex">
|
|
178
|
+
<img
|
|
179
|
+
src="${item.iconSrc}"
|
|
180
|
+
alt="Kompas.id"
|
|
181
|
+
scale="0"
|
|
182
|
+
class="block w-5"
|
|
183
|
+
/>
|
|
184
|
+
</div>`
|
|
185
|
+
: ''}
|
|
186
|
+
<span class="font-bold">${decodeSpecialChars(item.name)}</span>
|
|
187
|
+
${timedContent(item.redDot.start ?? '', item.redDot.end ?? '')
|
|
188
|
+
? html`<span
|
|
189
|
+
class="bg-orange-400 h‑2 w‑2 rounded-full relative -top-[12px] shrink-0"
|
|
190
|
+
></span>`
|
|
191
|
+
: ''}
|
|
192
|
+
</div>
|
|
193
|
+
${this.hasChildren(item)
|
|
194
|
+
? html`
|
|
195
|
+
<span
|
|
196
|
+
class="flex justify-center items-center rounded my‑1 py‑4 w‑10 h‑10 cursor‑pointer text-grey-400"
|
|
197
|
+
role="button"
|
|
198
|
+
tabindex="0"
|
|
199
|
+
@click=${(e: Event) => {
|
|
200
|
+
e.stopPropagation()
|
|
201
|
+
this.toggleChildren(item)
|
|
202
|
+
}}
|
|
203
|
+
@keydown=${(e: KeyboardEvent) => {
|
|
204
|
+
if (e.key === 'Enter') {
|
|
205
|
+
e.stopPropagation()
|
|
206
|
+
this.toggleChildren(item)
|
|
207
|
+
}
|
|
208
|
+
}}
|
|
209
|
+
>
|
|
210
|
+
${unsafeSVG(
|
|
211
|
+
getFontAwesomeIcon(
|
|
212
|
+
'fas',
|
|
213
|
+
this.expandedSlug === item.slug
|
|
214
|
+
? 'chevron-up'
|
|
215
|
+
: 'chevron-down',
|
|
216
|
+
12,
|
|
217
|
+
12
|
|
218
|
+
)
|
|
219
|
+
)}
|
|
220
|
+
</span>
|
|
221
|
+
`
|
|
222
|
+
: null}
|
|
223
|
+
</div>
|
|
329
224
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
225
|
+
${this.hasChildren(item) && this.expandedSlug === item.slug
|
|
226
|
+
? html`<div
|
|
227
|
+
class="${padClass.includes('px-6')
|
|
228
|
+
? 'pt‑1 pb‑2 space-y‑1 text-black'
|
|
229
|
+
: 'pl‑14 pt‑1 pb‑2 space-y‑1 text-black'}"
|
|
230
|
+
>
|
|
231
|
+
${repeat(
|
|
232
|
+
item.children ?? [],
|
|
233
|
+
(c: DataSideBarItem) => c.slug,
|
|
234
|
+
(child: DataSideBarItem) => html`
|
|
235
|
+
<div
|
|
236
|
+
role="button"
|
|
237
|
+
tabindex="0"
|
|
238
|
+
class="flex items-center justify-between text-sm font-medium px-6 transition-all cursor-pointer"
|
|
239
|
+
@click=${() => this.rubricClicked(child)}
|
|
240
|
+
@keydown=${(e: KeyboardEvent) => {
|
|
241
|
+
if (e.key === 'Enter') this.rubricClicked(child, e)
|
|
242
|
+
}}
|
|
243
|
+
>
|
|
244
|
+
<div
|
|
245
|
+
class="w-[216px] hover:bg-[#f3f4f6] rounded h-12 flex items-center pl-8"
|
|
246
|
+
>
|
|
247
|
+
${decodeSpecialChars(child.name)}
|
|
248
|
+
${timedContent(
|
|
249
|
+
child.redDot.start ?? '',
|
|
250
|
+
child.redDot.end ?? ''
|
|
251
|
+
)
|
|
252
|
+
? html`<span
|
|
253
|
+
class="bg-orange-400 h‑2 w‑2 rounded-full relative -top-[12px] shrink-0"
|
|
254
|
+
></span>`
|
|
255
|
+
: ''}
|
|
256
|
+
</div>
|
|
257
|
+
<span class="ml-auto text-grey-400">
|
|
258
|
+
${child.external
|
|
259
|
+
? unsafeSVG(
|
|
260
|
+
getFontAwesomeIcon('fas', 'external-link', 16, 16)
|
|
261
|
+
)
|
|
262
|
+
: ''}
|
|
263
|
+
</span>
|
|
264
|
+
</div>
|
|
265
|
+
`
|
|
266
|
+
)}
|
|
267
|
+
</div>`
|
|
268
|
+
: ''}
|
|
269
|
+
</div>
|
|
270
|
+
`
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private renderSection(title: string | null, items: any[], padClass: string) {
|
|
274
|
+
if (!items || items.length === 0) return null // skip if empty data
|
|
275
|
+
return html`
|
|
276
|
+
${title
|
|
277
|
+
? html`<span class="text-sm text-grey-400 ${padClass} font-normal"
|
|
278
|
+
>${title}</span
|
|
279
|
+
>`
|
|
280
|
+
: null}
|
|
281
|
+
${repeat(
|
|
282
|
+
items,
|
|
283
|
+
item => item.slug,
|
|
284
|
+
item => this.renderItem(item, padClass)
|
|
285
|
+
)}
|
|
286
|
+
`
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private renderChips() {
|
|
290
|
+
return html`
|
|
291
|
+
<div
|
|
292
|
+
class="py-0.5 px-1.5 rounded-full bg-[#D71920] inline-flex"
|
|
293
|
+
style="background-color:#D71920;"
|
|
294
|
+
>
|
|
295
|
+
<span class="font-bold font-sans text-xs text-white capitalize"
|
|
296
|
+
>Baru</span
|
|
297
|
+
>
|
|
298
|
+
</div>
|
|
299
|
+
`
|
|
333
300
|
}
|
|
334
301
|
|
|
335
302
|
render() {
|
|
336
303
|
return html`
|
|
337
|
-
<!-- Button
|
|
304
|
+
<!-- Toggle Button -->
|
|
338
305
|
<div
|
|
306
|
+
role="button"
|
|
307
|
+
tabindex="0"
|
|
339
308
|
class="w-fit flex items-center justify-center cursor-pointer relative"
|
|
340
309
|
@click=${this.toggleNavSidebar}
|
|
310
|
+
@keydown=${(e: KeyboardEvent) => {
|
|
311
|
+
if (e.key === 'Enter') this.toggleNavSidebar(e)
|
|
312
|
+
}}
|
|
341
313
|
>
|
|
342
314
|
<slot></slot>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
</div>
|
|
352
|
-
<span
|
|
353
|
-
class="font-sans hidden sm:inline ml-2 tracking-wide font-bold ${this
|
|
354
|
-
.isDark
|
|
355
|
-
? 'text-[#FFFFFF]'
|
|
356
|
-
: 'text-brand-1'}"
|
|
357
|
-
>
|
|
358
|
-
Menu
|
|
359
|
-
</span>
|
|
360
|
-
`
|
|
361
|
-
: ''}
|
|
315
|
+
<div class="h-4 inline-flex text-brand-1">
|
|
316
|
+
${unsafeSVG(getFontAwesomeIcon('fas', 'bars', 20, 20))}
|
|
317
|
+
</div>
|
|
318
|
+
<span
|
|
319
|
+
class="font-sans hidden sm:inline ml-2 tracking-wide font-bold text-brand-1"
|
|
320
|
+
>
|
|
321
|
+
Menu
|
|
322
|
+
</span>
|
|
362
323
|
</div>
|
|
363
|
-
<!--
|
|
324
|
+
<!-- Sidebar Menu -->
|
|
364
325
|
<nav
|
|
365
|
-
@click=${this.toggleNavSidebar}
|
|
366
326
|
class=${this.showNavBar
|
|
367
327
|
? 'fixed left-0 top-0 w-screen z-[100]'
|
|
368
328
|
: 'hidden'}
|
|
369
329
|
>
|
|
330
|
+
<!-- Sidebar Content -->
|
|
370
331
|
<div
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
style="width: 312px;"
|
|
332
|
+
class="bg-white h-screen menu-menu-sidebar overflow-y-auto pb-20 shadow-lg"
|
|
333
|
+
style="width:312px;"
|
|
374
334
|
>
|
|
335
|
+
<!-- Logo and Close Button -->
|
|
375
336
|
<div
|
|
376
|
-
class="bg-[#FFFFFF] flex flex-col items-center justify-center
|
|
337
|
+
class="bg-[#FFFFFF] flex flex-col items-center justify-center w-full"
|
|
377
338
|
>
|
|
378
339
|
<div
|
|
379
340
|
ref="logo-kompas"
|
|
@@ -388,343 +349,74 @@ export class KompasMenuSideBar extends LitElement {
|
|
|
388
349
|
/>
|
|
389
350
|
</a>
|
|
390
351
|
<span
|
|
352
|
+
role="button"
|
|
353
|
+
tabindex="0"
|
|
391
354
|
class="font-bold cursor-pointer text-grey-400 flex h-10 items-center justify-center rounded text-base w-10 py-4"
|
|
392
355
|
@click=${this.toggleNavSidebar}
|
|
356
|
+
@keydown=${(e: KeyboardEvent) => {
|
|
357
|
+
if (e.key === 'Enter') this.toggleNavSidebar(e)
|
|
358
|
+
}}
|
|
393
359
|
>
|
|
394
360
|
${unsafeSVG(getFontAwesomeIcon('fa', 'times', 20, 20))}
|
|
395
361
|
</span>
|
|
396
362
|
</div>
|
|
397
|
-
<div class="flex flex-wrap px-6 w-full">
|
|
398
|
-
${this.dataExternal.map(
|
|
399
|
-
item => html`
|
|
400
|
-
<a href="${item.url}" class="flex w-1/2 no-underline">
|
|
401
|
-
<div
|
|
402
|
-
class="cursor-pointer flex items-center pb-4 w-[312px]"
|
|
403
|
-
>
|
|
404
|
-
${item.icon &&
|
|
405
|
-
Array.isArray(item.icon) &&
|
|
406
|
-
item.icon.length >= 2
|
|
407
|
-
? html`
|
|
408
|
-
<div class="flex mr-2 text-brand-1">
|
|
409
|
-
${unsafeSVG(
|
|
410
|
-
getFontAwesomeIcon(item.icon[0], item.icon[1])
|
|
411
|
-
)}
|
|
412
|
-
</div>
|
|
413
|
-
`
|
|
414
|
-
: ''}
|
|
415
|
-
<span class="font-sans relative text-xs text-[#666666]">
|
|
416
|
-
${item.name}
|
|
417
|
-
</span>
|
|
418
|
-
<div class="ml-1">
|
|
419
|
-
${item.isNew ? this.renderChips() : ''}
|
|
420
|
-
</div>
|
|
421
|
-
</div>
|
|
422
|
-
</a>
|
|
423
|
-
`
|
|
424
|
-
)}
|
|
425
|
-
</div>
|
|
426
363
|
</div>
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
<span
|
|
444
|
-
class="text-sm font-bold relative text-[#333] w-full"
|
|
445
|
-
>${decodeSpecialChars(item.name)}</span
|
|
446
|
-
>
|
|
447
|
-
${timedContent(
|
|
448
|
-
item.redDot[0].start,
|
|
449
|
-
item.redDot[0].end
|
|
450
|
-
)
|
|
451
|
-
? html`<span
|
|
452
|
-
class="bg-orange-400 h-2 relative rounded-full w-2 flex shrink-0 -top-[12px]"
|
|
453
|
-
></span>`
|
|
454
|
-
: ''}
|
|
455
|
-
</div>
|
|
456
|
-
</div>
|
|
457
|
-
|
|
458
|
-
<!-- Toggle chevron -->
|
|
459
|
-
${this.hasChildren(item)
|
|
460
|
-
? html`
|
|
461
|
-
<span
|
|
462
|
-
class="text-xs text-brand-1 bg-[#e1f0ff] flex justify-center items-center rounded my-1 p-4 w-10 h-10 cursor-pointer"
|
|
463
|
-
@click=${(e: Event) => {
|
|
464
|
-
e.stopPropagation() // Prevents click from bubbling to parent
|
|
465
|
-
this.toggleChildren(item)
|
|
466
|
-
}}
|
|
467
|
-
>
|
|
468
|
-
${this.expandedSlug === item.slug
|
|
469
|
-
? unsafeSVG(
|
|
470
|
-
getFontAwesomeIcon(
|
|
471
|
-
'fas',
|
|
472
|
-
'chevron-up',
|
|
473
|
-
12,
|
|
474
|
-
12
|
|
475
|
-
)
|
|
476
|
-
)
|
|
477
|
-
: unsafeSVG(
|
|
478
|
-
getFontAwesomeIcon(
|
|
479
|
-
'fas',
|
|
480
|
-
'chevron-down',
|
|
481
|
-
12,
|
|
482
|
-
12
|
|
483
|
-
)
|
|
484
|
-
)}
|
|
485
|
-
</span>
|
|
486
|
-
`
|
|
487
|
-
: null}
|
|
488
|
-
</div>
|
|
489
|
-
|
|
490
|
-
<!-- Children items -->
|
|
491
|
-
${this.hasChildren(item) && this.expandedSlug === item.slug
|
|
492
|
-
? html`
|
|
493
|
-
<div class="pl-14 pt-1 pb-2 space-y-1">
|
|
494
|
-
${item.children.map(
|
|
495
|
-
child => html`
|
|
496
|
-
<div
|
|
497
|
-
class="flex items-center text-sm text-[#333] px-4 cursor-pointer transition-all"
|
|
498
|
-
@click=${() => this.rubricClicked(child)}
|
|
499
|
-
>
|
|
500
|
-
<div
|
|
501
|
-
class="w-[216px] hover:bg-[#f3f4f6] rounded h-12 flex items-center pl-11"
|
|
502
|
-
>
|
|
503
|
-
${decodeSpecialChars(child.name)}
|
|
504
|
-
${timedContent(
|
|
505
|
-
child.redDot[0].start,
|
|
506
|
-
child.redDot[0].end
|
|
507
|
-
)
|
|
508
|
-
? html`<span
|
|
509
|
-
class="bg-orange-400 h-2 relative rounded-full w-2 flex shrink-0 -top-[12px]"
|
|
510
|
-
></span>`
|
|
511
|
-
: ''}
|
|
512
|
-
<div></div>
|
|
513
|
-
</div>
|
|
514
|
-
</div>
|
|
515
|
-
`
|
|
516
|
-
)}
|
|
517
|
-
</div>
|
|
518
|
-
`
|
|
364
|
+
<!-- External Links -->
|
|
365
|
+
<div class="flex flex-wrap px-6">
|
|
366
|
+
${repeat(
|
|
367
|
+
this.dataExternal,
|
|
368
|
+
item => item.name,
|
|
369
|
+
item => html`
|
|
370
|
+
<a href="${item.url}" class="flex w-1/2 no-underline px-2">
|
|
371
|
+
<div class="cursor-pointer flex items-center pb-4">
|
|
372
|
+
${item.icon &&
|
|
373
|
+
Array.isArray(item.icon) &&
|
|
374
|
+
item.icon.length >= 2
|
|
375
|
+
? html`<div class="flex mr-2 text-brand-1">
|
|
376
|
+
${unsafeSVG(
|
|
377
|
+
getFontAwesomeIcon(item.icon[0], item.icon[1])
|
|
378
|
+
)}
|
|
379
|
+
</div>`
|
|
519
380
|
: ''}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
)}
|
|
523
|
-
</div>
|
|
524
|
-
</div>
|
|
525
|
-
<div class="border-b border-[#DDD] m-6 "></div>
|
|
526
|
-
<!-- category -->
|
|
527
|
-
<div class="flex">
|
|
528
|
-
<div class="w-full flex justify-between flex-col">
|
|
529
|
-
<span class="text-sm text-grey-400 px-6 font-normal"
|
|
530
|
-
>Redaksional</span
|
|
531
|
-
>
|
|
532
|
-
${this.dataSidebar.category.map(
|
|
533
|
-
item => html`
|
|
534
|
-
<div class="w-full font-sans">
|
|
535
|
-
<!-- Parent item -->
|
|
536
|
-
<div
|
|
537
|
-
class="flex items-center justify-between text-sm font-medium px-6 transition-all cursor-pointer"
|
|
538
|
-
@click=${(e: Event) => this.rubricClicked(item, e)}
|
|
381
|
+
<span class="font-sans text-xs text-[#666666]"
|
|
382
|
+
>${item.name}</span
|
|
539
383
|
>
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
>
|
|
543
|
-
<div class="flex items-center space-x-3">
|
|
544
|
-
<span
|
|
545
|
-
class="font-bold ${item.name === 'Beranda'
|
|
546
|
-
? 'text-[#00559a]'
|
|
547
|
-
: 'text-[#333] w-full'}"
|
|
548
|
-
>${decodeSpecialChars(item.name)}</span
|
|
549
|
-
>
|
|
550
|
-
|
|
551
|
-
${timedContent(
|
|
552
|
-
item.redDot[0].start,
|
|
553
|
-
item.redDot[0].end
|
|
554
|
-
)
|
|
555
|
-
? html`<span
|
|
556
|
-
class="bg-orange-400 h-2 relative rounded-full w-2 flex shrink-0 -top-[12px]"
|
|
557
|
-
></span>`
|
|
558
|
-
: ''}
|
|
559
|
-
</div>
|
|
560
|
-
</div>
|
|
561
|
-
|
|
562
|
-
<!-- Toggle chevron -->
|
|
563
|
-
${this.hasChildren(item)
|
|
564
|
-
? html`
|
|
565
|
-
<span
|
|
566
|
-
class="flex justify-center items-center rounded my-1 py-4 w-10 h-10 cursor-pointer font-bold text-grey-400"
|
|
567
|
-
@click=${(e: Event) => {
|
|
568
|
-
e.stopPropagation() // Prevents click from bubbling to parent
|
|
569
|
-
this.toggleChildren(item)
|
|
570
|
-
}}
|
|
571
|
-
>
|
|
572
|
-
${this.expandedSlug === item.slug
|
|
573
|
-
? unsafeSVG(
|
|
574
|
-
getFontAwesomeIcon(
|
|
575
|
-
'fas',
|
|
576
|
-
'chevron-up',
|
|
577
|
-
12,
|
|
578
|
-
12
|
|
579
|
-
)
|
|
580
|
-
)
|
|
581
|
-
: unsafeSVG(
|
|
582
|
-
getFontAwesomeIcon(
|
|
583
|
-
'fas',
|
|
584
|
-
'chevron-down',
|
|
585
|
-
12,
|
|
586
|
-
12
|
|
587
|
-
)
|
|
588
|
-
)}
|
|
589
|
-
</span>
|
|
590
|
-
`
|
|
591
|
-
: null}
|
|
592
|
-
</div>
|
|
593
|
-
|
|
594
|
-
<!-- Children items -->
|
|
595
|
-
${this.hasChildren(item) && this.expandedSlug === item.slug
|
|
596
|
-
? html`
|
|
597
|
-
<div class="pt-1 pb-2 space-y-1">
|
|
598
|
-
${item.children.map(
|
|
599
|
-
child => html`
|
|
600
|
-
<div
|
|
601
|
-
class="flex items-center text-sm text-[#333] px-4 cursor-pointer transition-all"
|
|
602
|
-
@click=${() => this.rubricClicked(child)}
|
|
603
|
-
>
|
|
604
|
-
<div
|
|
605
|
-
class="w-[216px] hover:bg-[#f3f4f6] rounded h-12 flex items-center pl-11"
|
|
606
|
-
>
|
|
607
|
-
${decodeSpecialChars(child.name)}
|
|
608
|
-
${timedContent(
|
|
609
|
-
child.redDot[0].start,
|
|
610
|
-
child.redDot[0].end
|
|
611
|
-
)
|
|
612
|
-
? html`<span
|
|
613
|
-
class="bg-orange-400 h-2 relative rounded-full w-2 flex shrink-0 -top-[12px]"
|
|
614
|
-
></span>`
|
|
615
|
-
: ''}
|
|
616
|
-
</div>
|
|
617
|
-
</div>
|
|
618
|
-
`
|
|
619
|
-
)}
|
|
620
|
-
</div>
|
|
621
|
-
`
|
|
384
|
+
${item.isNew
|
|
385
|
+
? html`<span class="ml-1">${this.renderChips()}</span>`
|
|
622
386
|
: ''}
|
|
623
387
|
</div>
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
</div>
|
|
628
|
-
|
|
629
|
-
<div class="border-b border-[#DDD] m-6 "></div>
|
|
630
|
-
<!-- Lainnya -->
|
|
631
|
-
<div class="flex">
|
|
632
|
-
<div class="w-full flex justify-between flex-col">
|
|
633
|
-
<span class="text-sm text-grey-400 px-6 font-normal"
|
|
634
|
-
>Lainnya</span
|
|
635
|
-
>
|
|
636
|
-
${this.dataSidebar.lainnya.map(
|
|
637
|
-
item => html`
|
|
638
|
-
<div class="w-full font-sans">
|
|
639
|
-
<!-- Parent item -->
|
|
640
|
-
<div
|
|
641
|
-
class="flex items-center justify-between text-sm font-medium px-6 transition-all cursor-pointer"
|
|
642
|
-
@click=${(e: Event) => this.rubricClicked(item, e)}
|
|
643
|
-
>
|
|
644
|
-
<div
|
|
645
|
-
class="w-[216px] hover:bg-[#f3f4f6] rounded h-12 flex items-center"
|
|
646
|
-
>
|
|
647
|
-
<div class="flex items-center space-x-3">
|
|
648
|
-
<span class="font-bold text-[#333]"
|
|
649
|
-
>${decodeSpecialChars(item.name)}</span
|
|
650
|
-
>
|
|
651
|
-
${timedContent(
|
|
652
|
-
item.redDot[0].start,
|
|
653
|
-
item.redDot[0].end
|
|
654
|
-
)
|
|
655
|
-
? html`<span
|
|
656
|
-
class="bg-orange-400 h-2 relative rounded-full w-2 flex shrink-0 -top-[12px]"
|
|
657
|
-
></span>`
|
|
658
|
-
: ''}
|
|
659
|
-
</div>
|
|
660
|
-
</div>
|
|
661
|
-
|
|
662
|
-
<!-- Toggle chevron -->
|
|
663
|
-
${this.hasChildren(item)
|
|
664
|
-
? html`
|
|
665
|
-
<span
|
|
666
|
-
class="flex justify-center items-center rounded my-1 py-4 w-10 h-10 cursor-pointer font-bold"
|
|
667
|
-
@click=${(e: Event) => {
|
|
668
|
-
e.stopPropagation() // Prevents click from bubbling to parent
|
|
669
|
-
this.toggleChildren(item)
|
|
670
|
-
}}
|
|
671
|
-
>
|
|
672
|
-
${this.expandedSlug === item.slug
|
|
673
|
-
? unsafeSVG(
|
|
674
|
-
getFontAwesomeIcon(
|
|
675
|
-
'fas',
|
|
676
|
-
'chevron-up',
|
|
677
|
-
12,
|
|
678
|
-
12
|
|
679
|
-
)
|
|
680
|
-
)
|
|
681
|
-
: unsafeSVG(
|
|
682
|
-
getFontAwesomeIcon(
|
|
683
|
-
'fas',
|
|
684
|
-
'chevron-down',
|
|
685
|
-
12,
|
|
686
|
-
12
|
|
687
|
-
)
|
|
688
|
-
)}
|
|
689
|
-
</span>
|
|
690
|
-
`
|
|
691
|
-
: null}
|
|
692
|
-
</div>
|
|
693
|
-
|
|
694
|
-
<!-- Children items -->
|
|
695
|
-
${this.hasChildren(item) && this.expandedSlug === item.slug
|
|
696
|
-
? html`
|
|
697
|
-
<div class="pt-1 pb-2 space-y-1">
|
|
698
|
-
${item.children.map(
|
|
699
|
-
child => html`
|
|
700
|
-
<div
|
|
701
|
-
class="flex items-center text-sm text-[#333] px-4 cursor-pointer transition-all"
|
|
702
|
-
@click=${() => this.rubricClicked(child)}
|
|
703
|
-
>
|
|
704
|
-
<div
|
|
705
|
-
class="w-[216px] hover:bg-[#f3f4f6] rounded h-12 flex items-center pl-11"
|
|
706
|
-
>
|
|
707
|
-
${decodeSpecialChars(child.name)}
|
|
708
|
-
${timedContent(
|
|
709
|
-
child.redDot[0].start,
|
|
710
|
-
child.redDot[0].end
|
|
711
|
-
)
|
|
712
|
-
? html`<span
|
|
713
|
-
class="bg-orange-400 h-2 relative rounded-full w-2 flex shrink-0 -top-[12px]"
|
|
714
|
-
></span>`
|
|
715
|
-
: ''}
|
|
716
|
-
</div>
|
|
717
|
-
</div>
|
|
718
|
-
`
|
|
719
|
-
)}
|
|
720
|
-
</div>
|
|
721
|
-
`
|
|
722
|
-
: ''}
|
|
723
|
-
</div>
|
|
724
|
-
`
|
|
725
|
-
)}
|
|
726
|
-
</div>
|
|
388
|
+
</a>
|
|
389
|
+
`
|
|
390
|
+
)}
|
|
727
391
|
</div>
|
|
392
|
+
${this.dataExternal.length > 0
|
|
393
|
+
? html`<div class="border-b border-[#DDD] mx-6 my-4"></div>`
|
|
394
|
+
: null}
|
|
395
|
+
|
|
396
|
+
<!-- Bundle Section -->
|
|
397
|
+
${this.renderSection(null, this.dataSidebar.bundles, 'px-6')}
|
|
398
|
+
${this.dataSidebar.bundles.length > 0
|
|
399
|
+
? html`<div class="border-b border-[#DDD] mx-6 my-4"></div>`
|
|
400
|
+
: null}
|
|
401
|
+
|
|
402
|
+
<!-- Feature Section -->
|
|
403
|
+
${this.renderSection(null, this.dataSidebar.feature, 'px-6')}
|
|
404
|
+
${this.dataSidebar.feature.length > 0
|
|
405
|
+
? html`<div class="border-b border-[#DDD] mx-6 my-4"></div>`
|
|
406
|
+
: null}
|
|
407
|
+
|
|
408
|
+
<!-- Category (Redaksional) -->
|
|
409
|
+
${this.renderSection(
|
|
410
|
+
'Redaksional',
|
|
411
|
+
this.dataSidebar.category,
|
|
412
|
+
'px-6'
|
|
413
|
+
)}
|
|
414
|
+
${this.dataSidebar.category.length > 0
|
|
415
|
+
? html`<div class="border-b border-[#DDD] mx-6 my-4"></div>`
|
|
416
|
+
: null}
|
|
417
|
+
|
|
418
|
+
<!-- Others (Lainnya) -->
|
|
419
|
+
${this.renderSection('Lainnya', this.dataSidebar.lainnya, 'px-6')}
|
|
728
420
|
</div>
|
|
729
421
|
</nav>
|
|
730
422
|
`
|