Skip to content

Commit 4457c40

Browse files
committed
feat: Implement project card
1 parent 5a79bbe commit 4457c40

File tree

8 files changed

+356
-17
lines changed

8 files changed

+356
-17
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="960"
5+
android:viewportHeight="960">
6+
<path
7+
android:pathData="M480,691 L314,791q-11,7 -23,6t-21,-8q-9,-7 -14,-17.5t-2,-23.5l44,-189 -147,-127q-10,-9 -12.5,-20.5T140,389q4,-11 12,-18t22,-9l194,-17 75,-178q5,-12 15.5,-18t21.5,-6q11,0 21.5,6t15.5,18l75,178 194,17q14,2 22,9t12,18q4,11 1.5,22.5T809,432L662,559l44,189q3,13 -2,23.5T690,789q-9,7 -21,8t-23,-6L480,691Z"
8+
android:fillColor="#e3e3e3"/>
9+
</vector>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fun AppScreen(modifier: Modifier = Modifier) {
4444
listOf(
4545
Experience(
4646
start = "May",
47-
end = "June 2022",
47+
end = "June 2025",
4848
position = "Research Asst. (Android Dev)",
4949
description = "Created an Android app for collecting and compiling a validation dataset for a binary image classification model from scratch. Generated output from the model on-device for a fast, offline experience. Designed an intuitive UI, with options for viewing and editing entries in the dataset. Optimized the UX: the validation dataset can be exported to the device with the click of a button.",
5050
company = "AIIMS Guwahati",

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,27 @@ fun ExperienceCard(
6565
color = colorScheme.onSurfaceVariant,
6666
modifier = Modifier.padding(top = 8.dp)
6767
)
68-
FlowRow(
69-
horizontalArrangement = Arrangement.spacedBy(6.dp),
70-
verticalArrangement = Arrangement.spacedBy(4.dp),
71-
modifier = Modifier.padding(top = 16.dp)
72-
) {
73-
experience.skills.fastForEach {
74-
Box(Modifier.clip(CircleShape).background(colorScheme.primaryContainer)) {
75-
Text(
76-
it,
77-
style = typography.labelMedium,
78-
color = colorScheme.onPrimaryContainer,
79-
modifier = Modifier.padding(vertical = 4.dp, horizontal = 12.dp)
80-
)
81-
}
82-
}
83-
}
68+
LabelRow(experience.skills, Modifier.padding(top = 16.dp))
69+
}
70+
}
71+
}
72+
}
73+
74+
@Composable
75+
fun LabelRow(list: List<String>, modifier: Modifier = Modifier) {
76+
FlowRow(
77+
horizontalArrangement = Arrangement.spacedBy(8.dp),
78+
verticalArrangement = Arrangement.spacedBy(8.dp),
79+
modifier = modifier
80+
) {
81+
list.fastForEach {
82+
Box(Modifier.clip(CircleShape).background(colorScheme.secondaryContainer)) {
83+
Text(
84+
it,
85+
style = typography.labelMedium,
86+
color = colorScheme.onSecondaryContainer,
87+
modifier = Modifier.padding(vertical = 6.dp, horizontal = 12.dp)
88+
)
8489
}
8590
}
8691
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package org.nsh07.nsh07.ui
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.*
5+
import androidx.compose.material3.Icon
6+
import androidx.compose.material3.MaterialTheme.colorScheme
7+
import androidx.compose.material3.MaterialTheme.shapes
8+
import androidx.compose.material3.MaterialTheme.typography
9+
import androidx.compose.material3.Text
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.ui.Alignment
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.draw.clip
14+
import androidx.compose.ui.layout.ContentScale
15+
import androidx.compose.ui.platform.LocalUriHandler
16+
import androidx.compose.ui.text.font.FontWeight
17+
import androidx.compose.ui.unit.Dp
18+
import androidx.compose.ui.unit.dp
19+
import coil3.compose.SubcomposeAsyncImage
20+
import nsh07.composeapp.generated.resources.Res
21+
import nsh07.composeapp.generated.resources.open_in_browser
22+
import nsh07.composeapp.generated.resources.star
23+
import org.jetbrains.compose.resources.painterResource
24+
import org.nsh07.nsh07.ui.network.Repo
25+
26+
@Composable
27+
fun ProjectCard(
28+
project: Repo,
29+
cardPadding: Dp,
30+
projectImageUri: String,
31+
projectDescription: String,
32+
modifier: Modifier = Modifier
33+
) {
34+
val colorScheme = colorScheme
35+
val uriHandler = LocalUriHandler.current
36+
37+
Box(
38+
modifier
39+
.clip(shapes.large)
40+
.clickable { uriHandler.openUri(project.htmlUrl) }
41+
) {
42+
Row(Modifier.fillMaxWidth().padding(cardPadding)) {
43+
SubcomposeAsyncImage(
44+
model = projectImageUri,
45+
contentDescription = null,
46+
contentScale = ContentScale.Crop,
47+
modifier = Modifier.weight(1f)
48+
)
49+
Column(Modifier.weight(3f)) {
50+
FlowRow(itemVerticalAlignment = Alignment.CenterVertically) {
51+
Text(project.name, style = typography.bodyLarge, fontWeight = FontWeight.Medium)
52+
Icon(
53+
painterResource(Res.drawable.open_in_browser),
54+
null,
55+
modifier = Modifier.padding(start = 4.dp).size(16.dp)
56+
)
57+
}
58+
Text(
59+
projectDescription,
60+
style = typography.bodyMedium,
61+
color = colorScheme.onSurfaceVariant,
62+
modifier = Modifier.padding(top = 8.dp)
63+
)
64+
Row(
65+
verticalAlignment = Alignment.CenterVertically,
66+
horizontalArrangement = Arrangement.spacedBy(4.dp),
67+
modifier = Modifier.padding(top = 8.dp)
68+
) {
69+
Icon(
70+
painterResource(Res.drawable.star),
71+
null
72+
)
73+
Text(project.stargazersCount.toString(), style = typography.labelLarge)
74+
}
75+
LabelRow(project.topics, Modifier.padding(top = 16.dp))
76+
}
77+
}
78+
}
79+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.nsh07.nsh07.ui.network
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class License(
8+
@SerialName("key")
9+
val key: String,
10+
@SerialName("name")
11+
val name: String,
12+
@SerialName("node_id")
13+
val nodeId: String,
14+
@SerialName("spdx_id")
15+
val spdxId: String,
16+
@SerialName("url")
17+
val url: String
18+
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.nsh07.nsh07.ui.network
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class Owner(
8+
@SerialName("avatar_url")
9+
val avatarUrl: String,
10+
@SerialName("events_url")
11+
val eventsUrl: String,
12+
@SerialName("followers_url")
13+
val followersUrl: String,
14+
@SerialName("following_url")
15+
val followingUrl: String,
16+
@SerialName("gists_url")
17+
val gistsUrl: String,
18+
@SerialName("gravatar_id")
19+
val gravatarId: String,
20+
@SerialName("html_url")
21+
val htmlUrl: String,
22+
@SerialName("id")
23+
val id: Int,
24+
@SerialName("login")
25+
val login: String,
26+
@SerialName("node_id")
27+
val nodeId: String,
28+
@SerialName("organizations_url")
29+
val organizationsUrl: String,
30+
@SerialName("received_events_url")
31+
val receivedEventsUrl: String,
32+
@SerialName("repos_url")
33+
val reposUrl: String,
34+
@SerialName("site_admin")
35+
val siteAdmin: Boolean,
36+
@SerialName("starred_url")
37+
val starredUrl: String,
38+
@SerialName("subscriptions_url")
39+
val subscriptionsUrl: String,
40+
@SerialName("type")
41+
val type: String,
42+
@SerialName("url")
43+
val url: String,
44+
@SerialName("user_view_type")
45+
val userViewType: String
46+
)
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package org.nsh07.nsh07.ui.network
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class Repo(
8+
@SerialName("allow_forking")
9+
val allowForking: Boolean,
10+
@SerialName("archive_url")
11+
val archiveUrl: String,
12+
@SerialName("archived")
13+
val archived: Boolean,
14+
@SerialName("assignees_url")
15+
val assigneesUrl: String,
16+
@SerialName("blobs_url")
17+
val blobsUrl: String,
18+
@SerialName("branches_url")
19+
val branchesUrl: String,
20+
@SerialName("clone_url")
21+
val cloneUrl: String,
22+
@SerialName("collaborators_url")
23+
val collaboratorsUrl: String,
24+
@SerialName("comments_url")
25+
val commentsUrl: String,
26+
@SerialName("commits_url")
27+
val commitsUrl: String,
28+
@SerialName("compare_url")
29+
val compareUrl: String,
30+
@SerialName("contents_url")
31+
val contentsUrl: String,
32+
@SerialName("contributors_url")
33+
val contributorsUrl: String,
34+
@SerialName("created_at")
35+
val createdAt: String,
36+
@SerialName("default_branch")
37+
val defaultBranch: String,
38+
@SerialName("deployments_url")
39+
val deploymentsUrl: String,
40+
@SerialName("description")
41+
val description: String,
42+
@SerialName("disabled")
43+
val disabled: Boolean,
44+
@SerialName("downloads_url")
45+
val downloadsUrl: String,
46+
@SerialName("events_url")
47+
val eventsUrl: String,
48+
@SerialName("fork")
49+
val fork: Boolean,
50+
@SerialName("forks")
51+
val forks: Int,
52+
@SerialName("forks_count")
53+
val forksCount: Int,
54+
@SerialName("forks_url")
55+
val forksUrl: String,
56+
@SerialName("full_name")
57+
val fullName: String,
58+
@SerialName("git_commits_url")
59+
val gitCommitsUrl: String,
60+
@SerialName("git_refs_url")
61+
val gitRefsUrl: String,
62+
@SerialName("git_tags_url")
63+
val gitTagsUrl: String,
64+
@SerialName("git_url")
65+
val gitUrl: String,
66+
@SerialName("has_discussions")
67+
val hasDiscussions: Boolean,
68+
@SerialName("has_downloads")
69+
val hasDownloads: Boolean,
70+
@SerialName("has_issues")
71+
val hasIssues: Boolean,
72+
@SerialName("has_pages")
73+
val hasPages: Boolean,
74+
@SerialName("has_projects")
75+
val hasProjects: Boolean,
76+
@SerialName("has_wiki")
77+
val hasWiki: Boolean,
78+
@SerialName("homepage")
79+
val homepage: String,
80+
@SerialName("hooks_url")
81+
val hooksUrl: String,
82+
@SerialName("html_url")
83+
val htmlUrl: String,
84+
@SerialName("id")
85+
val id: Int,
86+
@SerialName("is_template")
87+
val isTemplate: Boolean,
88+
@SerialName("issue_comment_url")
89+
val issueCommentUrl: String,
90+
@SerialName("issue_events_url")
91+
val issueEventsUrl: String,
92+
@SerialName("issues_url")
93+
val issuesUrl: String,
94+
@SerialName("keys_url")
95+
val keysUrl: String,
96+
@SerialName("labels_url")
97+
val labelsUrl: String,
98+
@SerialName("language")
99+
val language: String,
100+
@SerialName("languages_url")
101+
val languagesUrl: String,
102+
@SerialName("license")
103+
val license: License?,
104+
@SerialName("merges_url")
105+
val mergesUrl: String,
106+
@SerialName("milestones_url")
107+
val milestonesUrl: String,
108+
@SerialName("mirror_url")
109+
val mirrorUrl: Any?,
110+
@SerialName("name")
111+
val name: String,
112+
@SerialName("node_id")
113+
val nodeId: String,
114+
@SerialName("notifications_url")
115+
val notificationsUrl: String,
116+
@SerialName("open_issues")
117+
val openIssues: Int,
118+
@SerialName("open_issues_count")
119+
val openIssuesCount: Int,
120+
@SerialName("owner")
121+
val owner: Owner,
122+
@SerialName("private")
123+
val `private`: Boolean,
124+
@SerialName("pulls_url")
125+
val pullsUrl: String,
126+
@SerialName("pushed_at")
127+
val pushedAt: String,
128+
@SerialName("releases_url")
129+
val releasesUrl: String,
130+
@SerialName("score")
131+
val score: Double,
132+
@SerialName("size")
133+
val size: Int,
134+
@SerialName("ssh_url")
135+
val sshUrl: String,
136+
@SerialName("stargazers_count")
137+
val stargazersCount: Int,
138+
@SerialName("stargazers_url")
139+
val stargazersUrl: String,
140+
@SerialName("statuses_url")
141+
val statusesUrl: String,
142+
@SerialName("subscribers_url")
143+
val subscribersUrl: String,
144+
@SerialName("subscription_url")
145+
val subscriptionUrl: String,
146+
@SerialName("svn_url")
147+
val svnUrl: String,
148+
@SerialName("tags_url")
149+
val tagsUrl: String,
150+
@SerialName("teams_url")
151+
val teamsUrl: String,
152+
@SerialName("topics")
153+
val topics: List<String>,
154+
@SerialName("trees_url")
155+
val treesUrl: String,
156+
@SerialName("updated_at")
157+
val updatedAt: String,
158+
@SerialName("url")
159+
val url: String,
160+
@SerialName("visibility")
161+
val visibility: String,
162+
@SerialName("watchers")
163+
val watchers: Int,
164+
@SerialName("watchers_count")
165+
val watchersCount: Int,
166+
@SerialName("web_commit_signoff_required")
167+
val webCommitSignoffRequired: Boolean
168+
)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.nsh07.nsh07.ui.network
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class TopRepos(
8+
@SerialName("incomplete_results")
9+
val incompleteResults: Boolean,
10+
@SerialName("items")
11+
val repos: List<Repo>,
12+
@SerialName("total_count")
13+
val totalCount: Int
14+
)

0 commit comments

Comments
 (0)