tangled
alpha
login
or
join now
safwanyp.com
/
website
0
fork
atom
Code for my personal website
0
fork
atom
overview
issues
pulls
pipelines
chore: create home page
Safwan Parker
2 years ago
8ff186e8
9e6cdcd9
+152
-131
2 changed files
expand all
collapse all
unified
split
src
pages
index.astro
utils
index.ts
+138
-123
src/pages/index.astro
···
1
1
---
2
2
-
import Layout from '../layouts/Layout.astro';
3
3
-
import Card from '../components/Card.astro';
2
2
+
import { getCollection } from 'astro:content';
3
3
+
import Container from '@/components/Container.astro';
4
4
+
import PageLayout from '@/layouts/Layout.astro';
5
5
+
import ArrowCard from '@/components/NavCard.astro';
6
6
+
import Link from '@/components/Link.astro';
7
7
+
import { SITE, HOME, SOCIALS } from '@/config';
8
8
+
9
9
+
const blog = (await getCollection('blog'))
10
10
+
.filter((post) => !post.data.draft)
11
11
+
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
12
12
+
.slice(0, SITE.NUM_POSTS_ON_HOMEPAGE);
13
13
+
14
14
+
const projects = (await getCollection('projects'))
15
15
+
.filter((project) => !project.data.draft)
16
16
+
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
17
17
+
.slice(0, SITE.NUM_PROJECTS_ON_HOMEPAGE);
18
18
+
19
19
+
const allwork = (await getCollection('work'))
20
20
+
.sort(
21
21
+
(a, b) =>
22
22
+
new Date(b.data.dateStart).valueOf() -
23
23
+
new Date(a.data.dateStart).valueOf()
24
24
+
)
25
25
+
.slice(0, SITE.NUM_WORKS_ON_HOMEPAGE);
26
26
+
27
27
+
// const work = await Promise.all(
28
28
+
// allwork.map(async (item) => {
29
29
+
// const { Content } = await item.render();
30
30
+
// return { ...item, Content };
31
31
+
// })
32
32
+
// );
4
33
---
5
34
6
6
-
<Layout title='Welcome to Astro.'>
7
7
-
<main>
8
8
-
<svg
9
9
-
class='astro-a'
10
10
-
width='495'
11
11
-
height='623'
12
12
-
viewBox='0 0 495 623'
13
13
-
fill='none'
14
14
-
xmlns='http://www.w3.org/2000/svg'
15
15
-
aria-hidden='true'
16
16
-
>
17
17
-
<path
18
18
-
fill-rule='evenodd'
19
19
-
clip-rule='evenodd'
20
20
-
d='M167.19 364.254C83.4786 364.254 0 404.819 0 404.819C0 404.819 141.781 19.4876 142.087 18.7291C146.434 7.33701 153.027 0 162.289 0H332.441C341.703 0 348.574 7.33701 352.643 18.7291C352.92 19.5022 494.716 404.819 494.716 404.819C494.716 404.819 426.67 364.254 327.525 364.254L264.41 169.408C262.047 159.985 255.147 153.581 247.358 153.581C239.569 153.581 232.669 159.985 230.306 169.408L167.19 364.254ZM160.869 530.172C160.877 530.18 160.885 530.187 160.894 530.195L160.867 530.181C160.868 530.178 160.868 530.175 160.869 530.172ZM136.218 411.348C124.476 450.467 132.698 504.458 160.869 530.172C160.997 529.696 161.125 529.242 161.248 528.804C161.502 527.907 161.737 527.073 161.917 526.233C165.446 509.895 178.754 499.52 195.577 500.01C211.969 500.487 220.67 508.765 223.202 527.254C224.141 534.12 224.23 541.131 224.319 548.105C224.328 548.834 224.337 549.563 224.347 550.291C224.563 566.098 228.657 580.707 237.264 593.914C245.413 606.426 256.108 615.943 270.749 622.478C270.593 621.952 270.463 621.508 270.35 621.126C270.045 620.086 269.872 619.499 269.685 618.911C258.909 585.935 266.668 563.266 295.344 543.933C298.254 541.971 301.187 540.041 304.12 538.112C310.591 533.854 317.059 529.599 323.279 525.007C345.88 508.329 360.09 486.327 363.431 457.844C364.805 446.148 363.781 434.657 359.848 423.275C358.176 424.287 356.587 425.295 355.042 426.275C351.744 428.366 348.647 430.33 345.382 431.934C303.466 452.507 259.152 455.053 214.03 448.245C184.802 443.834 156.584 436.019 136.218 411.348Z'
21
21
-
fill='url(#paint0_linear_1805_24383)'></path>
22
22
-
<defs>
23
23
-
<linearGradient
24
24
-
id='paint0_linear_1805_24383'
25
25
-
x1='247.358'
26
26
-
y1='0'
27
27
-
x2='247.358'
28
28
-
y2='622.479'
29
29
-
gradientUnits='userSpaceOnUse'
30
30
-
>
31
31
-
<stop stop-opacity='0.9'></stop>
32
32
-
<stop offset='1' stop-opacity='0.2'></stop>
33
33
-
</linearGradient>
34
34
-
</defs>
35
35
-
</svg>
36
36
-
<h1>Welcome to <span class='text-gradient'>Astro</span></h1>
37
37
-
<p class='instructions'>
38
38
-
To get started, open the directory <code>src/pages</code> in your project.<br
39
39
-
/>
40
40
-
<strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
41
41
-
</p>
42
42
-
<ul role='list' class='link-card-grid'>
43
43
-
<Card
44
44
-
href='https://docs.astro.build/'
45
45
-
title='Documentation'
46
46
-
body='Learn how Astro works and explore the official API docs.'
47
47
-
/>
48
48
-
<Card
49
49
-
href='https://astro.build/integrations/'
50
50
-
title='Integrations'
51
51
-
body='Supercharge your project with new frameworks and libraries.'
52
52
-
/>
53
53
-
<Card
54
54
-
href='https://astro.build/themes/'
55
55
-
title='Themes'
56
56
-
body='Explore a galaxy of community-built starter themes.'
57
57
-
/>
58
58
-
<Card
59
59
-
href='https://astro.build/chat/'
60
60
-
title='Community'
61
61
-
body='Come say hi to our amazing Discord community. ❤️'
62
62
-
/>
63
63
-
</ul>
64
64
-
</main>
65
65
-
</Layout>
35
35
+
<PageLayout title={HOME.TITLE} description={HOME.DESCRIPTION}>
36
36
+
<Container>
37
37
+
<h4 class='animate font-semibold text-black dark:text-white'>
38
38
+
Hello, hej, namaste! <span class='text-xl'>👋🏻</span>
39
39
+
</h4>
40
40
+
<div class='space-y-16'>
41
41
+
<section>
42
42
+
<article class='space-y-4'>
43
43
+
<p class='animate'>
44
44
+
I only know so many ways to say hello, but I'm sure you get the
45
45
+
point. Welcome to my little corner of the internet!
46
46
+
</p>
47
47
+
<p class='animate'>
48
48
+
The name's Safwan. I'm a software engineer specializing in web
49
49
+
development. Frontend, backend, DevOps, you name it. I'm a fullstack
50
50
+
developer with a passion for building things that live on the
51
51
+
internet.
52
52
+
</p>
53
53
+
<p class='animate'>
54
54
+
This site is my digital "palace" (of sorts) where I share everything
55
55
+
I know about and learn. From blog posts to projects, to my work
56
56
+
experience, it's all here.
57
57
+
</p>
58
58
+
<p class='animate'>
59
59
+
This site's main purpose is for me to document my journey as a
60
60
+
developer and as a side benefit, share my knowledge with the world.
61
61
+
</p>
62
62
+
<p class='animate'>
63
63
+
This site has been in the works for a while now. I could never find
64
64
+
a design that I was satisfied with. Eventually, I looked at a crap
65
65
+
ton of personal websites to get inspiration and finally settled on
66
66
+
this design and I'm happy with it. Simple, yet pleasing 😌
67
67
+
</p>
68
68
+
</article>
69
69
+
</section>
70
70
+
71
71
+
<section class='animate space-y-6'>
72
72
+
<div class='flex flex-wrap gap-y-2 items-center justify-between'>
73
73
+
<h5 class='font-semibold text-black dark:text-white'>Latest posts</h5>
74
74
+
<Link href='/blog'> See all posts </Link>
75
75
+
</div>
76
76
+
<ul class='flex flex-col gap-4'>
77
77
+
{
78
78
+
blog.map((post) => (
79
79
+
<li>
80
80
+
<ArrowCard entry={post} />
81
81
+
</li>
82
82
+
))
83
83
+
}
84
84
+
</ul>
85
85
+
</section>
86
86
+
87
87
+
<section class='animate space-y-6'>
88
88
+
<div class='flex flex-wrap gap-y-2 items-center justify-between'>
89
89
+
<h5 class='font-semibold text-black dark:text-white'>
90
90
+
Recent projects
91
91
+
</h5>
92
92
+
<Link href='/projects'> See all projects </Link>
93
93
+
</div>
94
94
+
<ul class='flex flex-col gap-4'>
95
95
+
{
96
96
+
projects.map((project) => (
97
97
+
<li>
98
98
+
<ArrowCard entry={project} />
99
99
+
</li>
100
100
+
))
101
101
+
}
102
102
+
</ul>
103
103
+
</section>
66
104
67
67
-
<style>
68
68
-
main {
69
69
-
margin: auto;
70
70
-
padding: 1rem;
71
71
-
width: 800px;
72
72
-
max-width: calc(100% - 2rem);
73
73
-
color: white;
74
74
-
font-size: 20px;
75
75
-
line-height: 1.6;
76
76
-
}
77
77
-
.astro-a {
78
78
-
position: absolute;
79
79
-
top: -32px;
80
80
-
left: 50%;
81
81
-
transform: translatex(-50%);
82
82
-
width: 220px;
83
83
-
height: auto;
84
84
-
z-index: -1;
85
85
-
}
86
86
-
h1 {
87
87
-
font-size: 4rem;
88
88
-
font-weight: 700;
89
89
-
line-height: 1;
90
90
-
text-align: center;
91
91
-
margin-bottom: 1em;
92
92
-
}
93
93
-
.text-gradient {
94
94
-
background-image: var(--accent-gradient);
95
95
-
-webkit-background-clip: text;
96
96
-
-webkit-text-fill-color: transparent;
97
97
-
background-size: 400%;
98
98
-
background-position: 0%;
99
99
-
}
100
100
-
.instructions {
101
101
-
margin-bottom: 2rem;
102
102
-
border: 1px solid rgba(var(--accent-light), 25%);
103
103
-
background: linear-gradient(
104
104
-
rgba(var(--accent-dark), 66%),
105
105
-
rgba(var(--accent-dark), 33%)
106
106
-
);
107
107
-
padding: 1.5rem;
108
108
-
border-radius: 8px;
109
109
-
}
110
110
-
.instructions code {
111
111
-
font-size: 0.8em;
112
112
-
font-weight: bold;
113
113
-
background: rgba(var(--accent-light), 12%);
114
114
-
color: rgb(var(--accent-light));
115
115
-
border-radius: 4px;
116
116
-
padding: 0.3em 0.4em;
117
117
-
}
118
118
-
.instructions strong {
119
119
-
color: rgb(var(--accent-light));
120
120
-
}
121
121
-
.link-card-grid {
122
122
-
display: grid;
123
123
-
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
124
124
-
gap: 2rem;
125
125
-
padding: 0;
126
126
-
}
127
127
-
</style>
105
105
+
<section class='animate space-y-4'>
106
106
+
<h5 class='font-semibold text-black dark:text-white'>Let's Connect</h5>
107
107
+
<article>
108
108
+
<p>
109
109
+
If you want to connect with me for whatever reason - be it a
110
110
+
collaboration, a project, or just to say hi - feel free to reach out
111
111
+
to me on any of the following platforms. I'm always open to new
112
112
+
opportunities and meeting new people. So don't be shy! 🙃
113
113
+
</p>
114
114
+
</article>
115
115
+
<ul class='flex flex-wrap gap-2'>
116
116
+
{
117
117
+
SOCIALS.map((SOCIAL) => (
118
118
+
<li class='flex gap-x-2 text-nowrap'>
119
119
+
<Link
120
120
+
href={SOCIAL.HREF}
121
121
+
external
122
122
+
aria-label={`${SITE.NAME} on ${SOCIAL.NAME}`}
123
123
+
>
124
124
+
{SOCIAL.NAME}
125
125
+
</Link>
126
126
+
{'/'}
127
127
+
</li>
128
128
+
))
129
129
+
}
130
130
+
<li class='line-clamp-1'>
131
131
+
<Link
132
132
+
href={`mailto:${SITE.EMAIL}`}
133
133
+
aria-label={`Email ${SITE.NAME}`}
134
134
+
>
135
135
+
{SITE.EMAIL}
136
136
+
</Link>
137
137
+
</li>
138
138
+
</ul>
139
139
+
</section>
140
140
+
</div>
141
141
+
</Container>
142
142
+
</PageLayout>
+14
-8
src/utils/index.ts
···
27
27
};
28
28
29
29
const dateRange: DateRange = (startDate, endDate) => {
30
30
-
const startMonth = startDate.toLocaleString('default', { month: 'short' });
31
31
-
const startYear = startDate.getFullYear().toString();
30
30
+
const startDateObj = new Date(startDate);
31
31
+
const endDateObj = endDate ? new Date(endDate) : null;
32
32
+
33
33
+
const startMonth = startDateObj.toLocaleString('default', { month: 'short' });
34
34
+
const startYear = startDateObj.getFullYear().toString();
32
35
let endMonth;
33
36
let endYear;
34
37
35
35
-
if (endDate) {
36
36
-
if (typeof endDate === 'string') {
38
38
+
if (endDateObj) {
39
39
+
if (typeof endDateObj === 'string') {
37
40
endMonth = '';
38
38
-
endYear = endDate;
41
41
+
endYear = endDateObj;
39
42
} else {
40
40
-
endMonth = endDate.toLocaleString('default', { month: 'short' });
41
41
-
endYear = endDate.getFullYear().toString();
43
43
+
endMonth = endDateObj.toLocaleString('default', { month: 'short' });
44
44
+
endYear = endDateObj.getFullYear().toString();
42
45
}
46
46
+
} else {
47
47
+
endMonth = 'Present';
48
48
+
endYear = '';
43
49
}
44
50
45
45
-
return `${startMonth}${startYear} - ${endMonth}${endYear}`;
51
51
+
return `${startMonth} ${startYear} - ${endMonth} ${endYear}`;
46
52
};
47
53
48
54
export { combineClassNames, formatDate, readingTime, dateRange };