Skip to content

Commit e7b08f0

Browse files
committed
BackToTopButton.kt added and SiteFooter.kt updated.
1 parent 060fcab commit e7b08f0

7 files changed

Lines changed: 209 additions & 11 deletions

File tree

site/src/jsMain/kotlin/org/kotlang/portfolio/AppEntry.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package org.kotlang.portfolio
22

33
import androidx.compose.runtime.Composable
44
import androidx.compose.runtime.LaunchedEffect
5+
import com.varabyte.kobweb.compose.css.ScrollBehavior
56
import com.varabyte.kobweb.compose.ui.modifiers.fillMaxHeight
7+
import com.varabyte.kobweb.compose.ui.modifiers.scrollBehavior
68
import com.varabyte.kobweb.core.App
79
import com.varabyte.kobweb.silk.SilkApp
810
import com.varabyte.kobweb.silk.components.layout.Surface
@@ -20,7 +22,11 @@ fun AppEntry(content: @Composable () -> Unit) {
2022
colorMode.saveToLocalStorage()
2123
}
2224

23-
Surface(SmoothColorStyle.toModifier().fillMaxHeight()) {
25+
Surface(
26+
SmoothColorStyle.toModifier()
27+
.scrollBehavior(ScrollBehavior.Smooth)
28+
.fillMaxHeight()
29+
) {
2430
content()
2531
}
2632
}
Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
11
package org.kotlang.portfolio.components
22

33
import androidx.compose.runtime.Composable
4+
import com.varabyte.kobweb.compose.foundation.layout.Box
45
import com.varabyte.kobweb.compose.foundation.layout.Column
56
import com.varabyte.kobweb.compose.foundation.layout.ColumnScope
67
import com.varabyte.kobweb.compose.ui.Alignment
78
import com.varabyte.kobweb.compose.ui.Modifier
89
import com.varabyte.kobweb.compose.ui.modifiers.fillMaxSize
10+
import com.varabyte.kobweb.compose.ui.modifiers.fillMaxWidth
11+
import org.kotlang.portfolio.components.widgets.BackToTopButton
912

1013
@Composable
1114
fun PageLayout(
1215
header: @Composable () -> Unit,
1316
content: @Composable ColumnScope.() -> Unit
1417
) {
15-
Column(
16-
modifier = Modifier.fillMaxSize(),
17-
horizontalAlignment = Alignment.CenterHorizontally
18+
Box(
19+
modifier = Modifier.fillMaxSize()
1820
) {
19-
header()
20-
content()
21-
SiteFooter()
21+
Column(
22+
modifier = Modifier.fillMaxSize()
23+
) {
24+
header()
25+
Column(
26+
modifier = Modifier.fillMaxWidth().weight(1),
27+
horizontalAlignment = Alignment.CenterHorizontally
28+
) {
29+
content()
30+
}
31+
SiteFooter()
32+
}
33+
BackToTopButton()
2234
}
2335
}

site/src/jsMain/kotlin/org/kotlang/portfolio/components/SiteFooter.kt

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,60 @@ package org.kotlang.portfolio.components
22

33
import androidx.compose.runtime.Composable
44
import com.varabyte.kobweb.compose.foundation.layout.Box
5+
import com.varabyte.kobweb.compose.foundation.layout.Column
6+
import com.varabyte.kobweb.compose.foundation.layout.Row
57
import com.varabyte.kobweb.compose.ui.Alignment
68
import com.varabyte.kobweb.compose.ui.Modifier
9+
import com.varabyte.kobweb.compose.ui.modifiers.background
710
import com.varabyte.kobweb.compose.ui.modifiers.fillMaxWidth
8-
import com.varabyte.kobweb.compose.ui.modifiers.height
11+
import com.varabyte.kobweb.compose.ui.modifiers.gap
12+
import com.varabyte.kobweb.compose.ui.modifiers.padding
13+
import com.varabyte.kobweb.navigation.OpenLinkStrategy
14+
import com.varabyte.kobweb.silk.components.icons.fa.FaGithub
15+
import com.varabyte.kobweb.silk.components.navigation.Link
916
import com.varabyte.kobweb.silk.components.text.SpanText
17+
import com.varabyte.kobweb.silk.style.toModifier
18+
import com.varabyte.kobweb.silk.theme.colors.ColorMode
1019
import org.jetbrains.compose.web.css.px
20+
import org.kotlang.portfolio.theme.FooterTextStyle
21+
import org.kotlang.portfolio.theme.toPortfolioPalette
1122

1223
@Composable
1324
fun SiteFooter() {
25+
val palette = ColorMode.current.toPortfolioPalette()
1426
Box(
1527
modifier = Modifier
1628
.fillMaxWidth()
17-
.height(100.px),
29+
.background(palette.backgroundVariant)
30+
.padding(topBottom = 40.px),
1831
contentAlignment = Alignment.Center
1932
) {
20-
SpanText("© 2025 Mohammad Arif. All Rights Reserved.")
33+
Column(
34+
modifier = Modifier.gap(16.px),
35+
horizontalAlignment = Alignment.CenterHorizontally
36+
) {
37+
SpanText(
38+
text = "Copyright © 2025 Mohammad Arif. All rights reserved.",
39+
modifier = FooterTextStyle.toModifier()
40+
)
41+
Row(
42+
modifier = FooterTextStyle.toModifier().gap(4.px),
43+
verticalAlignment = Alignment.CenterVertically
44+
) {
45+
FaGithub()
46+
SpanText("This site is")
47+
Link(
48+
path = "https://github.com/kotlang-dev/PortfolioWebsite",
49+
text = "open source",
50+
openExternalLinksStrategy = OpenLinkStrategy.IN_NEW_TAB
51+
)
52+
SpanText("written using")
53+
Link(
54+
path = "https://kobweb.varabyte.com/",
55+
text = "Kobweb.",
56+
openExternalLinksStrategy = OpenLinkStrategy.IN_NEW_TAB
57+
)
58+
}
59+
}
2160
}
2261
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.kotlang.portfolio.components.widgets
2+
3+
import androidx.compose.runtime.*
4+
import com.varabyte.kobweb.compose.css.PointerEvents
5+
import com.varabyte.kobweb.compose.css.Visibility
6+
import com.varabyte.kobweb.compose.foundation.layout.Arrangement
7+
import com.varabyte.kobweb.compose.foundation.layout.Box
8+
import com.varabyte.kobweb.compose.foundation.layout.Column
9+
import com.varabyte.kobweb.compose.ui.Alignment
10+
import com.varabyte.kobweb.compose.ui.Modifier
11+
import com.varabyte.kobweb.compose.ui.modifiers.*
12+
import com.varabyte.kobweb.silk.components.icons.fa.FaArrowUp
13+
import com.varabyte.kobweb.silk.components.icons.fa.IconSize
14+
import com.varabyte.kobweb.silk.style.animation.toAnimation
15+
import com.varabyte.kobweb.silk.style.toModifier
16+
import kotlinx.browser.document
17+
import kotlinx.browser.window
18+
import org.jetbrains.compose.web.css.AnimationTimingFunction
19+
import org.jetbrains.compose.web.css.Position
20+
import org.jetbrains.compose.web.css.s
21+
import org.kotlang.portfolio.theme.BackToTopButtonStyle
22+
import org.kotlang.portfolio.theme.FadeInAnimation
23+
import org.w3c.dom.SMOOTH
24+
import org.w3c.dom.ScrollBehavior
25+
import org.w3c.dom.ScrollToOptions
26+
import org.w3c.dom.events.EventListener
27+
28+
@Composable
29+
fun BackToTopButton() {
30+
var scroll: Double? by remember { mutableStateOf(null) }
31+
32+
DisposableEffect(Unit) {
33+
val listener = EventListener {
34+
scroll = document.documentElement?.scrollTop
35+
}
36+
window.addEventListener(type = "scroll", callback = listener)
37+
onDispose {
38+
window.removeEventListener(type = "scroll", callback = listener)
39+
}
40+
}
41+
42+
val showButton = (scroll ?: 0.0) > 400.0
43+
44+
Column(
45+
modifier = Modifier
46+
.fillMaxSize()
47+
.position(Position.Fixed)
48+
.zIndex(1)
49+
.pointerEvents(PointerEvents.None),
50+
verticalArrangement = Arrangement.Bottom,
51+
horizontalAlignment = Alignment.End
52+
) {
53+
Box(
54+
modifier = BackToTopButtonStyle.toModifier()
55+
.visibility(if (showButton) Visibility.Visible else Visibility.Hidden)
56+
.onClick {
57+
document.documentElement?.scroll(
58+
ScrollToOptions(
59+
top = 0.0,
60+
behavior = ScrollBehavior.SMOOTH
61+
)
62+
)
63+
}
64+
.then(
65+
if (showButton) {
66+
Modifier.animation(
67+
FadeInAnimation.toAnimation(
68+
duration = 1.s,
69+
timingFunction = AnimationTimingFunction.EaseInOut
70+
)
71+
)
72+
} else {
73+
Modifier
74+
}
75+
),
76+
contentAlignment = Alignment.Center
77+
) {
78+
FaArrowUp(size = IconSize.LG)
79+
}
80+
}
81+
}

site/src/jsMain/kotlin/org/kotlang/portfolio/theme/AppStyles.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,24 @@ val ProfileImageStyle = CssStyle {
135135
scale(1.05)
136136
}
137137
}
138+
}
139+
140+
val FooterTextStyle = CssStyle {
141+
val palette = colorMode.toPortfolioPalette()
142+
base {
143+
Modifier
144+
.fontSize(14.px)
145+
.color(palette.text.toRgb().copyf(alpha = 0.7f))
146+
}
147+
148+
cssRule(" a") {
149+
Modifier
150+
.color(palette.primary)
151+
.textDecorationLine(TextDecorationLine.None)
152+
.transition(Transition.of("color", 200.ms))
153+
}
154+
155+
cssRule(" a:hover") {
156+
Modifier.textDecorationLine(TextDecorationLine.Underline)
157+
}
138158
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.kotlang.portfolio.theme
2+
3+
import com.varabyte.kobweb.compose.css.Cursor
4+
import com.varabyte.kobweb.compose.css.Transition
5+
import com.varabyte.kobweb.compose.ui.Modifier
6+
import com.varabyte.kobweb.compose.ui.modifiers.*
7+
import com.varabyte.kobweb.compose.ui.styleModifier
8+
import com.varabyte.kobweb.silk.style.CssStyle
9+
import com.varabyte.kobweb.silk.style.animation.Keyframes
10+
import com.varabyte.kobweb.silk.style.selectors.hover
11+
import org.jetbrains.compose.web.css.AnimationTimingFunction
12+
import org.jetbrains.compose.web.css.ms
13+
import org.jetbrains.compose.web.css.percent
14+
import org.jetbrains.compose.web.css.px
15+
16+
val BackToTopButtonStyle = CssStyle {
17+
val palette = colorMode.toPortfolioPalette()
18+
base {
19+
Modifier
20+
.size(50.px)
21+
.borderRadius(100.percent)
22+
.margin(right = 40.px, bottom = 40.px)
23+
.cursor(Cursor.Pointer)
24+
.styleModifier { property("pointer-events", "auto") }
25+
.transition(Transition.of("translate", 200.ms, AnimationTimingFunction.Ease))
26+
.backgroundColor(palette.background.inverted())
27+
.color(palette.background)
28+
}
29+
hover {
30+
Modifier.translateY((-10).px)
31+
}
32+
}
33+
34+
val FadeInAnimation = Keyframes {
35+
from { Modifier.opacity(0) }
36+
to { Modifier.opacity(1) }
37+
}

site/src/jsMain/kotlin/org/kotlang/portfolio/theme/PortfolioPalette.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import com.varabyte.kobweb.silk.theme.colors.ColorMode
99
// These are the semantic names for the color roles in our app.
1010
class PortfolioPalette(
1111
val background: Color,
12-
val surface: Color, // For slightly elevated surfaces
12+
val backgroundVariant: Color,
13+
val surface: Color,
1314
val header: Color,
1415
val primary: Color,
1516
val text: Color,
@@ -20,6 +21,7 @@ class PortfolioPalette(
2021
object PortfolioPalettes {
2122
val light = PortfolioPalette(
2223
background = Colors.WhiteSmoke, //Color.rgb(0xFFFFFF),
24+
backgroundVariant = Color.rgb(0xF1F1F1),
2325
surface = Color.rgb(0xF8F9FA),
2426
header = Colors.White.copyf(alpha = 0.85f),
2527
primary = Color.rgb(0x059669),
@@ -29,6 +31,7 @@ object PortfolioPalettes {
2931

3032
val dark = PortfolioPalette(
3133
background = Color.rgb(15, 15, 25), //Color.rgb(0x18181B),
34+
backgroundVariant = Color.rgb(0x0D0D0D),
3235
surface = Color.rgb(0x202023),
3336
header = Colors.Black.copyf(alpha = 0.85f),
3437
primary = Color.rgb(0x34D399),

0 commit comments

Comments
 (0)