aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/Card.astro
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/Card.astro')
-rw-r--r--src/components/Card.astro469
1 files changed, 197 insertions, 272 deletions
diff --git a/src/components/Card.astro b/src/components/Card.astro
index 6ffef91..326bd1d 100644
--- a/src/components/Card.astro
+++ b/src/components/Card.astro
@@ -3,6 +3,7 @@ interface Props {
title: string;
body: string;
href: string;
+ project?: string;
year?: string;
language: string;
languageColor: string;
@@ -14,6 +15,7 @@ interface Props {
const {
href,
+ project,
title,
body,
language,
@@ -27,55 +29,90 @@ const {
---
<li class="link-card">
- <a href={href}>
- <div class="card-layout">
- <div class="content-container">
- <div class="header-section">
- <h2>{title} {year ? `(${year})` : ""}</h2>
- <div class="meta-info">
- <div class="language-container">
- <span class="dot" style={{ backgroundColor: languageColor }}></span>
- <span class="language">{language}</span>
- </div>
- {
- tags && tags.length > 0 && (
- <div class="tags-container">
- {tags.map((tag) => (
- <span class="tag">{tag}</span>
- ))}
- </div>
- )
- }
+ <div class="card-layout">
+
+ <div class="content-container">
+
+ <div class="header-section">
+ <h2>{title} {year ? `(${year})` : ""}</h2>
+
+ <div class="meta-info">
+ <div class="language-container">
+ <span class="dot" style={{ backgroundColor: languageColor }}></span>
+ <span class="language">{language}</span>
</div>
+
+ {
+ tags && tags.length > 0 && (
+ <div class="tags-container">
+ {tags.map((tag) => (
+ <span class="tag">{tag}</span>
+ ))}
+ </div>
+ )
+ }
</div>
- <div class="description">
- <div class="bullet-list" set:html={body.split('\n').map(line =>
- line.trim().startsWith('•') ?
- `<div class="bullet-item"><span class="bullet">•</span>${line.substring(1)}</div>` :
- line
- ).join('\n')} />
- {contribution && <p class="contribution">{contribution}</p>}
- </div>
</div>
- {image ? (
- <div class="image-wrapper" onclick="event.stopPropagation();">
- <div class="image-container">
- <img src={image} alt={imageAlt || title} />
- <div class="image-overlay">
- <span class="zoom-icon">🔍</span>
- </div>
+
+ <div class="description">
+ <div
+ class="bullet-list"
+ set:html={body
+ .split("\n")
+ .map(line =>
+ line.trim().startsWith("•")
+ ? `<div class="bullet-item"><span class="bullet">•</span>${line.substring(1)}</div>`
+ : line
+ )
+ .join("\n")}
+ />
+
+ {contribution && <p class="contribution">{contribution}</p>}
+ </div>
+
+ <div class="actions">
+ <a
+ class="btn"
+ href={href}
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ Source Code
+ </a>
+
+ {project && (
+ <a
+ class="btn primary"
+ href={project}
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ Live Demo
+ </a>
+ )}
+ </div>
+
+ </div>
+
+ {image ? (
+ <div class="image-wrapper" onclick="event.stopPropagation();">
+ <div class="image-container">
+ <img src={image} alt={imageAlt || title} />
+ <div class="image-overlay">
+ <span class="zoom-icon">🔍</span>
</div>
</div>
- ) : (
- <div class="no-image-placeholder">
- <div class="placeholder-content">
- <span class="placeholder-icon">✨</span>
- <span class="placeholder-text">View Project</span>
- </div>
+ </div>
+ ) : (
+ <div class="no-image-placeholder">
+ <div class="placeholder-content">
+ <span class="placeholder-icon">✨</span>
+ <span class="placeholder-text">View Project</span>
</div>
- )}
- </div>
- </a>
+ </div>
+ )}
+
+ </div>
</li>
<style>
@@ -83,126 +120,22 @@ const {
list-style: none;
display: flex;
background-color: #23262d;
- background-image: none;
- background-size: 400%;
border-radius: 12px;
- background-position: 100%;
transition: all 0.3s ease;
- box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1), 0 4px 10px rgba(0, 0, 0, 0.1);
- position: relative;
+ box-shadow:
+ inset 0 0 0 1px rgba(255, 255, 255, 0.1),
+ 0 4px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
min-height: 200px;
height: 100%;
}
- .link-card > a {
- width: 100%;
- text-decoration: none;
- line-height: 1.6;
- color: white;
- background-color: #23262d;
- opacity: 0.95;
- display: block;
- position: relative;
- box-sizing: border-box;
- height: 100%;
- padding: 0;
- }
-
.card-layout {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
padding: 1.75rem;
- min-height: 220px;
- height: 100%;
- }
-
- .image-wrapper {
- width: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 5;
- }
-
- .image-container {
- width: 100%;
- max-width: 350px;
- border-radius: 8px;
- overflow: hidden;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
- background-color: #1a1c21;
- padding: 0.5rem;
- cursor: pointer;
- position: relative;
- transition: all 0.3s ease;
- }
-
- .no-image-placeholder {
- width: 100%;
- height: 180px;
- border-radius: 8px;
- display: flex;
- justify-content: center;
- align-items: center;
- background-color: #1d1f25;
- box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
- transition: all 0.2s ease;
- }
-
- .placeholder-content {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 0.8rem;
- color: rgba(255, 255, 255, 0.6);
- transition: all 0.2s ease;
- }
-
- .placeholder-icon {
- font-size: 2rem;
- }
-
- .placeholder-text {
- font-size: 1rem;
- font-weight: 500;
- }
-
- .image-container img {
- width: 100%;
- object-fit: contain;
- border-radius: 6px;
- transition: transform 0.3s ease;
- max-height: 200px;
- }
-
- .image-overlay {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
height: 100%;
- background: rgba(0, 0, 0, 0.5);
- opacity: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- transition: opacity 0.3s ease;
- }
-
- .zoom-icon {
- color: white;
- font-size: 1.5rem;
- }
-
- .image-container:hover .image-overlay {
- opacity: 1;
- }
-
- .image-container:hover img {
- transform: scale(1.05);
}
.content-container {
@@ -217,6 +150,13 @@ const {
gap: 0.75rem;
}
+ h2 {
+ margin: 0;
+ font-weight: bold;
+ font-size: 1.5rem;
+ line-height: 1.3;
+ }
+
.meta-info {
display: flex;
flex-direction: column;
@@ -233,7 +173,6 @@ const {
width: 10px;
height: 10px;
border-radius: 50%;
- display: inline-block;
}
.language {
@@ -246,60 +185,33 @@ const {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
- margin-top: 0.25rem;
}
.tag {
background-color: #4d4e4e;
- color: #ffffff;
+ color: #fff;
padding: 5px 10px;
font-size: 0.7rem;
font-weight: 600;
border-radius: 20px;
- display: inline-block;
- transition: background-color 0.2s ease;
}
.description {
- flex: 1;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
- h2 {
- margin: 0;
- font-weight: bold;
- font-size: 1.5rem;
- transition: color 0.3s ease;
- line-height: 1.3;
- }
-
- p, .bullet-list {
- margin: 0;
- font-size: 0.95rem;
- line-height: 1.5;
- color: rgba(255, 255, 255, 0.85);
- max-height: none;
- overflow: visible;
- text-overflow: ellipsis;
- }
-
- .bullet-list {
- white-space: pre-line;
- }
-
.bullet-list {
display: flex;
flex-direction: column;
gap: 0.35rem;
+ white-space: pre-line;
}
- /* Style for bullet points in descriptions */
.bullet-item {
position: relative;
padding-left: 1.25rem;
- margin-bottom: 0.1rem;
line-height: 1.4;
}
@@ -311,128 +223,141 @@ const {
}
.contribution {
- margin-top: 0.5rem;
font-style: italic;
color: rgba(255, 255, 255, 0.7);
}
- .link-card:is(:hover, :focus-within) {
- background-position: 0;
- background-image: var(--accent-gradient);
- transform: translateY(-5px);
- box-shadow: 0 12px 25px rgba(0, 0, 0, 0.25);
+ /* ACTION BUTTONS */
+ .actions {
+ display: flex;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+ margin-top: 0.5rem;
}
- .link-card:is(:hover, :focus-within) .image-container:not(:hover) img {
- transform: scale(1.02);
+ .btn {
+ padding: 0.4rem 0.75rem;
+ border-radius: 6px;
+ font-size: 0.85rem;
+ text-decoration: none;
+ color: white;
+ background: #3a3d46;
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ transition: 0.2s ease;
}
- .link-card:is(:hover, :focus-within) .no-image-placeholder .placeholder-content {
- color: rgba(255, 255, 255, 0.9);
+ .btn:hover {
+ transform: translateY(-2px);
+ background: #4a4d57;
}
- .link-card:is(:hover, :focus-within) .tag {
- background-color: #5d5e5e;
+ .btn.primary {
+ background: rgb(var(--accent-light));
+ color: black;
+ font-weight: 600;
}
- .link-card:is(:hover, :focus-within) h2 {
- color: rgb(var(--accent-light));
+ .image-wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
}
- @media (min-width: 768px) {
- .card-layout {
- grid-template-columns: 3fr 2fr;
- align-items: center;
- gap: 2rem;
- }
+ .image-container {
+ max-width: 350px;
+ border-radius: 8px;
+ overflow: hidden;
+ position: relative;
+ background: #1a1c21;
+ padding: 0.5rem;
+ }
- .card-layout:has(.image-wrapper) .content-container {
- grid-column: 1;
- }
+ .image-container img {
+ width: 100%;
+ max-height: 200px;
+ object-fit: contain;
+ border-radius: 6px;
+ transition: transform 0.3s ease;
+ }
- .card-layout .image-wrapper,
- .card-layout .no-image-placeholder {
- grid-column: 2;
- grid-row: 1;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .card-layout .image-container {
- max-width: 100%;
- height: auto;
- }
-
- .card-layout .no-image-placeholder {
- min-height: 200px;
- width: 100%;
- }
+ .image-container:hover img {
+ transform: scale(1.05);
}
- @media (max-width: 767px) {
- .card-layout {
- gap: 1.25rem;
- padding: 1.25rem;
- grid-template-columns: 1fr;
- }
+ .image-overlay {
+ position: absolute;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.5);
+ opacity: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transition: opacity 0.3s ease;
+ }
- .meta-info {
- flex-direction: row;
- justify-content: space-between;
- align-items: flex-start;
- flex-wrap: wrap;
- }
+ .image-container:hover .image-overlay {
+ opacity: 1;
+ }
- .tags-container {
- margin-top: 0.5rem;
- }
+ .zoom-icon {
+ font-size: 1.5rem;
+ color: white;
+ }
- h2 {
- font-size: 1.25rem;
- }
+ .no-image-placeholder {
+ width: 100%;
+ height: 180px;
+ border-radius: 8px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: #1d1f25;
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
+ }
- .image-wrapper,
- .no-image-placeholder {
- order: -1;
- width: 100%;
- margin-bottom: 1rem;
- }
-
- .image-container {
- max-width: 100%;
- margin: 0 auto;
- }
-
- .no-image-placeholder {
- height: 160px;
- }
+ .placeholder-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.8rem;
+ color: rgba(255, 255, 255, 0.6);
}
- @media (max-width: 480px) {
- .meta-info {
- flex-direction: column;
- align-items: flex-start;
- }
+ .placeholder-icon {
+ font-size: 2rem;
+ }
- .card-layout {
- padding: 1.1rem;
- gap: 1rem;
- }
+ .placeholder-text {
+ font-size: 1rem;
+ font-weight: 500;
+ }
+
+ /* HOVER */
+ .link-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 12px 25px rgba(0, 0, 0, 0.25);
+ }
- p {
- font-size: 0.9rem;
- line-height: 1.6;
+ .link-card:hover h2 {
+ color: rgb(var(--accent-light));
+ }
+
+ /* RESPONSIVE */
+ @media (min-width: 768px) {
+ .card-layout {
+ grid-template-columns: 3fr 2fr;
+ align-items: center;
+ gap: 2rem;
}
+ }
- .tags-container {
- margin-top: 0.25rem;
+ @media (max-width: 767px) {
+ .card-layout {
+ padding: 1.25rem;
}
- .tag {
- padding: 4px 8px;
- font-size: 0.65rem;
+ h2 {
+ font-size: 1.25rem;
}
}
</style>
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage