]> danix's work - danix.xyz-2.git/commitdiff
feat: add card component with hover lift and glow effects
authorDanilo M. <redacted>
Thu, 16 Apr 2026 13:27:05 +0000 (15:27 +0200)
committerDanilo M. <redacted>
Thu, 16 Apr 2026 13:27:05 +0000 (15:27 +0200)
- Add .card base component with border, rounded corners, glow shadow
- Add .card:hover state with translateY(-2px) lift and enhanced glow
- Add .card-image, .card-body, .card-title, .card-excerpt, .card-footer semantic classes
- Refactor article-list-item.html to use card component classes
- Rebuild CSS: main.min.css updated

Co-Authored-By: Claude Haiku 4.5 <redacted>
themes/danix-xyz-hacker/assets/css/main.css
themes/danix-xyz-hacker/assets/css/main.min.css
themes/danix-xyz-hacker/layouts/partials/article-list-item.html

index 36e7359888410f8f5a555504654e878a6827a445..e15d7567a22cf330e15e7c911c0ad649c78b2082 100644 (file)
@@ -194,7 +194,146 @@ html.theme-light {
     border-color: var(--border);
   }
 
+  /* Button component styles */
+  .btn {
+    @apply inline-flex items-center justify-center px-4 py-2 rounded font-bold transition-all duration-200 cursor-pointer;
+    background-color: var(--accent);
+    color: #ffffff;
+    border: none;
+    outline: none;
+  }
+
+  .btn:hover:not(:disabled) {
+    opacity: 0.85;
+    transform: translateY(-1px);
+  }
+
+  .btn:focus-visible {
+    @apply ring-2 ring-offset-2;
+    ring-color: var(--accent);
+    ring-offset-color: var(--bg);
+  }
+
+  .btn:active:not(:disabled) {
+    transform: translateY(0);
+    opacity: 0.75;
+  }
+
+  .btn:disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
+  }
+
+  /* Button variants */
+  .btn-primary {
+    background-color: var(--accent);
+    color: #ffffff;
+  }
+
+  .btn-primary:hover:not(:disabled) {
+    background-color: var(--accent);
+  }
+
+  .btn-secondary {
+    background-color: var(--accent2);
+    color: var(--bg);
+    font-weight: 600;
+  }
+
+  .btn-secondary:hover:not(:disabled) {
+    background-color: var(--accent2);
+  }
+
+  .btn-outline {
+    background-color: transparent;
+    color: var(--accent);
+    border: 2px solid var(--accent);
+  }
+
+  .btn-outline:hover:not(:disabled) {
+    background-color: var(--accent);
+    color: #ffffff;
+  }
+
+  /* Button sizes */
+  .btn-sm {
+    @apply px-3 py-1 text-sm;
+  }
+
+  .btn-lg {
+    @apply px-6 py-3 text-lg;
+  }
+
+  /* Icon button (for icons without text) */
+  .btn-icon {
+    @apply p-2 rounded-full inline-flex items-center justify-center;
+    width: 40px;
+    height: 40px;
+  }
+
+  .btn-icon svg {
+    width: 20px;
+    height: 20px;
+  }
+
+  /* Badge base style */
+  .badge {
+    @apply inline-flex items-center px-2.5 py-1 rounded text-sm font-mono font-semibold whitespace-nowrap transition-all duration-200;
+    border: 1px solid;
+  }
+
   /* Article type badge styles */
+  .badge-tech {
+    color: var(--type-tech);
+    background-color: rgba(168, 85, 247, 0.1);
+    border-color: rgba(168, 85, 247, 0.3);
+  }
+
+  .badge-tech:hover {
+    background-color: rgba(168, 85, 247, 0.2);
+  }
+
+  .badge-life {
+    color: var(--type-life);
+    background-color: rgba(245, 158, 11, 0.1);
+    border-color: rgba(245, 158, 11, 0.3);
+  }
+
+  .badge-life:hover {
+    background-color: rgba(245, 158, 11, 0.2);
+  }
+
+  .badge-quote {
+    color: var(--type-quote);
+    background-color: rgba(0, 255, 136, 0.1);
+    border-color: rgba(0, 255, 136, 0.3);
+  }
+
+  .badge-quote:hover {
+    background-color: rgba(0, 255, 136, 0.2);
+  }
+
+  .badge-link {
+    color: var(--type-link);
+    background-color: rgba(56, 189, 248, 0.1);
+    border-color: rgba(56, 189, 248, 0.3);
+  }
+
+  .badge-link:hover {
+    background-color: rgba(56, 189, 248, 0.2);
+  }
+
+  .badge-photo {
+    color: var(--type-photo);
+    background-color: rgba(236, 72, 153, 0.1);
+    border-color: rgba(236, 72, 153, 0.3);
+  }
+
+  .badge-photo:hover {
+    background-color: rgba(236, 72, 153, 0.2);
+  }
+
+  /* Legacy type-* classes for compatibility (with badge styling) */
   .type-tech {
     color: var(--type-tech);
     background-color: rgba(168, 85, 247, 0.1);
@@ -220,6 +359,51 @@ html.theme-light {
     background-color: rgba(236, 72, 153, 0.1);
   }
 
+  /* Card component */
+  .card {
+    @apply border border-border rounded-lg overflow-hidden transition-all duration-200;
+    box-shadow: 0 0 20px var(--accent-glow);
+  }
+
+  .card:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 0 30px var(--accent-glow);
+  }
+
+  .card-image {
+    @apply aspect-video object-cover w-full;
+  }
+
+  .card-body {
+    @apply p-5 md:p-6 space-y-3;
+  }
+
+  .card-title {
+    @apply text-xl font-semibold;
+  }
+
+  .card-excerpt {
+    @apply text-text-dim text-sm line-clamp-3;
+  }
+
+  .card-footer {
+    @apply flex items-center justify-between gap-4;
+  }
+
+  /* Article metadata styling (with icons) */
+  .article-meta {
+    @apply flex flex-wrap items-center gap-4 text-sm text-text-dim;
+  }
+
+  .article-meta-item {
+    @apply flex items-center gap-2;
+  }
+
+  .article-meta-item i {
+    @apply w-4 h-4 flex-shrink-0;
+    color: var(--accent2);
+  }
+
   /* Hero typography with fluid sizing */
   .hero-title {
     font-size: clamp(2rem, 5vw + 1rem, 4.5rem);
index 9c0aadb7119348ca1ad318cc0a6724b1f868a4b8..122dfcbdc3e56936fecfdb8f838a7a2cdd2e4cba 100644 (file)
@@ -1296,8 +1296,182 @@ button,
   border-color: var(--border);
 }
 
+/* Button component styles */
+
+.btn {
+  display: inline-flex;
+  cursor: pointer;
+  align-items: center;
+  justify-content: center;
+  border-radius: 0.25rem;
+  padding-left: 1rem;
+  padding-right: 1rem;
+  padding-top: 0.5rem;
+  padding-bottom: 0.5rem;
+  font-weight: 700;
+  transition-property: all;
+  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+  transition-duration: 200ms;
+  background-color: var(--accent);
+  color: #ffffff;
+  border: none;
+  outline: none;
+}
+
+.btn:hover:not(:disabled) {
+  opacity: 0.85;
+  transform: translateY(-1px);
+}
+
+.btn:focus-visible {
+  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
+  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
+  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
+  --tw-ring-offset-width: 2px;
+  ring-color: var(--accent);
+  ring-offset-color: var(--bg);
+}
+
+.btn:active:not(:disabled) {
+  transform: translateY(0);
+  opacity: 0.75;
+}
+
+.btn:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+}
+
+/* Button variants */
+
+.btn-primary {
+  background-color: var(--accent);
+  color: #ffffff;
+}
+
+.btn-primary:hover:not(:disabled) {
+  background-color: var(--accent);
+}
+
+.btn-outline {
+  background-color: transparent;
+  color: var(--accent);
+  border: 2px solid var(--accent);
+}
+
+.btn-outline:hover:not(:disabled) {
+  background-color: var(--accent);
+  color: #ffffff;
+}
+
+/* Button sizes */
+
+.btn-sm {
+  padding-left: 0.75rem;
+  padding-right: 0.75rem;
+  padding-top: 0.25rem;
+  padding-bottom: 0.25rem;
+  font-size: 0.875rem;
+  line-height: 1.25rem;
+}
+
+.btn-lg {
+  padding-left: 1.5rem;
+  padding-right: 1.5rem;
+  padding-top: 0.75rem;
+  padding-bottom: 0.75rem;
+  font-size: 1.125rem;
+  line-height: 1.75rem;
+}
+
+/* Icon button (for icons without text) */
+
+/* Badge base style */
+
+.badge {
+  display: inline-flex;
+  align-items: center;
+  white-space: nowrap;
+  border-radius: 0.25rem;
+  padding-left: 0.625rem;
+  padding-right: 0.625rem;
+  padding-top: 0.25rem;
+  padding-bottom: 0.25rem;
+  font-family: JetBrains Mono, monospace;
+  font-size: 0.875rem;
+  line-height: 1.25rem;
+  font-weight: 600;
+  transition-property: all;
+  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+  transition-duration: 200ms;
+  border: 1px solid;
+}
+
 /* Article type badge styles */
 
+/* Legacy type-* classes for compatibility (with badge styling) */
+
+/* Card component */
+
+.card {
+  overflow: hidden;
+  border-radius: 0.5rem;
+  border-width: 1px;
+  border-color: var(--border);
+  transition-property: all;
+  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+  transition-duration: 200ms;
+}
+
+article.card.border-border\/30.rounded-lg.overflow-hidden.group.bg-bg {
+  border-color: var(--border);
+  box-shadow: 0 0 20px var(--accent-glow);
+}
+
+article.border.border-border\/30.card.overflow-hidden.group.bg-bg {
+  border-color: var(--border);
+  box-shadow: 0 0 20px var(--accent-glow);
+}
+
+article.border.border-border\/30.rounded-lg.card.group.bg-bg {
+  border-color: var(--border);
+  box-shadow: 0 0 20px var(--accent-glow);
+}
+
+.card {
+  box-shadow: 0 0 20px var(--accent-glow);
+}
+
+.card:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 0 30px var(--accent-glow);
+}
+
+.card-image {
+  aspect-ratio: 16 / 9;
+  width: 100%;
+  -o-object-fit: cover;
+     object-fit: cover;
+}
+
+.card-body > :not([hidden]) ~ :not([hidden]) {
+  --tw-space-y-reverse: 0;
+  margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
+  margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
+}
+
+.card-body {
+  padding: 1.25rem;
+}
+
+@media (min-width: 768px) {
+  .card-body {
+    padding: 1.5rem;
+  }
+}
+
+/* Article metadata styling (with icons) */
+
 /* Hero typography with fluid sizing */
 
 .sr-only {
@@ -1444,6 +1618,10 @@ button,
   margin-bottom: 2rem;
 }
 
+.ml-2 {
+  margin-left: 0.5rem;
+}
+
 .mt-16 {
   margin-top: 4rem;
 }
@@ -1638,12 +1816,6 @@ button,
   margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
 }
 
-.space-y-3 > :not([hidden]) ~ :not([hidden]) {
-  --tw-space-y-reverse: 0;
-  margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
-  margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
-}
-
 .space-y-6 > :not([hidden]) ~ :not([hidden]) {
   --tw-space-y-reverse: 0;
   margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
@@ -1679,10 +1851,6 @@ button,
   border-width: 1px;
 }
 
-.border-2 {
-  border-width: 2px;
-}
-
 .border-4 {
   border-width: 4px;
 }
@@ -1744,10 +1912,6 @@ button,
   padding: 1rem;
 }
 
-.p-5 {
-  padding: 1.25rem;
-}
-
 .p-6 {
   padding: 1.5rem;
 }
@@ -1772,11 +1936,6 @@ button,
   padding-right: 1.5rem;
 }
 
-.px-8 {
-  padding-left: 2rem;
-  padding-right: 2rem;
-}
-
 .py-0\.5 {
   padding-top: 0.125rem;
   padding-bottom: 0.125rem;
@@ -2312,11 +2471,6 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.bg-bg {
   opacity: 0.5;
 }
 
-.group\/cta:hover .group-hover\/cta\:translate-x-1 {
-  --tw-translate-x: 0.25rem;
-  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
-}
-
 .group:hover .group-hover\:scale-105 {
   --tw-scale-x: 1.05;
   --tw-scale-y: 1.05;
@@ -2374,10 +2528,6 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.bg-bg {
     gap: 1.5rem;
   }
 
-  .md\:p-6 {
-    padding: 1.5rem;
-  }
-
   .md\:text-5xl {
     font-size: 3rem;
     line-height: 1;
index 29f8d2b175f565aa78a37d5ea3e46d6d83451a3d..d473e9a95c6934421052637ef3dd98c9701f761f 100644 (file)
   {{ end }}
 {{ end }}
 
-<article class="border border-border/30 rounded-lg overflow-hidden hover:border-accent/50 transition-all duration-200 group bg-bg">
+<article class="card group bg-bg">
   <!-- Thumbnail -->
   {{ if $imageURL }}
   <a href="{{ .RelPermalink }}" class="block overflow-hidden bg-surface/50 relative" tabindex="-1">
     <img
       src="{{ $imageURL }}"
       alt="{{ .Title }}"
-      class="w-full aspect-video object-cover group-hover:scale-105 transition-transform duration-200"
+      class="card-image group-hover:scale-105 transition-transform duration-200"
       loading="lazy"
     />
     <!-- Type badge pill overlay -->
@@ -36,7 +36,7 @@
   {{ end }}
 
   <!-- Content -->
-  <div class="p-5 md:p-6 space-y-3">
+  <div class="card-body">
     <!-- Pinned badge -->
     {{ if .Params.pinned }}
     <div class="inline-flex items-center gap-1 px-2 py-1 rounded text-sm font-semibold" style="color: {{ .Site.Params.secondaryAccent }};">
     <!-- CTA Button -->
     <a
       href="{{ .RelPermalink }}"
-      class="inline-flex items-center gap-2 px-3 py-2 rounded border border-border/30 text-sm font-medium hover:border-accent/50 hover:text-accent transition-colors group/cta"
+      class="btn btn-sm mt-2"
     >
       {{ i18n "readMore" }}
-      <i data-feather="arrow-right" class="w-4 h-4 group-hover/cta:translate-x-1 transition-transform"></i>
+      <i data-feather="arrow-right" class="w-4 h-4 ml-2"></i>
     </a>
   </div>
 </article>