repos

isaacbythewood.com-nextjs

mirror archived upstream

Animation-heavy personal portfolio on Next.js: a custom cursor, a page-transition loader, and canvas backgrounds.

canvas-animationscss-modulesdark-themehandcodednextjspersonal-websiteportfolioreact

5.8 KB · 354 lines · CSS Raw History
  1@keyframes transformRight {
  2  from {
  3    transform: scaleX(0);
  4  }
  5  to {
  6    transform: scaleX(1);
  7  }
  8}
  9
 10@keyframes transformLeft {
 11  from {
 12    transform: scaleX(1);
 13  }
 14  to {
 15    transform: scaleX(0);
 16  }
 17}
 18
 19@keyframes lightboxFadeIn {
 20  from {
 21    opacity: 0;
 22  }
 23  to {
 24    opacity: 1;
 25  }
 26}
 27
 28@keyframes lightboxScaleIn {
 29  from {
 30    opacity: 0;
 31    transform: scale(0.92);
 32  }
 33  to {
 34    opacity: 1;
 35    transform: scale(1);
 36  }
 37}
 38
 39@keyframes lightboxPulse {
 40  0%, 100% {
 41    opacity: 0.4;
 42  }
 43  50% {
 44    opacity: 1;
 45  }
 46}
 47
 48.background {
 49  position: absolute;
 50  top: 0;
 51  left: 0;
 52  right: 0;
 53  bottom: 0;
 54  background-color: white;
 55  z-index: -2;
 56}
 57
 58.heading {
 59  font-weight: 700;
 60  margin-top: 60px;
 61  margin-bottom: 10px;
 62  font-size: 2.5em;
 63  color: black;
 64}
 65
 66.heading::before {
 67  content: "";
 68  display: block;
 69  width: 50px;
 70  height: 5px;
 71  margin-bottom: 20px;
 72  background-image: linear-gradient(
 73    to right,
 74    var(--color-blue) 0,
 75    var(--color-purple) 100%
 76  );
 77}
 78
 79.paragraph {
 80  font-size: 1.3em;
 81  margin-top: 0;
 82  margin-bottom: 24px;
 83  font-weight: 300;
 84  color: rgba(0, 0, 0, 0.7);
 85  line-height: 1.6;
 86}
 87
 88.subheading {
 89  font-weight: 700;
 90  margin-top: 48px;
 91  margin-bottom: 12px;
 92  font-size: 1.6em;
 93  color: black;
 94  display: flex;
 95  align-items: center;
 96  gap: 12px;
 97}
 98
 99.subheading > span {
100  font-family: monospace;
101  font-size: 0.7em;
102  padding: 2px 8px;
103  background-image: linear-gradient(
104    to right,
105    var(--color-blue) 0,
106    var(--color-purple) 100%
107  );
108  color: white;
109  border-radius: var(--radius-2);
110  letter-spacing: 1px;
111}
112
113.paragraph a {
114  color: black;
115  text-decoration: none;
116  position: relative;
117  white-space: nowrap;
118}
119
120.paragraph a::before {
121  content: "";
122  position: absolute;
123  left: 0;
124  right: 0;
125  bottom: 0;
126  height: 2px;
127  background: rgba(0, 0, 0, 1);
128  transform-origin: left;
129  animation: transformLeft 300ms normal forwards;
130}
131
132.paragraph a::after {
133  content: "";
134  position: absolute;
135  left: 0;
136  right: 0;
137  bottom: 0;
138  height: 2px;
139  background: rgba(0, 0, 0, 0.2);
140}
141
142.paragraph a:hover::before {
143  animation: transformRight 300ms normal forwards;
144}
145
146.artGrid {
147  display: grid;
148  grid-template-columns: repeat(2, 1fr);
149  gap: 16px;
150}
151
152@media (max-width: 767.98px) {
153  .artGrid {
154    grid-template-columns: 1fr;
155  }
156}
157
158.artItem {
159  position: relative;
160  overflow: hidden;
161  border-radius: var(--radius-2);
162  transition: transform 300ms, box-shadow 300ms;
163}
164
165.artItem:hover {
166  transform: translateY(-3px);
167  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
168}
169
170.cardImage {
171  display: block;
172  background-color: var(--color-primary);
173  aspect-ratio: 16 / 9;
174  overflow: hidden;
175}
176
177.cardImage img {
178  object-fit: cover;
179  object-position: center;
180  width: 100%;
181  height: auto;
182  aspect-ratio: 16 / 9;
183  display: block;
184  opacity: 0;
185  transition: opacity 400ms ease-out;
186}
187
188.cardImage img.imgLoaded {
189  opacity: 1;
190}
191
192.artItemHeader {
193  margin: 0;
194  padding: 10px 14px;
195  display: flex;
196  justify-content: space-between;
197  align-items: center;
198  font-weight: 700;
199  font-size: 0.95em;
200  background: black;
201  color: white;
202}
203
204.artItemHeader > span {
205  font-family: monospace;
206  font-weight: 400;
207  font-size: 1em;
208  color: rgba(255, 255, 255, 0.8);
209  letter-spacing: 1px;
210}
211
212.artItemButton {
213  padding: 8px 14px;
214  font-size: 0.9em;
215  text-decoration: none;
216  font-weight: 700;
217  text-transform: uppercase;
218  display: inline-block;
219  letter-spacing: 2px;
220  color: white;
221  background-image: linear-gradient(
222    to right,
223    var(--color-blue) 0,
224    var(--color-purple) 100%
225  );
226  border-radius: var(--radius-2);
227  transform: scale(1);
228  transition: transform 250ms;
229  margin-bottom: 20px;
230}
231
232.artItemButton:hover {
233  transform: scale(1.1);
234}
235
236.artContainer {
237  width: 100%;
238  height: 500px;
239  max-height: 100vh;
240  background: black;
241  margin-bottom: 16px;
242  position: relative;
243  overflow: hidden;
244  border-radius: var(--radius-2);
245}
246
247.playButton {
248  position: absolute;
249  top: 16px;
250  right: 16px;
251  width: 44px;
252  height: 44px;
253  border: 1px solid rgba(255, 255, 255, 0.2);
254  border-radius: var(--radius-2);
255  background: rgba(0, 0, 0, 0.5);
256  color: white;
257  font-size: 20px;
258  line-height: 1;
259  padding: 0;
260  cursor: pointer;
261  display: flex;
262  align-items: center;
263  justify-content: center;
264  transition: border-color 200ms, background 200ms;
265  z-index: 5;
266}
267
268.playButton:hover {
269  border-color: var(--color-blue);
270  background: rgba(14, 63, 244, 0.2);
271}
272
273.playButton:active {
274  transform: scale(0.95);
275}
276
277/* Lightbox */
278
279.lightboxOverlay {
280  position: fixed;
281  top: 0;
282  left: 0;
283  right: 0;
284  bottom: 0;
285  background: rgba(0, 0, 0, 0.92);
286  display: flex;
287  align-items: center;
288  justify-content: center;
289  z-index: 99999;
290  animation: lightboxFadeIn 300ms ease-out;
291}
292
293.lightboxImageWrapper {
294  position: relative;
295  width: 90vw;
296  height: 90vh;
297  animation: lightboxScaleIn 400ms cubic-bezier(0.16, 1, 0.3, 1);
298  background: black;
299  border-radius: var(--radius-2);
300  overflow: hidden;
301}
302
303.lightboxImage {
304  visibility: hidden;
305  opacity: 0;
306  transition: opacity 300ms ease-out;
307}
308
309.lightboxLoading {
310  position: absolute;
311  top: 50%;
312  left: 50%;
313  transform: translate(-50%, -50%);
314  color: var(--color-blue);
315  font-family: monospace;
316  font-size: 1.2em;
317  letter-spacing: 4px;
318  text-transform: uppercase;
319  animation: lightboxPulse 1.5s ease-in-out infinite;
320}
321
322.show {
323  opacity: 1;
324  visibility: visible;
325}
326
327.hide {
328  opacity: 0;
329  visibility: hidden;
330}
331
332.lightboxClose {
333  position: absolute;
334  top: 16px;
335  right: 16px;
336  width: 40px;
337  height: 40px;
338  background: rgba(0, 0, 0, 0.6);
339  border: 1px solid rgba(255, 255, 255, 0.2);
340  border-radius: var(--radius-2);
341  color: white;
342  font-size: 1.2em;
343  display: flex;
344  align-items: center;
345  justify-content: center;
346  transition: border-color 200ms, background 200ms;
347  z-index: 1;
348}
349
350.lightboxClose:hover {
351  border-color: var(--color-blue);
352  background: rgba(14, 63, 244, 0.2);
353}