Skip to content

Commit f661774

Browse files
committed
feat: make site responsive
1 parent f23e4de commit f661774

File tree

5 files changed

+153
-68
lines changed

5 files changed

+153
-68
lines changed

composeApp/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ kotlin {
3636
implementation(compose.runtime)
3737
implementation(compose.foundation)
3838
implementation(compose.material3)
39-
implementation(libs.compose.material3.windowsizeclass)
39+
implementation(libs.compose.material3.adaptive)
4040
implementation(libs.coil.kt)
4141
implementation(libs.coil.kt.ktor)
4242
implementation(compose.ui)

composeApp/src/wasmJsMain/kotlin/org/nsh07/nsh07/ui/AppScreen.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package org.nsh07.nsh07.ui
22

3-
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
43
import androidx.compose.runtime.Composable
54
import androidx.compose.runtime.collectAsState
65
import androidx.compose.runtime.getValue
76
import androidx.compose.ui.Modifier
87
import androidx.lifecycle.viewmodel.compose.viewModel
98
import org.nsh07.nsh07.ui.homeScreen.AppHomeScreen
109

11-
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
1210
@Composable
1311
fun AppScreen(
1412
viewModel: UiViewModel = viewModel(factory = UiViewModel.Factory),
Lines changed: 135 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
11
package org.nsh07.nsh07.ui.homeScreen
22

3+
import androidx.compose.animation.*
34
import androidx.compose.foundation.layout.*
45
import androidx.compose.foundation.lazy.LazyColumn
56
import androidx.compose.foundation.lazy.rememberLazyListState
67
import androidx.compose.foundation.rememberScrollState
78
import androidx.compose.foundation.verticalScroll
8-
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
9+
import androidx.compose.material3.*
10+
import androidx.compose.material3.MaterialTheme.motionScheme
911
import androidx.compose.material3.MaterialTheme.typography
10-
import androidx.compose.material3.Text
12+
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
1113
import androidx.compose.runtime.*
1214
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.platform.LocalLayoutDirection
1316
import androidx.compose.ui.platform.LocalUriHandler
1417
import androidx.compose.ui.unit.dp
18+
import androidx.window.core.layout.WindowSizeClass
1519
import kotlinx.coroutines.launch
1620

17-
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
21+
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
1822
@Composable
1923
fun AppHomeScreen(
2024
projectState: ProjectsState,
2125
modifier: Modifier = Modifier
2226
) {
2327
val uriHandler = LocalUriHandler.current
2428
val scope = rememberCoroutineScope()
29+
val motionScheme = motionScheme
2530

2631
val listState = rememberLazyListState()
2732
val firstVisibleItem by derivedStateOf { listState.firstVisibleItemIndex }
33+
val scrolledUp by derivedStateOf { listState.lastScrolledForward }
2834

2935
val paragraphs = remember {
3036
listOf(
@@ -40,7 +46,7 @@ fun AppHomeScreen(
4046
start = "Aug 2025",
4147
end = "Present",
4248
position = "Open Source Lead",
43-
description = "Perform the role of Open Source Lead of the Development Club. Helped successfully organise OPCODE (Open Source Fest) 2025.",
49+
description = "Perform the role of Open Source Lead of the Development Club. Successfully organised OPCODE (Open Source Fest) 2025, while also contributing a project.",
4450
company = "DevC, IIIT Bhagalpur",
4551
companyUrl = "https://gymkhana.iiitbh.ac.in/technical/",
4652
skills = listOf()
@@ -60,63 +66,137 @@ fun AppHomeScreen(
6066

6167
val cardPadding = remember { 16.dp }
6268

63-
Row(
64-
modifier = Modifier
65-
.padding(horizontal = 48.dp)
66-
.widthIn(max = 1200.dp)
67-
.then(modifier)
68-
) {
69-
Column(Modifier.padding(vertical = 96.dp).weight(1f)) {
70-
Column(Modifier.verticalScroll(rememberScrollState())) {
71-
NameAndDesc()
69+
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
7270

73-
Spacer(Modifier.height(72.dp))
71+
if (windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND)) {
72+
Row(
73+
modifier = Modifier
74+
.padding(horizontal = 48.dp)
75+
.widthIn(max = 1200.dp)
76+
.then(modifier)
77+
) {
78+
Column(Modifier.padding(vertical = 96.dp).weight(1f)) {
79+
Column(Modifier.verticalScroll(rememberScrollState())) {
80+
NameAndDesc()
7481

75-
NavigationItem(
76-
selected = firstVisibleItem < paragraphCount + 1,
77-
onClick = {
78-
scope.launch { listState.animateScrollToItem(0) }
79-
},
80-
label = { Text("About", style = typography.bodyMedium) },
81-
modifier = Modifier.offset(x = (-20).dp)
82-
)
83-
NavigationItem(
84-
selected = firstVisibleItem in paragraphCount + 1..<paragraphCount + experienceCount + 2,
85-
onClick = {
86-
scope.launch { listState.animateScrollToItem(paragraphCount + 1) }
87-
},
88-
label = { Text("Experience", style = typography.bodyMedium) },
89-
modifier = Modifier.offset(x = (-20).dp)
90-
)
91-
NavigationItem(
92-
selected = firstVisibleItem >= paragraphCount + experienceCount + 2,
93-
onClick = {
94-
scope.launch { listState.animateScrollToItem(paragraphCount + experienceCount + 2) }
95-
},
96-
label = { Text("Projects", style = typography.bodyMedium) },
97-
modifier = Modifier.offset(x = (-20).dp)
98-
)
82+
Spacer(Modifier.height(72.dp))
9983

100-
Spacer(Modifier.height(32.dp))
101-
}
84+
NavigationItem(
85+
selected = firstVisibleItem < paragraphCount + 1,
86+
onClick = {
87+
scope.launch { listState.animateScrollToItem(0) }
88+
},
89+
label = { Text("About", style = typography.bodyMedium) },
90+
modifier = Modifier.offset(x = (-20).dp)
91+
)
92+
NavigationItem(
93+
selected = firstVisibleItem in paragraphCount + 1..<paragraphCount + experienceCount + 2,
94+
onClick = {
95+
scope.launch { listState.animateScrollToItem(paragraphCount + 1) }
96+
},
97+
label = { Text("Experience", style = typography.bodyMedium) },
98+
modifier = Modifier.offset(x = (-20).dp)
99+
)
100+
NavigationItem(
101+
selected = firstVisibleItem >= paragraphCount + experienceCount + 2,
102+
onClick = {
103+
scope.launch { listState.animateScrollToItem(paragraphCount + experienceCount + 2) }
104+
},
105+
label = { Text("Projects", style = typography.bodyMedium) },
106+
modifier = Modifier.offset(x = (-20).dp)
107+
)
102108

103-
Spacer(Modifier.weight(1f))
109+
Spacer(Modifier.height(32.dp))
110+
}
104111

105-
SocialIcons()
106-
}
112+
Spacer(Modifier.weight(1f))
107113

108-
LazyColumn(
109-
state = listState,
110-
contentPadding = PaddingValues(vertical = 96.dp),
111-
modifier = Modifier.fillMaxHeight().weight(1.1f)
112-
) {
113-
mainContent(
114-
paragraphs,
115-
experiences,
116-
projectState,
117-
cardPadding,
118-
uriHandler
119-
)
114+
SocialIcons()
115+
}
116+
117+
LazyColumn(
118+
state = listState,
119+
contentPadding = PaddingValues(vertical = 96.dp),
120+
modifier = Modifier.fillMaxHeight().weight(1.1f)
121+
) {
122+
mainContent(
123+
paragraphs,
124+
experiences,
125+
projectState,
126+
cardPadding,
127+
uriHandler
128+
)
129+
}
130+
}
131+
} else {
132+
Scaffold(
133+
topBar = {
134+
AnimatedVisibility(
135+
firstVisibleItem > 1,
136+
enter = slideInVertically(motionScheme.defaultSpatialSpec(), initialOffsetY = { -it }),
137+
exit = slideOutVertically(motionScheme.defaultSpatialSpec(), targetOffsetY = { -it })
138+
) {
139+
val topBarContent = when (firstVisibleItem) {
140+
in paragraphCount + 2..<paragraphCount + experienceCount + 3 -> 1
141+
in paragraphCount + experienceCount + 3..1000 -> 2
142+
else -> 0
143+
}
144+
TopAppBar(
145+
title = {
146+
AnimatedContent(
147+
topBarContent,
148+
transitionSpec = {
149+
slideInVertically(
150+
animationSpec = motionScheme.fastSpatialSpec(),
151+
initialOffsetY = {
152+
if (scrolledUp) (it * 1.25).toInt() else (-it * 1.25).toInt()
153+
}
154+
).togetherWith(
155+
slideOutVertically(
156+
animationSpec = motionScheme.fastSpatialSpec(),
157+
targetOffsetY = {
158+
if (scrolledUp) (-it * 1.25).toInt() else (it * 1.25).toInt()
159+
}
160+
)
161+
)
162+
},
163+
modifier = Modifier.width(200.dp).padding(start = 8.dp)
164+
) {
165+
when (it) {
166+
1 -> Text("Experience")
167+
2 -> Text("Projects")
168+
else -> Text("About")
169+
}
170+
}
171+
}
172+
)
173+
}
174+
}
175+
) { innerPadding ->
176+
val layoutDirection = LocalLayoutDirection.current
177+
LazyColumn(
178+
state = listState,
179+
contentPadding = PaddingValues(
180+
top = 48.dp,
181+
start = innerPadding.calculateStartPadding(layoutDirection),
182+
end = innerPadding.calculateEndPadding(layoutDirection),
183+
bottom = 48.dp
184+
),
185+
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)
186+
) {
187+
item { NameAndDesc(horizontalPadding = 16.dp) }
188+
item {
189+
SocialIcons(Modifier.padding(top = 32.dp, start = 12.dp, end = 12.dp))
190+
Spacer(Modifier.height(96.dp))
191+
}
192+
mainContent(
193+
paragraphs,
194+
experiences,
195+
projectState,
196+
cardPadding,
197+
uriHandler
198+
)
199+
}
120200
}
121201
}
122202
}

composeApp/src/wasmJsMain/kotlin/org/nsh07/nsh07/ui/homeScreen/HomeScreenContent.kt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,36 @@ import nsh07.composeapp.generated.resources.*
2121
import org.jetbrains.compose.resources.painterResource
2222

2323
@Composable
24-
fun NameAndDesc() {
24+
fun NameAndDesc(horizontalPadding: Dp = 0.dp) {
2525
Text(
2626
"Nishant Mishra",
2727
style = typography.displayLarge.copy(fontSize = 48.sp),
28-
color = colorScheme.onSurface
28+
color = colorScheme.onSurface,
29+
modifier = Modifier.padding(horizontal = horizontalPadding)
2930
)
3031
Spacer(Modifier.height(4.dp))
3132
Text(
3233
"App developer",
3334
style = typography.titleLarge,
34-
color = colorScheme.onSurface
35+
color = colorScheme.onSurface,
36+
modifier = Modifier.padding(horizontal = horizontalPadding)
3537
)
3638
Spacer(Modifier.height(20.dp))
3739
Text(
3840
"I build performant, beautiful apps for mobile and desktop.",
3941
style = typography.bodyLarge,
4042
color = colorScheme.onSurfaceVariant,
41-
modifier = Modifier.widthIn(max = 320.dp)
43+
modifier = Modifier.widthIn(max = 320.dp).padding(horizontal = horizontalPadding)
4244
)
4345
}
4446

4547
@Composable
46-
fun SocialIcons() {
48+
fun SocialIcons(modifier: Modifier = Modifier) {
4749
val uriHandler = LocalUriHandler.current
48-
Row(verticalAlignment = Alignment.CenterVertically) {
50+
Row(
51+
verticalAlignment = Alignment.CenterVertically,
52+
modifier = modifier
53+
) {
4954
IconButton(onClick = { uriHandler.openUri("https://github.com/nsh07") }) {
5055
Icon(
5156
painterResource(Res.drawable.github),
@@ -151,8 +156,8 @@ fun LazyListScope.mainContent(
151156
}
152157
item("tech stack spacer") { Spacer(Modifier.height(112.dp)) }
153158
item("tech stack") {
154-
Row(
155-
verticalAlignment = Alignment.CenterVertically,
159+
FlowRow(
160+
itemVerticalAlignment = Alignment.CenterVertically,
156161
modifier = Modifier.padding(horizontal = cardPadding)
157162
) {
158163
Text(
@@ -175,7 +180,8 @@ fun LazyListScope.mainContent(
175180
null,
176181
modifier = Modifier.clickable { uriHandler.openUri("https://www.jetbrains.com/compose-multiplatform/") }
177182
)
178-
Text(" in Kotlin. Deployed with ", style = typography.bodyMedium, color = colorScheme.outline)
183+
Text(" in Kotlin. ", style = typography.bodyMedium, color = colorScheme.outline)
184+
Text("Deployed with ", style = typography.bodyMedium, color = colorScheme.outline)
179185
Icon(
180186
painterResource(Res.drawable.githubpages),
181187
null,

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ composeMultiplatform = "1.10.0-alpha02"
55
kotlin = "2.2.20"
66
ksp = "2.2.20-2.0.4"
77
ktor = "3.3.1"
8+
material3-adaptive = "1.2.0-alpha07"
89

910
[libraries]
1011
androidx-lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
1112
androidx-lifecycle-viewmodelCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
1213
coil-kt = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil3" }
1314
coil-kt-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil3" }
14-
compose-material3-windowsizeclass = { module = "org.jetbrains.compose.material3:material3-window-size-class", version.ref = "composeMultiplatform" }
15+
compose-material3-adaptive = { module = "org.jetbrains.compose.material3.adaptive:adaptive", version.ref = "material3-adaptive" }
1516
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
1617
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
1718
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }

0 commit comments

Comments
 (0)