mirror of
https://github.com/soconnor0919/personal-website.git
synced 2025-12-12 23:04:43 -05:00
Enhance layout and project components; improve accessibility and content
- Added BreadcrumbWrapper to the layout for better navigation. - Updated ProjectsPage to include CardFooter with conditional rendering for project links. - Improved image alt text for better accessibility in travel and project sections. - Added new project details and alt text in data.ts for enhanced content clarity.
This commit is contained in:
83
SP25-Cumulative Website.md
Normal file
83
SP25-Cumulative Website.md
Normal file
File diff suppressed because one or more lines are too long
BIN
public/latex-thumbnail.jpg
Normal file
BIN
public/latex-thumbnail.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
BIN
public/videos/latex-intro.mp4
Normal file
BIN
public/videos/latex-intro.mp4
Normal file
Binary file not shown.
472
public/videos/latex-intro.srt
Normal file
472
public/videos/latex-intro.srt
Normal file
@@ -0,0 +1,472 @@
|
||||
1
|
||||
00:00:01,280 --> 00:00:05,600
|
||||
Hello, and welcome to getting started
|
||||
|
||||
2
|
||||
00:00:03,040 --> 00:00:06,960
|
||||
with LaTeX. This tutorial will walk you
|
||||
|
||||
3
|
||||
00:00:05,600 --> 00:00:09,160
|
||||
through creating your first document
|
||||
|
||||
4
|
||||
00:00:06,960 --> 00:00:12,800
|
||||
using the LaTeX
|
||||
|
||||
5
|
||||
00:00:09,160 --> 00:00:14,719
|
||||
system. Alright, so what is LaTeX? LaTeX
|
||||
|
||||
6
|
||||
00:00:12,800 --> 00:00:16,680
|
||||
is a typesetting system commonly used
|
||||
|
||||
7
|
||||
00:00:14,719 --> 00:00:18,640
|
||||
for technical and scientific
|
||||
|
||||
8
|
||||
00:00:16,680 --> 00:00:20,640
|
||||
documents. It's widely used throughout
|
||||
|
||||
9
|
||||
00:00:18,640 --> 00:00:23,199
|
||||
the world of academia specifically in
|
||||
|
||||
10
|
||||
00:00:20,640 --> 00:00:25,600
|
||||
engineering and science fields. This is
|
||||
|
||||
11
|
||||
00:00:23,199 --> 00:00:27,920
|
||||
due to how easy LaTeX makes it for someone
|
||||
|
||||
12
|
||||
00:00:25,600 --> 00:00:30,960
|
||||
to include complex mathematical
|
||||
|
||||
13
|
||||
00:00:27,920 --> 00:00:32,880
|
||||
equations, models and more. Most documents
|
||||
|
||||
14
|
||||
00:00:30,960 --> 00:00:34,920
|
||||
written in math or physics courses here
|
||||
|
||||
15
|
||||
00:00:32,880 --> 00:00:37,360
|
||||
at Bucknell are written using
|
||||
|
||||
16
|
||||
00:00:34,920 --> 00:00:39,360
|
||||
LaTeX. Throughout this tutorial we'll be
|
||||
|
||||
17
|
||||
00:00:37,360 --> 00:00:43,440
|
||||
utilizing a free LaTeX editor called
|
||||
|
||||
18
|
||||
00:00:39,360 --> 00:00:43,440
|
||||
Overleaf which is available online at
|
||||
|
||||
19
|
||||
00:00:44,360 --> 00:00:48,640
|
||||
overleaf.com. All right, so let's set up
|
||||
|
||||
20
|
||||
00:00:46,399 --> 00:00:51,280
|
||||
an editor. We'll start by going to
|
||||
|
||||
21
|
||||
00:00:48,640 --> 00:00:52,800
|
||||
Overleaf and signing in. If you don't
|
||||
|
||||
22
|
||||
00:00:51,280 --> 00:00:54,520
|
||||
have an account, register using your
|
||||
|
||||
23
|
||||
00:00:52,800 --> 00:00:57,199
|
||||
school provided Google
|
||||
|
||||
24
|
||||
00:00:54,520 --> 00:00:58,960
|
||||
account. Once you see this page, click the
|
||||
|
||||
25
|
||||
00:00:57,199 --> 00:01:00,879
|
||||
create a new project button and select
|
||||
|
||||
26
|
||||
00:00:58,960 --> 00:01:03,840
|
||||
blank project. You'll be sent to the
|
||||
|
||||
27
|
||||
00:01:00,879 --> 00:01:06,000
|
||||
Overleaf editor. This is where we'll be
|
||||
|
||||
28
|
||||
00:01:03,840 --> 00:01:08,479
|
||||
working on our documents. The editor has
|
||||
|
||||
29
|
||||
00:01:06,000 --> 00:01:11,280
|
||||
three main segments: the file selector,
|
||||
|
||||
30
|
||||
00:01:08,479 --> 00:01:12,799
|
||||
code editor, and preview pane. When
|
||||
|
||||
31
|
||||
00:01:11,280 --> 00:01:14,640
|
||||
editing code, you'll need to hit the
|
||||
|
||||
32
|
||||
00:01:12,799 --> 00:01:16,439
|
||||
recompile button to see changes on the
|
||||
|
||||
33
|
||||
00:01:14,640 --> 00:01:18,960
|
||||
preview
|
||||
|
||||
34
|
||||
00:01:16,439 --> 00:01:21,520
|
||||
pane. Let's talk about some commonly used
|
||||
|
||||
35
|
||||
00:01:18,960 --> 00:01:23,840
|
||||
tags. We begin with the title, author, and
|
||||
|
||||
36
|
||||
00:01:21,520 --> 00:01:25,680
|
||||
date tags. These specify important
|
||||
|
||||
37
|
||||
00:01:23,840 --> 00:01:27,479
|
||||
information about the document and their
|
||||
|
||||
38
|
||||
00:01:25,680 --> 00:01:29,520
|
||||
specifics are
|
||||
|
||||
39
|
||||
00:01:27,479 --> 00:01:31,280
|
||||
self-explanatory. Next we have the begin
|
||||
|
||||
40
|
||||
00:01:29,520 --> 00:01:33,000
|
||||
tag which tells the compiler to start
|
||||
|
||||
41
|
||||
00:01:31,280 --> 00:01:35,520
|
||||
building the document
|
||||
|
||||
42
|
||||
00:01:33,000 --> 00:01:37,600
|
||||
itself. The make title tag tells the
|
||||
|
||||
43
|
||||
00:01:35,520 --> 00:01:40,200
|
||||
compiler to format and display the title
|
||||
|
||||
44
|
||||
00:01:37,600 --> 00:01:42,880
|
||||
information including the author and the
|
||||
|
||||
45
|
||||
00:01:40,200 --> 00:01:44,479
|
||||
date. The section tag signifies the
|
||||
|
||||
46
|
||||
00:01:42,880 --> 00:01:48,159
|
||||
beginning of a section and produces a
|
||||
|
||||
47
|
||||
00:01:44,479 --> 00:01:49,920
|
||||
numbered section heading.
|
||||
|
||||
48
|
||||
00:01:48,159 --> 00:01:53,520
|
||||
Next we'll talk about tags that can be
|
||||
|
||||
49
|
||||
00:01:49,920 --> 00:01:57,200
|
||||
used to format text. The textbf tag
|
||||
|
||||
50
|
||||
00:01:53,520 --> 00:01:58,759
|
||||
makes text appear bold. The textit tag
|
||||
|
||||
51
|
||||
00:01:57,200 --> 00:02:01,360
|
||||
makes text appear
|
||||
|
||||
52
|
||||
00:01:58,759 --> 00:02:04,799
|
||||
italicized. The underline tag makes text
|
||||
|
||||
53
|
||||
00:02:01,360 --> 00:02:06,880
|
||||
appear underlined. The emph tag emphasizes a
|
||||
|
||||
54
|
||||
00:02:04,799 --> 00:02:09,520
|
||||
specific block of text. The appearance of
|
||||
|
||||
55
|
||||
00:02:06,880 --> 00:02:11,360
|
||||
this effect depends on the situation. If
|
||||
|
||||
56
|
||||
00:02:09,520 --> 00:02:12,879
|
||||
the text being emphasized is within a
|
||||
|
||||
57
|
||||
00:02:11,360 --> 00:02:16,080
|
||||
block of standard text, it will be
|
||||
|
||||
58
|
||||
00:02:12,879 --> 00:02:18,000
|
||||
italicized. Otherwise, if that selected
|
||||
|
||||
59
|
||||
00:02:16,080 --> 00:02:19,959
|
||||
text block is within other italicized
|
||||
|
||||
60
|
||||
00:02:18,000 --> 00:02:21,920
|
||||
text, it will be
|
||||
|
||||
61
|
||||
00:02:19,959 --> 00:02:23,760
|
||||
de-italicized. These effects can be
|
||||
|
||||
62
|
||||
00:02:21,920 --> 00:02:26,080
|
||||
combined within the same line. For
|
||||
|
||||
63
|
||||
00:02:23,760 --> 00:02:28,720
|
||||
example, this line of code will italicize
|
||||
|
||||
64
|
||||
00:02:26,080 --> 00:02:31,440
|
||||
the selected text as well as keep the
|
||||
|
||||
65
|
||||
00:02:28,720 --> 00:02:31,440
|
||||
surrounding text
|
||||
|
||||
66
|
||||
00:02:31,480 --> 00:02:36,720
|
||||
bold. Next we'll talk about displaying
|
||||
|
||||
67
|
||||
00:02:33,920 --> 00:02:38,720
|
||||
math within a LaTeX document. Math
|
||||
|
||||
68
|
||||
00:02:36,720 --> 00:02:41,440
|
||||
equations can be displayed in two modes:
|
||||
|
||||
69
|
||||
00:02:38,720 --> 00:02:43,200
|
||||
inline mode and display mode.
|
||||
|
||||
70
|
||||
00:02:41,440 --> 00:02:45,360
|
||||
Starting with inline mode, we use the
|
||||
|
||||
71
|
||||
00:02:43,200 --> 00:02:48,000
|
||||
begin math and end math tags to specify
|
||||
|
||||
72
|
||||
00:02:45,360 --> 00:02:50,239
|
||||
where an equation is written. This method
|
||||
|
||||
73
|
||||
00:02:48,000 --> 00:02:51,840
|
||||
places an equation inline, meaning that
|
||||
|
||||
74
|
||||
00:02:50,239 --> 00:02:54,519
|
||||
it will wrap as if it was part of the
|
||||
|
||||
75
|
||||
00:02:51,840 --> 00:02:57,120
|
||||
paragraph, blending with the surrounding
|
||||
|
||||
76
|
||||
00:02:54,519 --> 00:02:59,120
|
||||
text. On the other hand, we can use
|
||||
|
||||
77
|
||||
00:02:57,120 --> 00:03:01,040
|
||||
display mode which uses the begin
|
||||
|
||||
78
|
||||
00:02:59,120 --> 00:03:03,840
|
||||
equation and end equation tags to
|
||||
|
||||
79
|
||||
00:03:01,040 --> 00:03:05,519
|
||||
distinguish equations from text.
|
||||
|
||||
80
|
||||
00:03:03,840 --> 00:03:08,640
|
||||
This will display math as if it's its
|
||||
|
||||
81
|
||||
00:03:05,519 --> 00:03:10,480
|
||||
own line in a paragraph and can be used
|
||||
|
||||
82
|
||||
00:03:08,640 --> 00:03:12,640
|
||||
to separate equations from the rest of
|
||||
|
||||
83
|
||||
00:03:10,480 --> 00:03:12,640
|
||||
the
|
||||
|
||||
84
|
||||
00:03:12,680 --> 00:03:18,000
|
||||
text. Now we'll put it all together.
|
||||
|
||||
85
|
||||
00:03:15,920 --> 00:03:20,319
|
||||
Here's an example of a document, this one
|
||||
|
||||
86
|
||||
00:03:18,000 --> 00:03:22,239
|
||||
being the script for this video. Notice
|
||||
|
||||
87
|
||||
00:03:20,319 --> 00:03:24,800
|
||||
how the title, author, and date tags are
|
||||
|
||||
88
|
||||
00:03:22,239 --> 00:03:26,879
|
||||
used as well as the section headers. The
|
||||
|
||||
89
|
||||
00:03:24,800 --> 00:03:28,280
|
||||
title, author, and date are formatted in
|
||||
|
||||
90
|
||||
00:03:26,879 --> 00:03:30,640
|
||||
the center of the page
|
||||
|
||||
91
|
||||
00:03:28,280 --> 00:03:33,120
|
||||
automatically with text sizes being
|
||||
|
||||
92
|
||||
00:03:30,640 --> 00:03:34,640
|
||||
decided by the compiler. The section
|
||||
|
||||
93
|
||||
00:03:33,120 --> 00:03:36,879
|
||||
headings are automatically numbered and
|
||||
|
||||
94
|
||||
00:03:34,640 --> 00:03:39,599
|
||||
bolded and create coherent paragraphs
|
||||
|
||||
95
|
||||
00:03:36,879 --> 00:03:41,680
|
||||
with minimal effort. As you can see, the
|
||||
|
||||
96
|
||||
00:03:39,599 --> 00:03:43,360
|
||||
LaTeX system allows for an author to
|
||||
|
||||
97
|
||||
00:03:41,680 --> 00:03:45,599
|
||||
create a document without focusing on
|
||||
|
||||
98
|
||||
00:03:43,360 --> 00:03:47,519
|
||||
its formatting as one would see with
|
||||
|
||||
99
|
||||
00:03:45,599 --> 00:03:50,080
|
||||
other what-you-see-is-what-you-get
|
||||
|
||||
100
|
||||
00:03:47,519 --> 00:03:53,040
|
||||
editors such as Microsoft Word or Google
|
||||
|
||||
101
|
||||
00:03:50,080 --> 00:03:55,200
|
||||
Docs. Instead, the author can focus on the
|
||||
|
||||
102
|
||||
00:03:53,040 --> 00:03:57,360
|
||||
content knowing that the content will be
|
||||
|
||||
103
|
||||
00:03:55,200 --> 00:03:59,599
|
||||
presented in a coherent way that makes
|
||||
|
||||
104
|
||||
00:03:57,360 --> 00:04:01,599
|
||||
sense to the reader. When you're done
|
||||
|
||||
105
|
||||
00:03:59,599 --> 00:04:04,400
|
||||
writing the document or making any edits
|
||||
|
||||
106
|
||||
00:04:01,599 --> 00:04:06,319
|
||||
to it, you can click the recompile button
|
||||
|
||||
107
|
||||
00:04:04,400 --> 00:04:08,799
|
||||
and that will display a preview in the
|
||||
|
||||
108
|
||||
00:04:06,319 --> 00:04:10,959
|
||||
preview pane. When you want to download
|
||||
|
||||
109
|
||||
00:04:08,799 --> 00:04:12,959
|
||||
or export the document, click the
|
||||
|
||||
110
|
||||
00:04:10,959 --> 00:04:15,920
|
||||
download button next to the recompile
|
||||
|
||||
111
|
||||
00:04:12,959 --> 00:04:19,160
|
||||
button. That will export a PDF file and
|
||||
|
||||
112
|
||||
00:04:15,920 --> 00:04:22,400
|
||||
send it to your downloads
|
||||
|
||||
113
|
||||
00:04:19,160 --> 00:04:24,080
|
||||
folder. And that's it! Congratulations,
|
||||
|
||||
114
|
||||
00:04:22,400 --> 00:04:26,160
|
||||
you've just finished your first LaTeX
|
||||
|
||||
115
|
||||
00:04:24,080 --> 00:04:28,320
|
||||
document. I hope you've been able to
|
||||
|
||||
116
|
||||
00:04:26,160 --> 00:04:30,400
|
||||
learn from this video and you'll be able
|
||||
|
||||
117
|
||||
00:04:28,320 --> 00:04:34,919
|
||||
to recreate a LaTeX document whenever
|
||||
|
||||
118
|
||||
00:04:30,400 --> 00:04:34,919
|
||||
you need. Thank you for watching.
|
||||
|
||||
355
public/videos/latex-intro.vtt
Normal file
355
public/videos/latex-intro.vtt
Normal file
@@ -0,0 +1,355 @@
|
||||
WEBVTT
|
||||
|
||||
00:00:01.280 --> 00:00:05.600
|
||||
Hello, and welcome to getting started
|
||||
|
||||
00:00:03.040 --> 00:00:06.960
|
||||
with LaTeX. This tutorial will walk you
|
||||
|
||||
00:00:05.600 --> 00:00:09.160
|
||||
through creating your first document
|
||||
|
||||
00:00:06.960 --> 00:00:12.800
|
||||
using the LaTeX
|
||||
|
||||
00:00:09.160 --> 00:00:14.719
|
||||
system. Alright, so what is LaTeX? LaTeX
|
||||
|
||||
00:00:12.800 --> 00:00:16.680
|
||||
is a typesetting system commonly used
|
||||
|
||||
00:00:14.719 --> 00:00:18.640
|
||||
for technical and scientific
|
||||
|
||||
00:00:16.680 --> 00:00:20.640
|
||||
documents. It's widely used throughout
|
||||
|
||||
00:00:18.640 --> 00:00:23.199
|
||||
the world of academia specifically in
|
||||
|
||||
00:00:20.640 --> 00:00:25.600
|
||||
engineering and science fields. This is
|
||||
|
||||
00:00:23.199 --> 00:00:27.920
|
||||
due to how easy LaTeX makes it for someone
|
||||
|
||||
00:00:25.600 --> 00:00:30.960
|
||||
to include complex mathematical
|
||||
|
||||
00:00:27.920 --> 00:00:32.880
|
||||
equations, models and more. Most documents
|
||||
|
||||
00:00:30.960 --> 00:00:34.920
|
||||
written in math or physics courses here
|
||||
|
||||
00:00:32.880 --> 00:00:37.360
|
||||
at Bucknell are written using
|
||||
|
||||
00:00:34.920 --> 00:00:39.360
|
||||
LaTeX. Throughout this tutorial we'll be
|
||||
|
||||
00:00:37.360 --> 00:00:43.440
|
||||
utilizing a free LaTeX editor called
|
||||
|
||||
00:00:39.360 --> 00:00:43.440
|
||||
Overleaf which is available online at
|
||||
|
||||
00:00:44.360 --> 00:00:48.640
|
||||
overleaf.com. All right, so let's set up
|
||||
|
||||
00:00:46.399 --> 00:00:51.280
|
||||
an editor. We'll start by going to
|
||||
|
||||
00:00:48.640 --> 00:00:52.800
|
||||
Overleaf and signing in. If you don't
|
||||
|
||||
00:00:51.280 --> 00:00:54.520
|
||||
have an account, register using your
|
||||
|
||||
00:00:52.800 --> 00:00:57.199
|
||||
school provided Google
|
||||
|
||||
00:00:54.520 --> 00:00:58.960
|
||||
account. Once you see this page, click the
|
||||
|
||||
00:00:57.199 --> 00:01:00.879
|
||||
create a new project button and select
|
||||
|
||||
00:00:58.960 --> 00:01:03.840
|
||||
blank project. You'll be sent to the
|
||||
|
||||
00:01:00.879 --> 00:01:06.000
|
||||
Overleaf editor. This is where we'll be
|
||||
|
||||
00:01:03.840 --> 00:01:08.479
|
||||
working on our documents. The editor has
|
||||
|
||||
00:01:06.000 --> 00:01:11.280
|
||||
three main segments: the file selector,
|
||||
|
||||
00:01:08.479 --> 00:01:12.799
|
||||
code editor, and preview pane. When
|
||||
|
||||
00:01:11.280 --> 00:01:14.640
|
||||
editing code, you'll need to hit the
|
||||
|
||||
00:01:12.799 --> 00:01:16.439
|
||||
recompile button to see changes on the
|
||||
|
||||
00:01:14.640 --> 00:01:18.960
|
||||
preview
|
||||
|
||||
00:01:16.439 --> 00:01:21.520
|
||||
pane. Let's talk about some commonly used
|
||||
|
||||
00:01:18.960 --> 00:01:23.840
|
||||
tags. We begin with the title, author, and
|
||||
|
||||
00:01:21.520 --> 00:01:25.680
|
||||
date tags. These specify important
|
||||
|
||||
00:01:23.840 --> 00:01:27.479
|
||||
information about the document and their
|
||||
|
||||
00:01:25.680 --> 00:01:29.520
|
||||
specifics are
|
||||
|
||||
00:01:27.479 --> 00:01:31.280
|
||||
self-explanatory. Next we have the begin
|
||||
|
||||
00:01:29.520 --> 00:01:33.000
|
||||
tag which tells the compiler to start
|
||||
|
||||
00:01:31.280 --> 00:01:35.520
|
||||
building the document
|
||||
|
||||
00:01:33.000 --> 00:01:37.600
|
||||
itself. The make title tag tells the
|
||||
|
||||
00:01:35.520 --> 00:01:40.200
|
||||
compiler to format and display the title
|
||||
|
||||
00:01:37.600 --> 00:01:42.880
|
||||
information including the author and the
|
||||
|
||||
00:01:40.200 --> 00:01:44.479
|
||||
date. The section tag signifies the
|
||||
|
||||
00:01:42.880 --> 00:01:48.159
|
||||
beginning of a section and produces a
|
||||
|
||||
00:01:44.479 --> 00:01:49.920
|
||||
numbered section heading.
|
||||
|
||||
00:01:48.159 --> 00:01:53.520
|
||||
Next we'll talk about tags that can be
|
||||
|
||||
00:01:49.920 --> 00:01:57.200
|
||||
used to format text. The textbf tag
|
||||
|
||||
00:01:53.520 --> 00:01:58.759
|
||||
makes text appear bold. The textit tag
|
||||
|
||||
00:01:57.200 --> 00:02:01.360
|
||||
makes text appear
|
||||
|
||||
00:01:58.759 --> 00:02:04.799
|
||||
italicized. The underline tag makes text
|
||||
|
||||
00:02:01.360 --> 00:02:06.880
|
||||
appear underlined. The emph tag emphasizes a
|
||||
|
||||
00:02:04.799 --> 00:02:09.520
|
||||
specific block of text. The appearance of
|
||||
|
||||
00:02:06.880 --> 00:02:11.360
|
||||
this effect depends on the situation. If
|
||||
|
||||
00:02:09.520 --> 00:02:12.879
|
||||
the text being emphasized is within a
|
||||
|
||||
00:02:11.360 --> 00:02:16.080
|
||||
block of standard text, it will be
|
||||
|
||||
00:02:12.879 --> 00:02:18.000
|
||||
italicized. Otherwise, if that selected
|
||||
|
||||
00:02:16.080 --> 00:02:19.959
|
||||
text block is within other italicized
|
||||
|
||||
00:02:18.000 --> 00:02:21.920
|
||||
text, it will be
|
||||
|
||||
00:02:19.959 --> 00:02:23.760
|
||||
de-italicized. These effects can be
|
||||
|
||||
00:02:21.920 --> 00:02:26.080
|
||||
combined within the same line. For
|
||||
|
||||
00:02:23.760 --> 00:02:28.720
|
||||
example, this line of code will italicize
|
||||
|
||||
00:02:26.080 --> 00:02:31.440
|
||||
the selected text as well as keep the
|
||||
|
||||
00:02:28.720 --> 00:02:31.440
|
||||
surrounding text
|
||||
|
||||
00:02:31.480 --> 00:02:36.720
|
||||
bold. Next we'll talk about displaying
|
||||
|
||||
00:02:33.920 --> 00:02:38.720
|
||||
math within a LaTeX document. Math
|
||||
|
||||
00:02:36.720 --> 00:02:41.440
|
||||
equations can be displayed in two modes:
|
||||
|
||||
00:02:38.720 --> 00:02:43.200
|
||||
inline mode and display mode.
|
||||
|
||||
00:02:41.440 --> 00:02:45.360
|
||||
Starting with inline mode, we use the
|
||||
|
||||
00:02:43.200 --> 00:02:48.000
|
||||
begin math and end math tags to specify
|
||||
|
||||
00:02:45.360 --> 00:02:50.239
|
||||
where an equation is written. This method
|
||||
|
||||
00:02:48.000 --> 00:02:51.840
|
||||
places an equation inline, meaning that
|
||||
|
||||
00:02:50.239 --> 00:02:54.519
|
||||
it will wrap as if it was part of the
|
||||
|
||||
00:02:51.840 --> 00:02:57.120
|
||||
paragraph, blending with the surrounding
|
||||
|
||||
00:02:54.519 --> 00:02:59.120
|
||||
text. On the other hand, we can use
|
||||
|
||||
00:02:57.120 --> 00:03:01.040
|
||||
display mode which uses the begin
|
||||
|
||||
00:02:59.120 --> 00:03:03.840
|
||||
equation and end equation tags to
|
||||
|
||||
00:03:01.040 --> 00:03:05.519
|
||||
distinguish equations from text.
|
||||
|
||||
00:03:03.840 --> 00:03:08.640
|
||||
This will display math as if it's its
|
||||
|
||||
00:03:05.519 --> 00:03:10.480
|
||||
own line in a paragraph and can be used
|
||||
|
||||
00:03:08.640 --> 00:03:12.640
|
||||
to separate equations from the rest of
|
||||
|
||||
00:03:10.480 --> 00:03:12.640
|
||||
the
|
||||
|
||||
00:03:12.680 --> 00:03:18.000
|
||||
text. Now we'll put it all together.
|
||||
|
||||
00:03:15.920 --> 00:03:20.319
|
||||
Here's an example of a document, this one
|
||||
|
||||
00:03:18.000 --> 00:03:22.239
|
||||
being the script for this video. Notice
|
||||
|
||||
00:03:20.319 --> 00:03:24.800
|
||||
how the title, author, and date tags are
|
||||
|
||||
00:03:22.239 --> 00:03:26.879
|
||||
used as well as the section headers. The
|
||||
|
||||
00:03:24.800 --> 00:03:28.280
|
||||
title, author, and date are formatted in
|
||||
|
||||
00:03:26.879 --> 00:03:30.640
|
||||
the center of the page
|
||||
|
||||
00:03:28.280 --> 00:03:33.120
|
||||
automatically with text sizes being
|
||||
|
||||
00:03:30.640 --> 00:03:34.640
|
||||
decided by the compiler. The section
|
||||
|
||||
00:03:33.120 --> 00:03:36.879
|
||||
headings are automatically numbered and
|
||||
|
||||
00:03:34.640 --> 00:03:39.599
|
||||
bolded and create coherent paragraphs
|
||||
|
||||
00:03:36.879 --> 00:03:41.680
|
||||
with minimal effort. As you can see, the
|
||||
|
||||
00:03:39.599 --> 00:03:43.360
|
||||
LaTeX system allows for an author to
|
||||
|
||||
00:03:41.680 --> 00:03:45.599
|
||||
create a document without focusing on
|
||||
|
||||
00:03:43.360 --> 00:03:47.519
|
||||
its formatting as one would see with
|
||||
|
||||
00:03:45.599 --> 00:03:50.080
|
||||
other what-you-see-is-what-you-get
|
||||
|
||||
00:03:47.519 --> 00:03:53.040
|
||||
editors such as Microsoft Word or Google
|
||||
|
||||
00:03:50.080 --> 00:03:55.200
|
||||
Docs. Instead, the author can focus on the
|
||||
|
||||
00:03:53.040 --> 00:03:57.360
|
||||
content knowing that the content will be
|
||||
|
||||
00:03:55.200 --> 00:03:59.599
|
||||
presented in a coherent way that makes
|
||||
|
||||
00:03:57.360 --> 00:04:01.599
|
||||
sense to the reader. When you're done
|
||||
|
||||
00:03:59.599 --> 00:04:04.400
|
||||
writing the document or making any edits
|
||||
|
||||
00:04:01.599 --> 00:04:06.319
|
||||
to it, you can click the recompile button
|
||||
|
||||
00:04:04.400 --> 00:04:08.799
|
||||
and that will display a preview in the
|
||||
|
||||
00:04:06.319 --> 00:04:10.959
|
||||
preview pane. When you want to download
|
||||
|
||||
00:04:08.799 --> 00:04:12.959
|
||||
or export the document, click the
|
||||
|
||||
00:04:10.959 --> 00:04:15.920
|
||||
download button next to the recompile
|
||||
|
||||
00:04:12.959 --> 00:04:19.160
|
||||
button. That will export a PDF file and
|
||||
|
||||
00:04:15.920 --> 00:04:22.400
|
||||
send it to your downloads
|
||||
|
||||
00:04:19.160 --> 00:04:24.080
|
||||
folder. And that's it! Congratulations,
|
||||
|
||||
00:04:22.400 --> 00:04:26.160
|
||||
you've just finished your first LaTeX
|
||||
|
||||
00:04:24.080 --> 00:04:28.320
|
||||
document. I hope you've been able to
|
||||
|
||||
00:04:26.160 --> 00:04:30.400
|
||||
learn from this video and you'll be able
|
||||
|
||||
00:04:28.320 --> 00:04:34.919
|
||||
to recreate a LaTeX document whenever
|
||||
|
||||
00:04:30.400 --> 00:04:34.919
|
||||
you need. Thank you for watching.
|
||||
@@ -3,6 +3,8 @@ import { SpeedInsights } from "@vercel/speed-insights/next"
|
||||
import { Footer } from "~/components/Footer"
|
||||
import { Navigation } from "~/components/Navigation"
|
||||
import { Sidebar } from "~/components/Sidebar"
|
||||
import { BreadcrumbWrapper } from "~/components/BreadcrumbWrapper"
|
||||
|
||||
import { inter } from "~/lib/fonts"
|
||||
import { description, name } from "~/lib/data";
|
||||
import "~/styles/globals.css"
|
||||
@@ -27,13 +29,14 @@ export default function RootLayout({ children }: React.PropsWithChildren) {
|
||||
<Sidebar />
|
||||
</aside>
|
||||
<main className="flex-1 overflow-y-auto py-8">
|
||||
<BreadcrumbWrapper />
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</body>
|
||||
</html >
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
16
src/app/not-found.tsx
Normal file
16
src/app/not-found.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-[calc(100vh-200px)]">
|
||||
<h2 className="text-3xl font-bold mb-4">404 - Not Found</h2>
|
||||
<p className="mb-6">Could not find the requested resource</p>
|
||||
<Link
|
||||
href="/"
|
||||
className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
|
||||
>
|
||||
Return Home
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
81
src/app/projects/latex-intro/page.tsx
Normal file
81
src/app/projects/latex-intro/page.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Metadata } from "next";
|
||||
import { projects } from "~/lib/data";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { AccessibleVideo } from "~/components/AccessibleVideo";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "LaTeX Introduction Tutorial",
|
||||
description: "A comprehensive 5-minute introduction to LaTeX document preparation system for beginners.",
|
||||
};
|
||||
|
||||
const transcript = `
|
||||
<p>Hello, and welcome to getting started with LaTeX. This tutorial will walk you through creating your first document using the LaTeX system.</p>
|
||||
<p>LaTeX is a typesetting system commonly used for technical and scientific documents. It's widely used throughout the world of academia specifically in engineering and science fields.</p>
|
||||
<p>This is due to how easy LaTeX makes it for someone to include complex mathematical equations, models and more. Most documents written in math or physics courses here at Bucknell are written using LaTeX.</p>
|
||||
<p>Throughout this tutorial we'll be utilizing a free LaTeX editor called Overleaf which is available online at overleaf.com.</p>
|
||||
<p>We'll go through:</p>
|
||||
<ul>
|
||||
<li>Setting up the editor</li>
|
||||
<li>Commonly used tags and formatting</li>
|
||||
<li>Working with math equations</li>
|
||||
<li>Creating a complete document</li>
|
||||
</ul>
|
||||
<p>By the end of this tutorial, you'll be able to create your own professional-looking documents with proper formatting and mathematical notation.</p>
|
||||
`;
|
||||
|
||||
export default function LatexTutorialPage() {
|
||||
// Find the LaTeX project data
|
||||
const project = projects.find((p) => p.title === "LaTeX Introduction Tutorial");
|
||||
|
||||
return (
|
||||
<div className="container pt-0 pb-6">
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold tracking-tight mb-4">{project?.title}</h1>
|
||||
<p className="text-lg text-muted-foreground">{project?.longDescription}</p>
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
{project?.tags.map((tag) => (
|
||||
<Badge key={tag} variant="secondary">
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8">
|
||||
<AccessibleVideo
|
||||
src="/videos/latex-intro.mp4"
|
||||
poster="/latex-thumbnail.jpg"
|
||||
captionSrc="/videos/latex-intro.vtt"
|
||||
title="LaTeX Introduction Tutorial"
|
||||
description="A 5-minute introduction to LaTeX, covering basic syntax, document structure, and common use cases."
|
||||
transcript={transcript}
|
||||
posterAlt="Decorative thumbnail showing LaTeX code and formatting example"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 space-y-6">
|
||||
<h2 className="text-2xl font-bold tracking-tight">Why Learn LaTeX?</h2>
|
||||
<p>LaTeX is a document preparation system widely used in academia, especially in fields like mathematics, computer science, physics, and engineering. It excels at:</p>
|
||||
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li>Professional typesetting of mathematical equations</li>
|
||||
<li>Consistent document formatting</li>
|
||||
<li>Automated handling of citations and references</li>
|
||||
<li>Version control compatibility</li>
|
||||
<li>Cross-platform document creation</li>
|
||||
</ul>
|
||||
|
||||
<p>This tutorial provides a gentle introduction to get you started with your first LaTeX document.</p>
|
||||
|
||||
<h2 className="text-2xl font-bold tracking-tight">Key Resources</h2>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<li><a href="https://www.overleaf.com" className="text-primary hover:underline" target="_blank" rel="noopener noreferrer">Overleaf</a> - A popular online LaTeX editor</li>
|
||||
<li><a href="https://www.latex-project.org/get/" className="text-primary hover:underline" target="_blank" rel="noopener noreferrer">LaTeX Project</a> - Official downloads for local installation</li>
|
||||
<li><a href="https://en.wikibooks.org/wiki/LaTeX" className="text-primary hover:underline" target="_blank" rel="noopener noreferrer">LaTeX Wikibook</a> - Comprehensive reference guide</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "~/components/ui/card";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "~/components/ui/card";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import Link from "next/link";
|
||||
import { ArrowUpRight } from "lucide-react";
|
||||
import { ArrowUpRight, Play, BookOpen } from "lucide-react";
|
||||
import { projects } from "~/lib/data";
|
||||
import Image from "next/image";
|
||||
import { CardSkeleton } from "~/components/ui/skeletons";
|
||||
@@ -41,7 +42,7 @@ export default function ProjectsPage() {
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle>{project.title}</CardTitle>
|
||||
{project.link && (
|
||||
{project.link && !project.link.startsWith('/') && (
|
||||
<Link
|
||||
href={project.link}
|
||||
target="_blank"
|
||||
@@ -66,20 +67,53 @@ export default function ProjectsPage() {
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
{project.link && project.link.startsWith('/') && (
|
||||
<CardFooter className="pt-0">
|
||||
<Link href={project.link}>
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
className="mt-0"
|
||||
>
|
||||
{project.title === "LaTeX Introduction Tutorial" ? (
|
||||
<>
|
||||
<Play className="mr-2 h-4 w-4" />
|
||||
Watch the LaTeX tutorial
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<BookOpen className="mr-2 h-4 w-4" />
|
||||
View project details
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</Link>
|
||||
</CardFooter>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{project.image && (
|
||||
<div className="px-6 pb-6 lg:py-6 lg:w-1/3 md:px-24 lg:px-6">
|
||||
<div className="relative aspect-[4/3] w-full overflow-hidden">
|
||||
<Image
|
||||
src={project.image}
|
||||
alt={project.title}
|
||||
width={400}
|
||||
height={300}
|
||||
className="object-contain w-full h-full"
|
||||
priority={index === 0}
|
||||
/>
|
||||
</div>
|
||||
<Link href={project.link?.startsWith('/') ? project.link : project.link || '#'}>
|
||||
<div className="relative aspect-[4/3] w-full overflow-hidden rounded-md transition-all hover:opacity-90">
|
||||
<Image
|
||||
src={project.image}
|
||||
alt={project.imageAlt || project.title}
|
||||
width={400}
|
||||
height={300}
|
||||
className="object-cover w-full h-full"
|
||||
priority={index === 0}
|
||||
/>
|
||||
{project.title === "LaTeX Introduction Tutorial" && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-black/30">
|
||||
<div className="rounded-full bg-white/80 p-3">
|
||||
<Play className="h-8 w-8 text-primary" fill="currentColor" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function TripsPage() {
|
||||
<div key={imgIndex} className="flex-shrink-0">
|
||||
<Image
|
||||
src={image}
|
||||
alt={trip.title}
|
||||
alt={trip.alts && trip.alts[imgIndex] ? trip.alts[imgIndex] : `${trip.title} - image ${imgIndex + 1}`}
|
||||
width={250}
|
||||
height={200}
|
||||
className="object-cover min-h-[200px] max-h-[200px]"
|
||||
|
||||
143
src/components/AccessibleVideo.tsx
Normal file
143
src/components/AccessibleVideo.tsx
Normal file
@@ -0,0 +1,143 @@
|
||||
"use client";
|
||||
|
||||
import { useRef, useState } from "react";
|
||||
import { Card, CardContent } from "~/components/ui/card";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Play, Pause, Volume2, VolumeX } from "lucide-react";
|
||||
|
||||
interface AccessibleVideoProps {
|
||||
src: string;
|
||||
poster?: string;
|
||||
posterAlt?: string;
|
||||
captionSrc?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
transcript?: string;
|
||||
}
|
||||
|
||||
export function AccessibleVideo({
|
||||
src,
|
||||
poster,
|
||||
posterAlt,
|
||||
captionSrc,
|
||||
title,
|
||||
description,
|
||||
transcript,
|
||||
}: AccessibleVideoProps) {
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const [playing, setPlaying] = useState(false);
|
||||
const [muted, setMuted] = useState(false);
|
||||
const [captionsEnabled, setCaptionsEnabled] = useState(true);
|
||||
|
||||
const togglePlay = () => {
|
||||
if (videoRef.current) {
|
||||
if (playing) {
|
||||
videoRef.current.pause();
|
||||
} else {
|
||||
void videoRef.current.play();
|
||||
}
|
||||
setPlaying(!playing);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMute = () => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.muted = !muted;
|
||||
setMuted(!muted);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleCaptions = () => {
|
||||
if (videoRef.current && videoRef.current.textTracks.length > 0) {
|
||||
const track = videoRef.current.textTracks[0];
|
||||
if (track) {
|
||||
track.mode = captionsEnabled ? "hidden" : "showing";
|
||||
setCaptionsEnabled(!captionsEnabled);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div aria-labelledby="video-title" aria-describedby="video-description">
|
||||
<h2 id="video-title" className="sr-only">{title}</h2>
|
||||
<p id="video-description" className="sr-only">{description}</p>
|
||||
</div>
|
||||
|
||||
<Card className="overflow-hidden">
|
||||
<CardContent className="p-0">
|
||||
<div className="relative aspect-video w-full">
|
||||
<video
|
||||
ref={videoRef}
|
||||
className="h-full w-full"
|
||||
poster={poster}
|
||||
onPlay={() => setPlaying(true)}
|
||||
onPause={() => setPlaying(false)}
|
||||
controls
|
||||
src={src}
|
||||
aria-label={title}
|
||||
title={posterAlt || title}
|
||||
>
|
||||
{captionSrc && (
|
||||
<track
|
||||
kind="captions"
|
||||
src={captionSrc}
|
||||
label="English"
|
||||
srcLang="en"
|
||||
default={captionsEnabled}
|
||||
/>
|
||||
)}
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={togglePlay}
|
||||
aria-label={playing ? "Pause video" : "Play video"}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
{playing ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
|
||||
<span className="ml-2">{playing ? "Pause" : "Play"}</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={toggleMute}
|
||||
aria-label={muted ? "Unmute video" : "Mute video"}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
{muted ? <VolumeX className="h-4 w-4" /> : <Volume2 className="h-4 w-4" />}
|
||||
<span className="ml-2">{muted ? "Unmute" : "Mute"}</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{captionSrc && (
|
||||
<Button
|
||||
onClick={toggleCaptions}
|
||||
aria-label={captionsEnabled ? "Turn off captions" : "Turn on captions"}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<span>{captionsEnabled ? "Captions On" : "Captions Off"}</span>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{transcript && (
|
||||
<details className="mt-4">
|
||||
<summary className="cursor-pointer font-medium text-primary">View Full Transcript</summary>
|
||||
<div className="mt-2 rounded-md bg-muted p-4">
|
||||
<div className="prose prose-sm dark:prose-invert max-w-none">
|
||||
<div dangerouslySetInnerHTML={{ __html: transcript }} />
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
12
src/components/BreadcrumbWrapper.tsx
Normal file
12
src/components/BreadcrumbWrapper.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
// Dynamically import PageBreadcrumb with no SSR to avoid hydration issues
|
||||
const PageBreadcrumb = dynamic(() => import("~/components/PageBreadcrumb").then(mod => mod.PageBreadcrumb), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
export function BreadcrumbWrapper() {
|
||||
return <PageBreadcrumb />;
|
||||
}
|
||||
117
src/components/PageBreadcrumb.tsx
Normal file
117
src/components/PageBreadcrumb.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Home, ChevronRight, Folder, BookOpen, Newspaper, Plane, FileText } from "lucide-react";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "~/components/ui/breadcrumb";
|
||||
|
||||
interface BreadcrumbItem {
|
||||
href: string;
|
||||
label: string;
|
||||
icon: React.ReactNode;
|
||||
isCurrentPage?: boolean;
|
||||
}
|
||||
|
||||
export function PageBreadcrumb() {
|
||||
const pathname = usePathname();
|
||||
|
||||
// Generate breadcrumb items based on current path
|
||||
const breadcrumbItems: BreadcrumbItem[] = [
|
||||
{
|
||||
href: "/",
|
||||
label: "Home",
|
||||
icon: <Home className="h-3.5 w-3.5 mr-1" />,
|
||||
}
|
||||
];
|
||||
|
||||
// Parse path segments into breadcrumb items
|
||||
const pathSegments = pathname.split('/').filter(segment => segment !== '');
|
||||
|
||||
if (pathSegments.length > 0) {
|
||||
// Build paths incrementally for correct href values
|
||||
let currentPath = "";
|
||||
|
||||
pathSegments.forEach((segment, index) => {
|
||||
currentPath += `/${segment}`;
|
||||
const isLastSegment = index === pathSegments.length - 1;
|
||||
|
||||
let label = segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' ');
|
||||
let icon;
|
||||
|
||||
// Assign appropriate icons based on path
|
||||
switch (segment) {
|
||||
case 'projects':
|
||||
icon = <Folder className="h-3.5 w-3.5 mr-1" />;
|
||||
break;
|
||||
case 'articles':
|
||||
icon = <Newspaper className="h-3.5 w-3.5 mr-1" />;
|
||||
break;
|
||||
case 'publications':
|
||||
icon = <BookOpen className="h-3.5 w-3.5 mr-1" />;
|
||||
break;
|
||||
case 'travel':
|
||||
icon = <Plane className="h-3.5 w-3.5 mr-1" />;
|
||||
break;
|
||||
case 'cv':
|
||||
icon = <FileText className="h-3.5 w-3.5 mr-1" />;
|
||||
label = "CV";
|
||||
break;
|
||||
case 'latex-intro':
|
||||
icon = <BookOpen className="h-3.5 w-3.5 mr-1" />;
|
||||
label = "LaTeX Tutorial";
|
||||
break;
|
||||
default:
|
||||
icon = <ChevronRight className="h-3.5 w-3.5 mr-1" />;
|
||||
}
|
||||
|
||||
breadcrumbItems.push({
|
||||
href: currentPath,
|
||||
label,
|
||||
icon,
|
||||
isCurrentPage: isLastSegment,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Don't show breadcrumbs on the home page
|
||||
if (pathname === "/") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mb-6">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList className="flex items-center text-sm">
|
||||
{breadcrumbItems.map((item, index) => (
|
||||
<React.Fragment key={item.href}>
|
||||
<BreadcrumbItem>
|
||||
{item.isCurrentPage ? (
|
||||
<BreadcrumbPage className="flex items-center">
|
||||
{item.icon}
|
||||
{item.label}
|
||||
</BreadcrumbPage>
|
||||
) : (
|
||||
<BreadcrumbLink href={item.href} className="flex items-center">
|
||||
{item.icon}
|
||||
{item.label}
|
||||
</BreadcrumbLink>
|
||||
)}
|
||||
</BreadcrumbItem>
|
||||
|
||||
{index < breadcrumbItems.length - 1 && (
|
||||
<BreadcrumbSeparator />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
115
src/components/ui/breadcrumb.tsx
Normal file
115
src/components/ui/breadcrumb.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
||||
|
||||
import { cn } from "~/lib/utils"
|
||||
|
||||
const Breadcrumb = React.forwardRef<
|
||||
HTMLElement,
|
||||
React.ComponentPropsWithoutRef<"nav"> & {
|
||||
separator?: React.ReactNode
|
||||
}
|
||||
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
|
||||
Breadcrumb.displayName = "Breadcrumb"
|
||||
|
||||
const BreadcrumbList = React.forwardRef<
|
||||
HTMLOListElement,
|
||||
React.ComponentPropsWithoutRef<"ol">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ol
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
BreadcrumbList.displayName = "BreadcrumbList"
|
||||
|
||||
const BreadcrumbItem = React.forwardRef<
|
||||
HTMLLIElement,
|
||||
React.ComponentPropsWithoutRef<"li">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<li
|
||||
ref={ref}
|
||||
className={cn("inline-flex items-center gap-1.5", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
BreadcrumbItem.displayName = "BreadcrumbItem"
|
||||
|
||||
const BreadcrumbLink = React.forwardRef<
|
||||
HTMLAnchorElement,
|
||||
React.ComponentPropsWithoutRef<"a"> & {
|
||||
asChild?: boolean
|
||||
}
|
||||
>(({ asChild, className, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "a"
|
||||
|
||||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
className={cn("transition-colors hover:text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
BreadcrumbLink.displayName = "BreadcrumbLink"
|
||||
|
||||
const BreadcrumbPage = React.forwardRef<
|
||||
HTMLSpanElement,
|
||||
React.ComponentPropsWithoutRef<"span">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<span
|
||||
ref={ref}
|
||||
role="link"
|
||||
aria-disabled="true"
|
||||
aria-current="page"
|
||||
className={cn("font-normal text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
BreadcrumbPage.displayName = "BreadcrumbPage"
|
||||
|
||||
const BreadcrumbSeparator = ({
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"li">) => (
|
||||
<li
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
className={cn("[&>svg]:w-3.5 [&>svg]:h-3.5", className)}
|
||||
{...props}
|
||||
>
|
||||
{children ?? <ChevronRight />}
|
||||
</li>
|
||||
)
|
||||
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
|
||||
|
||||
const BreadcrumbEllipsis = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) => (
|
||||
<span
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
||||
{...props}
|
||||
>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
<span className="sr-only">More</span>
|
||||
</span>
|
||||
)
|
||||
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
|
||||
|
||||
export {
|
||||
Breadcrumb,
|
||||
BreadcrumbList,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
BreadcrumbEllipsis,
|
||||
}
|
||||
@@ -61,7 +61,7 @@ export const articles = [
|
||||
title: "Positively Innovative: Robotics for Good",
|
||||
link: "https://magazine.bucknell.edu/issue/fall-2024/robotics-for-good/",
|
||||
author: "Kate Willard",
|
||||
description: "Sean O’Connor ’26 is using his interest in robotics to fuel forward-thinking research and lead important conversations about the impact robots can have on society.",
|
||||
description: "Sean O'Connor '26 is using his interest in robotics to fuel forward-thinking research and lead important conversations about the impact robots can have on society.",
|
||||
source: "Bucknell Magazine (Fall 2024)"
|
||||
},
|
||||
{
|
||||
@@ -89,6 +89,7 @@ export const projects = [
|
||||
tags: ["ROS2", "React", "TypeScript", "C++", "Python"],
|
||||
link: "https://github.com/soconnor0919/hristudio",
|
||||
image: "/hristudio_laptop.png",
|
||||
imageAlt: "Screenshot of HRIStudio application showing the robot control dashboard on a laptop",
|
||||
featured: true
|
||||
},
|
||||
{
|
||||
@@ -97,6 +98,17 @@ export const projects = [
|
||||
longDescription: "Designed and developed a personal portfolio website using modern web technologies. Features include responsive design, dark mode support, PDF rendering for CV display, and a clean, professional interface for showcasing projects and experience.",
|
||||
tags: ["Next.js", "TypeScript", "TailwindCSS", "React"],
|
||||
link: "https://github.com/soconnor0919/personal-website",
|
||||
imageAlt: "Screenshot of the personal website showing the homepage with project showcases",
|
||||
featured: true
|
||||
},
|
||||
{
|
||||
title: "LaTeX Introduction Tutorial",
|
||||
description: "A 5-minute introduction to LaTeX document preparation system for academic and technical writing.",
|
||||
longDescription: "Created an accessible tutorial video explaining LaTeX, a typesetting system commonly used for technical and scientific documents in academia. The video covers how to set up Overleaf as an editor, explains key LaTeX tags and formatting, demonstrates both inline and display math equations, and provides a complete walkthrough of creating your first document with proper formatting.",
|
||||
tags: ["LaTeX", "Tutorial", "Accessibility", "Education", "Overleaf"],
|
||||
link: "/projects/latex-intro",
|
||||
image: "/latex-thumbnail.jpg",
|
||||
imageAlt: "Decorative thumbnail showing the project title 'Getting Started with LaTeX'",
|
||||
featured: true
|
||||
},
|
||||
{
|
||||
@@ -114,6 +126,7 @@ export const projects = [
|
||||
tags: ["C++", "Embedded Systems", "Hardware Design"],
|
||||
link: "https://github.com/soconnor0919/national_fa24",
|
||||
image: "/car.png",
|
||||
imageAlt: "Photo of the Chem-E-Car with custom control system hardware visible, showing the microcontroller and sensor connections",
|
||||
featured: true
|
||||
},
|
||||
];
|
||||
@@ -123,36 +136,42 @@ export const travel = [
|
||||
title: "AIChE Annual Student Conference 2024",
|
||||
description: "With the funding of Bucknell's chemical engineering department, and an amazing team, I was able to attend the 2024 AIChE Annual Student Conference and compete in the national Chem-E-Car competition.",
|
||||
images: ["/trips/asc2024/IMG_2641.png", "/trips/asc2024/IMG_2631.png", "/trips/asc2024/IMG_7987.png"],
|
||||
alts: ["A photo of the Chem-E-Car team holding their trophies, dressed in their lab coats.", "A selfie of the Chem-E-Car team at their workstation.", "Sean discussing the components of the Chem-E-Car with a judge."],
|
||||
tags: ["Chem-E-Car", "AIChE", "Conference", "Competition"]
|
||||
},
|
||||
{
|
||||
title: "IEEE RO-MAN 2024",
|
||||
description: "I got to attend the IEEE RO-MAN 2024 conference in Pasadena, California. It was a great opportunity to present my work on my project HRIStudio, and to network with other researchers and industry professionals.",
|
||||
images: ["/trips/roman2024/IMG_3951.png", "/trips/roman2024/IMG_3978.png", "/trips/roman2024/IMG_3946.png"],
|
||||
alts: ["A photo of Sean presenting his poster at RO-MAN 2024.", "A photo Felipe and Sean at dinner.", "A photo of Sean discussing his poster with a group of attendees."],
|
||||
tags: ["RO-MAN", "IEEE", "Conference", "Presentation"]
|
||||
},
|
||||
{
|
||||
title: "ENGR 290: Following da Vinci's Footsteps",
|
||||
description: "During the summer of 2024, I went on a study abroad program with about thirty of my peers. We explored Italy and France, following the footsteps of Leonardo da Vinci- evaluating the world through his lenses.",
|
||||
images: ["/trips/engr290/insta290.jpg", "/trips/engr290/P1013747.png", "/trips/engr290/_1024461.png"],
|
||||
tags: ["Italy", "France", "Study Abroad", "Engineering"]
|
||||
alts: ["A photo of the group taken during the final dinner of the trip.", "A photo of Florence, taken from the top of a distant hill.", "A photo of the River Seine in Paris, taken from the top of the Eiffel Tower."],
|
||||
tags: ["Study Abroad", "Italy", "France", "da Vinci"]
|
||||
},
|
||||
{
|
||||
title: "SCA Specialty Coffee Expo 2024",
|
||||
description: "As a member of the executive board of the Bucknell Coffee Society, I was able to attend the Specialty Coffee Association's Specialty Coffee Expo in early 2024, traveling to Chicago, IL.",
|
||||
images: ["/trips/sca2024/group.jpeg", "/trips/sca2024/bean.png", "/trips/sca2024/plane.png"],
|
||||
alts: ["A photo of the group at the SCA Specialty Coffee Expo in Chicago.", "A photo of the Chicago Bean.", "A photo of Chicago's coastline, taken through the window of the plane."],
|
||||
tags: ["Coffee Society", "Chicago", "SCA", "Coffee"]
|
||||
},
|
||||
{
|
||||
title: "Formula 1 Gran Premio dell'Emilia Romagna 2024",
|
||||
description: "While studying abroad with Bucknell Engineering, we were lucky enough to be within a few hours of the Imola Grand Prix! A group of students went to see the race, and it was an amazing experience.",
|
||||
images: ["/trips/imola2024/IMG_2093.png", "/trips/imola2024/IMG_2050.png", "/trips/imola2024/IMG_2066.png"],
|
||||
alts: ["A photo of the group at the Imola Circuit.", "A photo of flags on a fence, in honor of the late Ayrton Senna.", "A photo Lando Norris driving through the Imola Circuit, taken through a fence."],
|
||||
tags: ["Racing", "Formula One", "Italy"]
|
||||
},
|
||||
{
|
||||
title: "Formula 1 British Grand Prix 2024",
|
||||
description: "As a semi-recent Formula One fan, I was very excited to have the opportunity to attend the British Grand Prix weekend in 2024. I was able to see every event- marking one of my favorite weekends, probably ever.",
|
||||
images: ["/trips/silverstone/_1035852.png", "/trips/silverstone/P1025274.png", "/trips/silverstone/_1035764.png"],
|
||||
alts: ["Sean and his professor sitting on a sign with the text #BritishGP.", "A close-up photo of the rear of the McLaren MCL38.", "A photo of Oscar Piastri taking a turn at Silverstone Circuit."],
|
||||
tags: ["Racing", "Formula One", "Great Britain", "Silverstone"]
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user