Start of resources section with placeholders

This commit is contained in:
Dan 2026-01-04 13:36:59 +00:00
parent 0788ab8896
commit 8fdc28e7c5
10 changed files with 721 additions and 0 deletions

View file

@ -0,0 +1,12 @@
---
title: "{{ replace .File.ContentBaseName "-" " " | title }}"
date: {{ .Date }}
tags: []
description: ""
icon: ""
demo_url: ""
source_url: ""
draft: false
---
Resource description here.

View file

@ -0,0 +1,549 @@
// Resources Whiteboard Page
.resources-page {
min-height: 100vh;
padding: 2rem 1rem;
@include media-up(md) {
padding: 3rem 2rem;
}
}
.resources-container {
max-width: 1400px;
margin: 0 auto;
}
.whiteboard {
background: linear-gradient(135deg, #f5f5f0 0%, #e8e8dd 100%);
border-radius: 8px;
padding: 3rem 2rem;
box-shadow:
0 10px 40px rgba(0, 0, 0, 0.1),
inset 0 0 100px rgba(0, 0, 0, 0.02);
position: relative;
// Subtle texture overlay
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0, 0, 0, 0.01) 2px, rgba(0, 0, 0, 0.01) 4px),
repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(0, 0, 0, 0.01) 2px, rgba(0, 0, 0, 0.01) 4px);
pointer-events: none;
border-radius: 8px;
}
}
.whiteboard-header {
text-align: center;
margin-bottom: 4rem;
position: relative;
z-index: 1;
h1 {
font-size: 3rem;
color: #2c3e50;
margin-bottom: 1rem;
font-weight: 700;
}
.whiteboard-description {
color: #546e7a;
font-size: 1.1rem;
max-width: 600px;
margin: 0 auto;
}
}
.whiteboard-pins {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 3rem;
position: relative;
z-index: 1;
@include media-up(lg) {
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
}
}
// Resource Pin (Post-it note style)
.resource-pin {
position: relative;
transform: rotate(0deg);
transition: transform 0.3s ease, box-shadow 0.3s ease;
// Random slight rotations for pins
&:nth-child(3n+1) {
transform: rotate(-1deg);
}
&:nth-child(3n+2) {
transform: rotate(1deg);
}
&:nth-child(3n+3) {
transform: rotate(-0.5deg);
}
&:hover {
transform: rotate(0deg) translateY(-5px) !important;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
z-index: 10;
.pin-tack {
transform: translateY(-2px);
}
}
}
// Pin tack at the top
.pin-tack {
position: absolute;
top: -15px;
left: 50%;
transform: translateX(-50%);
width: 20px;
height: 20px;
background: radial-gradient(circle at 30% 30%, #ff6b6b, #c92a2a);
border-radius: 50%;
box-shadow:
0 2px 5px rgba(0, 0, 0, 0.3),
inset -2px -2px 4px rgba(0, 0, 0, 0.2);
z-index: 2;
transition: transform 0.3s ease;
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 6px;
height: 6px;
background: #fff;
border-radius: 50%;
opacity: 0.5;
}
}
// Resource card (the note itself)
.resource-card {
background: linear-gradient(135deg, #fef9c3 0%, #fde68a 100%);
padding: 2rem 1.5rem 1.5rem;
border-radius: 4px;
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.1),
inset 0 -40px 40px -20px rgba(0, 0, 0, 0.05);
min-height: 280px;
display: flex;
flex-direction: column;
gap: 1rem;
// Vary note colors
.resource-pin:nth-child(4n+1) & {
background: linear-gradient(135deg, #fef9c3 0%, #fde68a 100%); // Yellow
}
.resource-pin:nth-child(4n+2) & {
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); // Blue
}
.resource-pin:nth-child(4n+3) & {
background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); // Green
}
.resource-pin:nth-child(4n+4) & {
background: linear-gradient(135deg, #fce7f3 0%, #fbcfe8 100%); // Pink
}
}
.resource-icon {
width: 80px;
height: 80px;
margin: 0 auto 1rem;
position: relative;
// Lavalamp icon
&.lavalamp {
background: linear-gradient(180deg, transparent 0%, transparent 20%, #9333ea 20%, #7c3aed 100%);
border-radius: 10px 10px 40px 40px;
border: 3px solid #6b21a8;
position: relative;
box-shadow: inset 0 0 20px rgba(147, 51, 234, 0.3);
// Lamp base
&::before {
content: '';
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
width: 90%;
height: 12px;
background: #1f2937;
border-radius: 4px;
}
// Lava blobs
&::after {
content: '';
position: absolute;
top: 30%;
left: 30%;
width: 25px;
height: 30px;
background: radial-gradient(circle, #ec4899 0%, #db2777 100%);
border-radius: 50% 50% 40% 60%;
opacity: 0.9;
animation: float-blob 4s ease-in-out infinite;
}
}
// Last.fm stats icon
&.lastfm-stats {
background: linear-gradient(135deg, #d32323 0%, #b71c1c 100%);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
// Equalizer bars
&::before,
&::after {
content: '';
position: absolute;
bottom: 15px;
width: 8px;
background: #fff;
border-radius: 2px;
}
&::before {
left: 20px;
height: 35px;
animation: equalizer-1 0.8s ease-in-out infinite;
}
&::after {
left: 35px;
height: 25px;
animation: equalizer-2 0.8s ease-in-out infinite 0.2s;
}
}
}
// Additional lava blob for lavalamp
.resource-icon.lavalamp {
& > span {
position: absolute;
top: 50%;
right: 25%;
width: 20px;
height: 25px;
background: radial-gradient(circle, #f97316 0%, #ea580c 100%);
border-radius: 60% 40% 50% 50%;
opacity: 0.85;
animation: float-blob-2 3.5s ease-in-out infinite;
}
// Create the blob with a pseudo-element instead
&:not(:empty)::before {
// Override for when we add content
animation: float-blob 4s ease-in-out infinite;
}
}
// Last.fm additional bars
.resource-icon.lastfm-stats {
& > span {
position: absolute;
bottom: 15px;
width: 8px;
background: #fff;
border-radius: 2px;
&:nth-child(1) {
left: 50px;
height: 30px;
animation: equalizer-3 0.8s ease-in-out infinite 0.4s;
}
}
}
@keyframes float-blob {
0%, 100% {
transform: translateY(0) scale(1);
}
50% {
transform: translateY(-15px) scale(1.1);
}
}
@keyframes float-blob-2 {
0%, 100% {
transform: translateY(0) scale(1);
}
50% {
transform: translateY(-20px) scale(0.9);
}
}
@keyframes equalizer-1 {
0%, 100% {
height: 35px;
}
50% {
height: 20px;
}
}
@keyframes equalizer-2 {
0%, 100% {
height: 25px;
}
50% {
height: 40px;
}
}
@keyframes equalizer-3 {
0%, 100% {
height: 30px;
}
50% {
height: 15px;
}
}
.resource-info {
flex: 1;
display: flex;
flex-direction: column;
h2 {
font-size: 1.5rem;
margin: 0 0 0.5rem 0;
color: #1f2937;
font-weight: 600;
a {
color: inherit;
text-decoration: none;
transition: color 0.2s ease;
&:hover {
color: #3b82f6;
}
}
}
}
.resource-description {
color: #4b5563;
font-size: 0.95rem;
line-height: 1.5;
margin: 0 0 1rem 0;
flex: 1;
}
.resource-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1rem;
.tag {
background: rgba(0, 0, 0, 0.1);
padding: 0.25rem 0.75rem;
border-radius: 12px;
font-size: 0.8rem;
color: #374151;
text-decoration: none;
transition: background 0.2s ease;
&:hover {
background: rgba(0, 0, 0, 0.2);
}
}
}
.resource-links {
display: flex;
gap: 0.75rem;
margin-top: auto;
.resource-link {
flex: 1;
padding: 0.5rem 1rem;
text-align: center;
text-decoration: none;
border-radius: 4px;
font-weight: 500;
font-size: 0.9rem;
transition: all 0.2s ease;
&.demo {
background: #3b82f6;
color: #fff;
&:hover {
background: #2563eb;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(59, 130, 246, 0.4);
}
}
&.source {
background: #1f2937;
color: #fff;
&:hover {
background: #111827;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(31, 41, 55, 0.4);
}
}
}
}
// Single Resource Page
.resource-single {
max-width: 900px;
margin: 0 auto;
padding: 2rem 1rem;
@include media-up(md) {
padding: 3rem 2rem;
}
}
.resource-content {
background: #fff;
border-radius: 8px;
padding: 3rem 2rem;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
@include media-up(md) {
padding: 4rem 3rem;
}
}
.resource-header {
text-align: center;
margin-bottom: 3rem;
padding-bottom: 2rem;
border-bottom: 2px solid #e5e7eb;
h1 {
font-size: 2.5rem;
color: #1f2937;
margin: 1rem 0;
@include media-up(md) {
font-size: 3rem;
}
}
.lead {
font-size: 1.25rem;
color: #6b7280;
margin: 1rem 0;
}
}
.resource-icon-large {
width: 120px;
height: 120px;
margin: 0 auto;
&.lavalamp,
&.lastfm-stats {
// Inherit styles from smaller icons
}
}
.resource-body {
color: #374151;
line-height: 1.8;
font-size: 1.1rem;
h2 {
color: #1f2937;
margin-top: 2rem;
margin-bottom: 1rem;
}
p {
margin-bottom: 1rem;
}
code {
background: #f3f4f6;
padding: 0.2rem 0.4rem;
border-radius: 4px;
font-size: 0.9em;
}
pre {
background: #1f2937;
color: #e5e7eb;
padding: 1.5rem;
border-radius: 8px;
overflow-x: auto;
margin: 1.5rem 0;
code {
background: none;
padding: 0;
color: inherit;
}
}
}
.resource-navigation {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 3rem;
padding-top: 2rem;
border-top: 2px solid #e5e7eb;
gap: 1rem;
flex-wrap: wrap;
.nav-link {
padding: 0.75rem 1.5rem;
background: #f3f4f6;
color: #374151;
text-decoration: none;
border-radius: 6px;
font-weight: 500;
transition: all 0.2s ease;
&:hover {
background: #e5e7eb;
transform: translateY(-2px);
}
&.back {
background: #3b82f6;
color: #fff;
&:hover {
background: #2563eb;
}
}
&.prev,
&.next {
flex: 1;
min-width: 150px;
}
}
}

View file

@ -23,6 +23,7 @@
@import "pages/now"; @import "pages/now";
@import "pages/blog"; @import "pages/blog";
@import "pages/media"; @import "pages/media";
@import "pages/resources";
@import url("https://fonts.bunny.net/css2?family=Caveat:wght@400..700&family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&family=Neonderthaw&display=swap"); @import url("https://fonts.bunny.net/css2?family=Caveat:wght@400..700&family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&family=Neonderthaw&display=swap");

View file

@ -52,6 +52,10 @@ menu:
name: gear & edc name: gear & edc
url: /gear/ url: /gear/
weight: 10 weight: 10
- identifier: resources
name: resources
url: /resources/
weight: 12
- identifier: archives - identifier: archives
name: archives name: archives
url: /archives/ url: /archives/

View file

@ -0,0 +1,7 @@
---
title: "Resources"
description: "A collection of useful tools, scripts, and experiments"
draft: false
---
Welcome to my whiteboard of resources. Here you'll find various tools, scripts, and experiments I've built and wanted to share.

View file

@ -0,0 +1,34 @@
---
title: "Last.fm Weekly Stats Script"
date: 2026-01-04
tags: ["javascript", "api", "last.fm"]
description: "Fetch and display your weekly listening stats from Last.fm"
icon: "lastfm-stats"
demo_url: ""
source_url: ""
draft: false
---
A handy script for pulling your weekly listening statistics from Last.fm's API. Perfect for tracking your music habits and creating weekly listening reports.
## Features
- Fetches weekly top tracks from Last.fm
- Displays track count and listening time
- Formats data in a clean, readable format
- Easy to integrate into blogs or dashboards
## Setup
1. Get your Last.fm API key from [Last.fm API](https://www.last.fm/api)
2. Configure your username in the script
3. Run the script to fetch your weekly stats
## Output
The script returns your top tracks for the week, including:
- Track name and artist
- Play count
- Listening duration
Great for weekly blog posts or personal music tracking!

View file

@ -0,0 +1,27 @@
---
title: "HTML/CSS Lavalamp"
date: 2026-01-04
tags: ["css", "html", "animation"]
description: "A pure CSS lavalamp animation with floating blobs"
icon: "lavalamp"
demo_url: ""
source_url: ""
draft: false
---
A mesmerizing lavalamp effect created entirely with HTML and CSS. Features smooth floating animations and gradient blobs that rise and fall like a classic lava lamp.
## Features
- Pure CSS animation (no JavaScript required)
- Customizable colors and blob shapes
- Smooth, organic floating motion
- Responsive design
## How It Works
The animation uses CSS keyframes to create the illusion of blobs floating up and down. Multiple blob elements with different animation delays create a realistic lava lamp effect.
## Usage
Simply copy the HTML and CSS into your project. You can customize the colors by changing the gradient values and adjust the animation speed by modifying the animation duration.

View file

@ -0,0 +1,20 @@
{{ define "main" }}
<div class="resources-page">
<div class="resources-container">
<div class="whiteboard">
<div class="whiteboard-header">
<h1>{{ .Title }}</h1>
<div class="whiteboard-description">
{{ .Content }}
</div>
</div>
<div class="whiteboard-pins">
{{ range .Pages }}
{{ .Render "summary" }}
{{ end }}
</div>
</div>
</div>
</div>
{{ end }}

View file

@ -0,0 +1,42 @@
{{ define "main" }}
<div class="resource-single">
<article class="resource-content">
<header class="resource-header">
<div class="resource-icon-large {{ .Params.icon }}"></div>
<h1>{{ .Title }}</h1>
{{ if .Params.description }}
<p class="lead">{{ .Params.description }}</p>
{{ end }}
{{ if .Params.tags }}
<div class="resource-tags">
{{ range .Params.tags }}
<a href="{{ printf "/tags/%s/" (. | urlize) }}" class="tag">{{ . }}</a>
{{ end }}
</div>
{{ end }}
<div class="resource-links">
{{ if .Params.demo_url }}
<a href="{{ .Params.demo_url }}" class="resource-link demo" target="_blank">View Demo</a>
{{ end }}
{{ if .Params.source_url }}
<a href="{{ .Params.source_url }}" class="resource-link source" target="_blank">View Source</a>
{{ end }}
</div>
</header>
<div class="resource-body">
{{ .Content }}
</div>
<nav class="resource-navigation">
{{ with .PrevInSection }}
<a href="{{ .Permalink }}" class="nav-link prev">← {{ .Title }}</a>
{{ end }}
<a href="/resources/" class="nav-link back">Back to Resources</a>
{{ with .NextInSection }}
<a href="{{ .Permalink }}" class="nav-link next">{{ .Title }} →</a>
{{ end }}
</nav>
</article>
</div>
{{ end }}

View file

@ -0,0 +1,25 @@
<div class="resource-pin" data-icon="{{ .Params.icon }}">
<div class="pin-tack"></div>
<div class="resource-card">
<div class="resource-icon {{ .Params.icon }}"></div>
<div class="resource-info">
<h2><a href="{{ .Permalink }}">{{ .Title }}</a></h2>
<p class="resource-description">{{ .Params.description }}</p>
{{ if .Params.tags }}
<div class="resource-tags">
{{ range .Params.tags }}
<span class="tag">{{ . }}</span>
{{ end }}
</div>
{{ end }}
<div class="resource-links">
{{ if .Params.demo_url }}
<a href="{{ .Params.demo_url }}" class="resource-link demo" target="_blank">Demo</a>
{{ end }}
{{ if .Params.source_url }}
<a href="{{ .Params.source_url }}" class="resource-link source" target="_blank">Source</a>
{{ end }}
</div>
</div>
</div>
</div>