Files for my website bwc9876.dev
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at e3d7649e82ed20e1e1479ea3d89f13bc44e8e404 141 lines 2.8 kB view raw
1--- 2import { Image } from "astro:assets"; 3import backdrop from "@assets/backdrop.webp"; 4import type { CollectionEntry } from "astro:content"; 5 6export interface Props { 7 project: CollectionEntry<"projects">; 8} 9 10const stringToNumber = (str: string, seed = 3) => { 11 let h1 = 0xdeadbeef ^ seed, 12 h2 = 0x41c6ce57 ^ seed; 13 for (let i = 0, ch; i < str.length; i++) { 14 ch = str.charCodeAt(i); 15 h1 = Math.imul(h1 ^ ch, 2654435761); 16 h2 = Math.imul(h2 ^ ch, 1597334677); 17 } 18 h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909); 19 h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909); 20 return 4294967296 * (2097151 & h2) + (h1 >>> 0); 21}; 22 23const getHueFromText = (text: string): string => `hue-rotate(${stringToNumber(text) % 360}deg)`; 24 25const { project } = Astro.props; 26--- 27 28<a href={`/projects/${project.id}/`}> 29 <article> 30 <div> 31 <Image 32 class="thumbnail" 33 transition:name={`project-img-${project.id}`} 34 src={project.data.image} 35 densities={[1, 1.5, 2]} 36 width="400" 37 alt="" 38 /> 39 <Image 40 style={{ filter: getHueFromText(project.id) }} 41 class="backdrop" 42 aria-hidden="true" 43 role="presentation" 44 src={backdrop} 45 alt="Backdrop" 46 /> 47 </div> 48 <div> 49 <h3 class="project-name">{project.data.name}</h3> 50 <small>{project.data.tags.join(", ")}</small> 51 <p>{project.data.summary}</p> 52 </div> 53 </article> 54</a> 55 56<style> 57 :not(.project-name) { 58 text-decoration: none !important; 59 } 60 61 small { 62 margin: 0 var(--1); 63 display: block; 64 text-wrap: balance; 65 } 66 67 h3 { 68 margin: var(--1) var(--1) 0 var(--1); 69 } 70 71 p { 72 margin: var(--1); 73 } 74 75 article { 76 display: flex; 77 flex-direction: column; 78 height: 100%; 79 color: var(--text); 80 background-color: var(--secondary); 81 border-radius: 5px; 82 } 83 84 a { 85 transition: transform cubic-bezier(0.68, -0.55, 0.27, 1.55) 0.4s; 86 } 87 88 a:hover { 89 transform: translateY(calc(var(--1) * -1)); 90 } 91 92 a:hover img { 93 transform: scale(1.06); 94 } 95 96 span { 97 flex-grow: 1; 98 text-align: center; 99 display: flex; 100 align-items: center; 101 justify-content: center; 102 } 103 104 div:first-child { 105 display: flex; 106 flex-direction: column; 107 align-items: center; 108 } 109 110 div { 111 overflow: hidden; 112 position: relative; 113 } 114 115 img, 116 div:first-child { 117 border-top-left-radius: 5px; 118 border-top-right-radius: 5px; 119 } 120 121 img { 122 position: relative; 123 object-fit: contain; 124 width: 100%; 125 height: auto; 126 transition: transform ease-in-out 0.4s; 127 height: var(--14); 128 } 129 130 img.thumbnail { 131 z-index: 2; 132 } 133 134 img.backdrop { 135 position: absolute; 136 transform: scale(1.1); 137 inset: 0; 138 object-fit: cover; 139 filter: blur(6px); 140 } 141</style>