1+ package com.sakethh.linkora.presentation.routing.http
2+
3+ import Colors
4+ import com.sakethh.linkora.authenticate
5+ import com.sakethh.linkora.domain.Result
6+ import com.sakethh.linkora.domain.dto.Correlation
7+ import com.sakethh.linkora.domain.dto.IDBasedDTO
8+ import com.sakethh.linkora.domain.model.Folder
9+ import com.sakethh.linkora.domain.repository.FoldersRepo
10+ import io.ktor.http.*
11+ import io.ktor.server.response.*
12+ import io.ktor.server.routing.*
13+ import kotlinx.coroutines.runBlocking
14+ import kotlinx.html.*
15+ import kotlinx.html.stream.createHTML
16+ import sakethh.kapsule.*
17+ import sakethh.kapsule.utils.*
18+
19+ fun Routing.browserExtensionRouting (foldersRepo : FoldersRepo ) {
20+ authenticate {
21+ get(" /browser-extension" ) {
22+ call.respondText(text = createHTML().html {
23+ Surface (
24+ fonts = listOf (
25+ " https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" ,
26+ " https://fonts.googleapis.com/icon?family=Material+Icons+Outlined"
27+ ),
28+ modifier = Modifier .width(400 .px).height(250 .px).backgroundColor(color = Colors .surfaceDark)
29+ .boxSizing(BoxSizing .BorderBox ).margin(0 .px).padding(0 .px).custom(" overflow: auto !important" )
30+ ) {
31+ runBlocking {
32+ BrowserExtensionUI (foldersRepo)
33+ }
34+ }
35+ }, contentType = ContentType .Text .Html )
36+ }
37+ }
38+ }
39+
40+ private suspend fun BODY.BrowserExtensionUI (foldersRepo : FoldersRepo ) {
41+ val folders = (foldersRepo.getRootFolders() as Result .Success ).response
42+ Column (
43+ modifier = Modifier .margin(15 .px).custom(
44+ """
45+ overflow: auto !important;
46+ overflow-x: auto !important;
47+ overflow-y: auto !important;
48+ """ .trimIndent()
49+ )
50+ ) {
51+ Button (
52+ modifier = Modifier .cursor(Cursor .Pointer ).height(25 .px).margin(bottom = 10 .px)
53+ .backgroundColor(Colors .codeblockBG).color(Colors .onPrimaryContainerDark),
54+ id = " change-extension-config" ,
55+ onClick = { " " }) {
56+ Text (
57+ text = " Change Extension Config" ,
58+ fontWeight = FontWeight .Predefined .Normal ,
59+ fontSize = 12 .px,
60+ fontFamily = " Inter" ,
61+ )
62+ }
63+ Text (
64+ text = " Link address" ,
65+ fontFamily = " Inter" ,
66+ fontWeight = FontWeight .Predefined .Normal ,
67+ fontSize = 10 .px,
68+ color = Colors .onSurfaceDark,
69+ )
70+ Text (
71+ id = " link" ,
72+ text = " #LINK_PLACEHOLDER#" ,
73+ fontFamily = " Inter" ,
74+ fontWeight = FontWeight .Predefined .Medium ,
75+ fontSize = 12 .px,
76+ color = Colors .onSurfaceDark,
77+ modifier = Modifier .margin(bottom = 10 .px)
78+ )
79+ Text (
80+ text = " Title for the link" ,
81+ fontFamily = " Inter" ,
82+ fontWeight = FontWeight .Predefined .Normal ,
83+ fontSize = 14 .px,
84+ color = Colors .onSurfaceDark,
85+ modifier = Modifier .margin(bottom = 5 .px)
86+ )
87+ input(type = InputType .text) {
88+ id = " link_title"
89+ style = Modifier .backgroundColor(Colors .codeblockBG).color(Colors .onSurfaceDark).height(25 .px)
90+ .margin(bottom = 10 .px).padding(end = 15 .px).fontFamily(" Inter" ).toString()
91+ }
92+ Text (
93+ text = " Note for saving the link" ,
94+ fontFamily = " Inter" ,
95+ fontWeight = FontWeight .Predefined .Normal ,
96+ fontSize = 14 .px,
97+ color = Colors .onSurfaceDark,
98+ modifier = Modifier .margin(bottom = 5 .px)
99+ )
100+ input(type = InputType .text) {
101+ id = " link_note"
102+ style = Modifier .backgroundColor(Colors .codeblockBG).color(Colors .onSurfaceDark).height(25 .px)
103+ .margin(bottom = 10 .px).padding(end = 15 .px).fontFamily(" Inter" ).toString()
104+ }
105+ Text (
106+ text = " Total root folders found: ${folders.size} " ,
107+ fontFamily = " Inter" ,
108+ fontWeight = FontWeight .Predefined .Thin ,
109+ fontSize = 14 .px,
110+ color = Colors .onSurfaceDark,
111+ )
112+ Spacer (modifier = Modifier .height(8.5 .px))
113+ Button (
114+ modifier = Modifier .cursor(Cursor .Pointer ).height(25 .px).margin(bottom = 10 .px)
115+ .backgroundColor(Colors .codeblockBG).color(Colors .onPrimaryContainerDark),
116+ id = " add-new-root-folder" ,
117+ onClick = { " " }) {
118+ Text (
119+ text = " Create a new root folder" ,
120+ fontWeight = FontWeight .Predefined .Medium ,
121+ fontSize = 12 .px,
122+ fontFamily = " Inter" ,
123+ )
124+ }
125+ Text (
126+ text = " Save to folder:" ,
127+ fontFamily = " Inter" ,
128+ fontWeight = FontWeight .Predefined .SemiBold ,
129+ fontSize = 16 .px,
130+ color = Colors .primaryDark,
131+ )
132+ Spacer (modifier = Modifier .height(10 .px))
133+ Div (id = " folders-list" ) {
134+ FolderComponent (
135+ icon = " link" , folder = Folder (
136+ id = - 1 , name = " Saved Links" , note = " " , parentFolderId = 0 , isArchived = false , eventTimestamp = 0
137+ )
138+ )
139+
140+ FolderComponent (
141+ icon = " star_outline" , folder = Folder (
142+ id = - 2 ,
143+ name = " Important Links" ,
144+ note = " " ,
145+ parentFolderId = 0 ,
146+ isArchived = false ,
147+ eventTimestamp = 0
148+ )
149+ )
150+
151+ runBlocking {
152+ folders.forEach { folder ->
153+
154+ val childFolders = (foldersRepo.getChildFolders(
155+ idBasedDTO = IDBasedDTO (
156+ id = folder.id,
157+ correlation = Correlation (id = " " , clientName = " " ),
158+ eventTimestamp = 1527 ,
159+ )
160+ ) as Result .Success ).response
161+
162+ FolderComponent (
163+ showDivider = childFolders.isEmpty(),
164+ folder = folder,
165+ bottomSpacing = if (childFolders.isEmpty()) 12 else 8
166+ )
167+ if (childFolders.isNotEmpty()) {
168+ ChildFoldersComponent (foldersRepo = foldersRepo, folders = childFolders)
169+ Spacer (
170+ modifier = Modifier .height(8 .px)
171+ )
172+ Spacer (
173+ modifier = Modifier .fillMaxWidth(0.95 ).margin(start = 10 .px, end = 15 .px, bottom = 12 .px)
174+ .padding(end = 15 .px).height(0.75 .px).opacity(0.15 ).backgroundColor(Colors .outlineDark)
175+ .borderRadius(5 .px)
176+ )
177+ }
178+ }
179+ }
180+ }
181+
182+ }
183+ }
184+
185+ private suspend fun DIV.ChildFoldersComponent (
186+ marginStart : Int = 5, folders : List <Folder >, foldersRepo : FoldersRepo
187+ ) {
188+ folders.forEach {
189+ Row {
190+ Spacer (
191+ modifier = Modifier .width((marginStart - 2 ).px).backgroundColor(Colors .primaryContainerDark).opacity(
192+ 0.15
193+ )
194+ )
195+ Spacer (modifier = Modifier .width(5 .px))
196+ FolderComponent (showDivider = false , folder = it, bottomSpacing = 8 )
197+ }
198+ Spacer (modifier = Modifier .height(5 .px))
199+ val childFolders = (foldersRepo.getChildFolders(
200+ idBasedDTO = IDBasedDTO (
201+ id = it.id,
202+ correlation = Correlation (id = " " , clientName = " " ),
203+ eventTimestamp = 1527 ,
204+ )
205+ ) as Result .Success ).response
206+
207+ if (childFolders.isNotEmpty()) {
208+ Spacer (modifier = Modifier .height(5 .px))
209+ ChildFoldersComponent (
210+ marginStart = marginStart + 5 , foldersRepo = foldersRepo, folders = childFolders
211+ )
212+ }
213+ }
214+ }
215+
216+ private fun DIV.FolderComponent (
217+ folder : Folder , showDivider : Boolean = true, icon : String = "create_new_folder", bottomSpacing : Int = 12
218+ ) {
219+ Row (
220+ className = " folder-component" , horizontalAlignment = HorizontalAlignment .Center
221+ ) {
222+ span(classes = " material-icons-outlined" ) {
223+ id = " ${folder.name} -${folder.id} "
224+ style = Modifier .color(
225+ Colors .primaryDark
226+ ).cursor(Cursor .Pointer ).blockSelection().size(24 .px).toString()
227+ + icon
228+ }
229+ Row (
230+ id = folder.id.toString(),
231+ horizontalAlignment = HorizontalAlignment .Center ,
232+ modifier = Modifier .cursor(Cursor .Pointer )
233+ ) {
234+ Spacer (modifier = Modifier .width(8.5 .px))
235+ Text (
236+ text = folder.name,
237+ fontFamily = " Inter" ,
238+ fontWeight = FontWeight .Predefined .Normal ,
239+ fontSize = 16 .px,
240+ color = Colors .primaryDark,
241+ modifier = Modifier .blockSelection()
242+ )
243+ }
244+ }
245+ if (showDivider) {
246+ Spacer (
247+ modifier = Modifier .height(12 .px)
248+ )
249+
250+ Spacer (
251+ modifier = Modifier .fillMaxWidth(0.95 ).margin(start = 10 .px, end = 15 .px).padding(end = 15 .px)
252+ .height(0.75 .px).opacity(0.15 ).backgroundColor(Colors .outlineDark).borderRadius(5 .px)
253+ )
254+ }
255+ Spacer (
256+ modifier = Modifier .height(bottomSpacing.px)
257+ )
258+ }
259+
260+ private fun Modifier.blockSelection () = this .custom(" user-select: none;" )
0 commit comments