this repo has no description
0
fork

Configure Feed

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

Add configuration options

- size/position options for posts can be configured
- posts are now slightly offset
- posts will sway slightly (respects reduced motion)
- posts with focus will be frozen with a coloured shadow when focused
- add <main> for accessibility

+165 -32
+149 -24
src/components/blog/post.astro
··· 15 15 const img = data.image.src.match(/.*(?=\.png)/gm); 16 16 if (img === null) return; 17 17 const { default: image } = await import(`../../posts/assets/${img[0]}.png`); 18 + 19 + const positions: [number, number] = [Math.random(), Math.random()]; 20 + const offsets: [[number, number], [number, number], [number, number]] = [ 21 + [ 22 + Math.random() * blog.post.drift[0] - blog.post.drift[0] / 2, 23 + Math.random() * 0.5 * blog.post.drift[1] - blog.post.drift[1] / 2, 24 + ], 25 + [ 26 + Math.random() * blog.post.drift[0] - blog.post.drift[0] / 2, 27 + Math.random() * 0.5 * blog.post.drift[1] - blog.post.drift[1] / 2, 28 + ], 29 + [ 30 + Math.random() * blog.post.drift[0] - blog.post.drift[0] / 2, 31 + Math.random() * 0.5 * blog.post.drift[1] - blog.post.drift[1] / 2, 32 + ], 33 + ]; 18 34 --- 19 35 36 + <a 37 + style={`--colour: ${data.colour}; 38 + --layer: ${layer}; 39 + 40 + /* generated */ 41 + 42 + --x-offset: ${positions[0]}; 43 + --y-offset: ${positions[1]}; 44 + 45 + ${offsets.map((x, i) => `--x-offset-${i}: ${x[0]}; --y-offset-${i}: ${x[1]};`).join("\n")} 46 + 47 + --timing: ${ 48 + blog.post.timing.scale + 49 + Math.random() * blog.post.timing.leeway - 50 + blog.post.timing.leeway / 2 51 + }s; 52 + 53 + /* config */ 54 + 55 + --y-leeway: ${blog.post.yLeeway}rem; 56 + ${blog.post.size[0] ? `--width: ${blog.post.size[0]}rem;` : ""} 57 + ${blog.post.size[1] ? `--height: ${blog.post.size[1]}rem;` : ""} 58 + --y-gap: ${blog.post.yGap}rem; 59 + --x-padding: ${blog.post.xPadding}rem; 60 + `} 61 + href={`/blog/${id}/`} 62 + > 63 + <Image src={image} alt={data.image.alt} /> 64 + ({id}) {data.title} 65 + <br /> 66 + {data.date.toLocaleString()} 67 + </a> 68 + 20 69 <style> 70 + @property --x-offset-0 { 71 + syntax: "<number>"; 72 + inherits: false; 73 + initial-value: 0; 74 + } 75 + 76 + @property --x-offset-1 { 77 + syntax: "<number>"; 78 + inherits: false; 79 + initial-value: 0; 80 + } 81 + 82 + @property --x-offset-2 { 83 + syntax: "<number>"; 84 + inherits: false; 85 + initial-value: 0; 86 + } 87 + 88 + @property --y-offset-0 { 89 + syntax: "<number>"; 90 + inherits: false; 91 + initial-value: 0; 92 + } 93 + 94 + @property --y-offset-1 { 95 + syntax: "<number>"; 96 + inherits: false; 97 + initial-value: 0; 98 + } 99 + 100 + @property --y-offset-2 { 101 + syntax: "<number>"; 102 + inherits: false; 103 + initial-value: 0; 104 + } 105 + 106 + @keyframes bob { 107 + 0%, 108 + 100% { 109 + top: calc(var(--y-leeway) * 2 * var(--y-offset) - var(--y-leeway)); 110 + left: calc( 111 + (100svw - var(--width) - 2 * var(--x-padding)) * var(--x-offset) + 112 + var(--x-padding) 113 + ); 114 + } 115 + 116 + 25% { 117 + top: calc( 118 + var(--y-leeway) * 2 * (var(--y-offset) + var(--y-offset-0)) - 119 + var(--y-leeway) 120 + ); 121 + left: calc( 122 + (100svw - var(--width) - 2 * var(--x-padding)) * 123 + (var(--x-offset) + var(--x-offset-0)) + var(--x-padding) 124 + ); 125 + } 126 + 127 + 50% { 128 + top: calc( 129 + var(--y-leeway) * 2 * (var(--y-offset) + var(--y-offset-1)) - 130 + var(--y-leeway) 131 + ); 132 + left: calc( 133 + (100svw - var(--width) - 2 * var(--x-padding)) * 134 + (var(--x-offset) + var(--x-offset-1)) + var(--x-padding) 135 + ); 136 + } 137 + 138 + 75% { 139 + top: calc( 140 + var(--y-leeway) * 2 * (var(--y-offset) + var(--y-offset-2)) - 141 + var(--y-leeway) 142 + ); 143 + left: calc( 144 + (100svw - var(--width) - 2 * var(--x-padding)) * 145 + (var(--x-offset) + var(--x-offset-2)) + var(--x-padding) 146 + ); 147 + } 148 + } 149 + 21 150 a { 22 151 width: var(--width); 23 152 height: var(--height); ··· 26 155 border-radius: 2.5rem; 27 156 padding: 1rem; 28 157 display: block; 29 - box-shadow: 0 0 7.5rem #00000080; 30 - margin-bottom: var(--gap); 158 + --box-shadow-colour: #00000080; 159 + box-shadow: 0 0 7.5rem var(--box-shadow-colour); 160 + margin-bottom: var(--y-gap); 31 161 32 - position: relative; 33 - left: calc((100svw - 30rem) * var(--x-offset)); 34 - 162 + /* default, overridden by reduced motion */ 35 163 top: calc(var(--y-leeway) * 2 * var(--y-offset) - var(--y-leeway)); 164 + left: calc( 165 + (100svw - var(--width) - 2 * var(--x-padding)) * var(--x-offset) + 166 + var(--x-padding) 167 + ); 36 168 169 + @media (prefers-reduced-motion: no-preference) { 170 + animation: infinite var(--timing) bob; 171 + } 172 + 173 + position: relative; 37 174 z-index: var(--layer); 38 175 176 + &:focus-visible, 177 + &:active { 178 + animation-play-state: paused; 179 + --box-shadow-colour: var(--colour); 180 + outline: none; 181 + } 182 + 39 183 & > img { 40 184 border-radius: 1.5rem; 41 185 ··· 45 189 } 46 190 } 47 191 </style> 48 - 49 - <a 50 - style={`--colour: ${data.colour}; 51 - --layer: ${layer}; 52 - --x-offset: ${Math.random()}; 53 - --y-offset: ${Math.random()}; 54 - 55 - --y-leeway: ${blog.post.yLeeway}rem; 56 - ${blog.post.size[0] ? `--width: ${blog.post.size[0]}rem;` : ""} 57 - ${blog.post.size[1] ? `--height: ${blog.post.size[1]}rem;` : ""} 58 - --gap: ${blog.post.gap}rem; 59 - `} 60 - href={`/blog/${id}/`} 61 - > 62 - <Image src={image} alt={data.image.alt} /> 63 - ({id}) {data.title} 64 - <br /> 65 - {data.date.toLocaleString()} 66 - </a>
+7 -1
src/config.ts
··· 2 2 post: { 3 3 yLeeway: 5, 4 4 size: [30, undefined], 5 - gap: 10 5 + yGap: 10, 6 + xPadding: 15, 7 + drift: [0.1, 1], 8 + timing: { 9 + scale: 15, 10 + leeway: 5, 11 + }, 6 12 }, 7 13 };
+9 -7
src/pages/blog/index.astro
··· 19 19 </style> 20 20 21 21 <Base title="Blog"> 22 - <h1>Blog</h1> 23 - <a href="/rss.xml" aria-label="Rss Feed"><Rss width={64} height={64} /></a> 24 - { 25 - posts.map((x, i) => ( 26 - <Post id={x.id} data={x.data} layer={posts.length - i} /> 27 - )) 28 - } 22 + <main> 23 + <h1>Blog</h1> 24 + <a href="/rss.xml" aria-label="Rss Feed"><Rss width={64} height={64} /></a> 25 + { 26 + posts.map((x, i) => ( 27 + <Post id={x.id} data={x.data} layer={posts.length - i} /> 28 + )) 29 + } 30 + </main> 29 31 </Base>