closes #1 by adding headshot feature
This commit is contained in:
		| @@ -16,8 +16,45 @@ body { | ||||
|   font-family: $font-garamond; | ||||
| } | ||||
|  | ||||
| .wompum-radial-grid { | ||||
|   @apply absolute w-full h-full top-0 left-0; | ||||
| } | ||||
|  | ||||
| .narrator-image-container { | ||||
|   @apply relative; | ||||
|  | ||||
|   .wompum-radial-grid { | ||||
|     @apply absolute inset-0 w-full h-full; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .narrator-headshot { | ||||
|   @apply w-full rounded-full object-cover relative z-10 border-2 border-white; | ||||
|   aspect-ratio: 1; | ||||
| } | ||||
|  | ||||
| .interviewer-question { | ||||
|   font-style: italic; | ||||
|   color: #444; | ||||
|   margin-left: -1rem; | ||||
| } | ||||
|  | ||||
| // Narrator Image Component | ||||
| .narrator { | ||||
|   &__container { | ||||
|     @apply relative; | ||||
|   } | ||||
|  | ||||
|   &__frame { | ||||
|     @apply relative p-4; | ||||
|   } | ||||
|  | ||||
|   &__image { | ||||
|     @apply w-full rounded-full object-cover relative z-10 bg-white text-center border-4 border-white grid place-items-center; | ||||
|     aspect-ratio: 1; | ||||
|   } | ||||
|  | ||||
|   &__wompum { | ||||
|     @apply absolute inset-0 w-full h-full; | ||||
|   } | ||||
| } | ||||
| @@ -7,6 +7,7 @@ approved: 2025-03-20 | ||||
| summary: "Drawing on many ancestral traditions and the experience of her own body, Asia Dorsey learns and teaches the pattern language of a healthy gut." | ||||
| location: "Denver CO" | ||||
| tags: [ancestors, food, health, indigeneity] | ||||
| headshot: "/headshots/placeholder-headshot.png" | ||||
| links: | ||||
|   - text: "Bugs Bones & Botany" | ||||
|     url: "https://www.bonesbugsandbotany.com" | ||||
|   | ||||
| @@ -6,6 +6,7 @@ date: 2024-10-10 | ||||
| approved: 2024-10-11 | ||||
| summary: "After widespread resistance to codes of conduct in open-source software communities, Coraline Ada Ehmke's Contributor Covenant became the most popular code of conduct in the ecosystem." | ||||
| location: "Chicago, USA" | ||||
| headshot: "/headshots/placeholder-headshot.png" | ||||
| tags: [code of conduct, dispute resolution, gender, open source, organizations, software] | ||||
| --- | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ date: 2024-10-29 | ||||
| approved: 2024-12-16 | ||||
| summary: "Good Market is a digital commons for enterprises that prioritize people and the planet over profit. It enables communities to set and enforce their own standards for doing business." | ||||
| location: "Sri Lanka / United States" | ||||
| headshot: "/headshots/placeholder-headshot.png" | ||||
| tags: [economics, organizations, ecology, standards] | ||||
| --- | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ date: 2025-02-04 | ||||
| approved: 2025-02-11 | ||||
| summary: "Constructed languages, or conlangs, are the basis of a hobby, a science, and a community that now occupies a small corner of the entertainment industry." | ||||
| location: "Wellington, NZ" | ||||
| headshot: "/headshots/placeholder-headshot.png" | ||||
| tags: [fiction, gender, language, open source, software] | ||||
| --- | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ date: 2024-12-13 | ||||
| approved: 2025-03-04 | ||||
| summary: "A diplomat for Bangladesh describes the role of protocol in high-profile international visits and treaty negotiations." | ||||
| location: "Dhaka, Bangladesh" | ||||
| headshot: "/headshots/placeholder-headshot.png" | ||||
| tags: [diplomacy, government, friendship] | ||||
| --- | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ date: 2024-12-06 | ||||
| approved: 2025-04-01 | ||||
| summary: "A career-long journey to build online social networks that cannot be controlled by a single company, culminating with the ActivityPub standard." | ||||
| location: "Montreal, Canada" | ||||
| headshot: "/headshots/placeholder-headshot.png" | ||||
| links: | ||||
|   - text: Website | ||||
|     url: https://evanp.me/ | ||||
|   | ||||
| @@ -6,6 +6,7 @@ date: 2024-11-04 | ||||
| approved: 2024-12-02 | ||||
| summary: "As a sport often played with no referees, ultimate frisbee has developed a strong set of norms for addressing conflict and self-governing." | ||||
| location: "East Greenbush, NY USA" | ||||
| headshot: "/headshots/placeholder-headshot.png" | ||||
| tags: [frisbee, sports, organizations, dispute resolution] | ||||
| --- | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,13 @@ | ||||
|  | ||||
|       <div class="flex gap-4"> | ||||
|         <aside class="lg:sticky lg:top-0 lg:h-screen lg:overflow-y-auto lg:w-1/3 p-4 font-iosevka"> | ||||
|           {{ if .Params.headshot }} | ||||
|           <div class="narrator__container w-48 mb-2" data-text="{{ .Params.narrator }}"> | ||||
|             <div class="narrator__frame"> | ||||
|               <img src="{{ .Params.headshot }}" alt="Photo of {{ .Params.narrator }}" class="narrator__image" loading="lazy"> | ||||
|             </div> | ||||
|           </div> | ||||
|           {{ end }} | ||||
|           <p><strong>Date:</strong> <time datetime="{{ .Date.Format " 2006-01-02" }}">{{ .Date.Format "January 2, 2006" }}</time></p> | ||||
|           <p><strong>Narrator:</strong> <a href="{{ "/narrator/" | relLangURL }}{{ .Params.narrator | urlize }}">{{ .Params.narrator }}</a></p> | ||||
|           <p><strong>Facilitator:</strong> <a href="{{ "/facilitator/" | relLangURL }}{{ .Params.facilitator | urlize }}">{{ .Params.facilitator }}</a></p> | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								static/headshots/placeholder-headshot.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/headshots/placeholder-headshot.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.9 MiB | 
| @@ -152,6 +152,93 @@ class ArticleGrid extends WompumGrid { | ||||
|     } | ||||
| } | ||||
|  | ||||
| class RadialWompumGrid { | ||||
|     constructor(element, size = 10) { | ||||
|         this.element = element; // Remove .parentElement | ||||
|         this.segments = size; | ||||
|         this.colorCalculator = new ColorCalculator(); | ||||
|                 this.sigil = Sigil.generate(this.element.dataset.text || ''); | ||||
|     } | ||||
|  | ||||
|     createSegment(index) { | ||||
|         const angle = (360 / this.segments); | ||||
|         // Add a small gap by reducing the arc angle | ||||
|         const gap = 2; // degrees of gap | ||||
|         const startAngle = (index * angle) + (gap / 2); | ||||
|         const endAngle = ((index + 1) * angle) - (gap / 2); | ||||
|         const outerRadius = 50; | ||||
|         const innerRadius = 0; | ||||
|  | ||||
|         const start = this.polarToCartesian(startAngle, outerRadius); | ||||
|         const end = this.polarToCartesian(endAngle, outerRadius); | ||||
|         const innerStart = this.polarToCartesian(startAngle, innerRadius); | ||||
|         const innerEnd = this.polarToCartesian(endAngle, innerRadius); | ||||
|  | ||||
|         const largeArcFlag = (angle - gap) > 180 ? 1 : 0; | ||||
|  | ||||
|         const d = [ | ||||
|             `M ${start.x} ${start.y}`, | ||||
|             `A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}`, | ||||
|             `L ${innerEnd.x} ${innerEnd.y}`, | ||||
|             `A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${innerStart.x} ${innerStart.y}`, | ||||
|             'Z' | ||||
|         ].join(' '); | ||||
|  | ||||
|         const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | ||||
|         path.setAttribute('d', d); | ||||
|          | ||||
|         const sigilDigit = this.getSigilDigit(index); | ||||
|         // Pass empty array for influences since we don't need adjacent segments | ||||
|         const color = this.colorCalculator.getColor(sigilDigit, []); | ||||
|         path.setAttribute('fill', color); | ||||
|          | ||||
|         return path; | ||||
|     } | ||||
|  | ||||
|     polarToCartesian(angle, radius) { | ||||
|         const radian = (angle - 90) * Math.PI / 180.0; | ||||
|         return { | ||||
|             x: 50 + (radius * Math.cos(radian)), | ||||
|             y: 50 + (radius * Math.sin(radian)) | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     getSigilDigit(position) { | ||||
|         if (!this.sigil || !this.sigil.length) return 0; | ||||
|         return this.sigil[position % this.sigil.length]; | ||||
|     } | ||||
|  | ||||
|     getInfluences(index) { | ||||
|         const prev = (index - 1 + this.segments) % this.segments; | ||||
|         const next = (index + 1) % this.segments; | ||||
|         return [ | ||||
|             this.getSigilDigit(prev), | ||||
|             this.getSigilDigit(next) | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     createSVG() { | ||||
|         const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | ||||
|         svg.setAttribute('viewBox', '0 0 100 100'); | ||||
|         svg.setAttribute('class', 'wompum-radial-grid'); | ||||
|  | ||||
|         for (let i = 0; i < this.segments; i++) { | ||||
|             svg.appendChild(this.createSegment(i)); | ||||
|         } | ||||
|  | ||||
|         return svg; | ||||
|     } | ||||
|  | ||||
|     init() { | ||||
|         if (!this.sigil || !this.sigil.length) { | ||||
|             console.error('No sigil generated from text:', this.element.getAttribute('data-text')); | ||||
|             return; | ||||
|         } | ||||
|         const svg = this.createSVG(); | ||||
|         this.element.insertBefore(svg, this.element.firstChild); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Initialize grids | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|     // Initialize basic grids | ||||
| @@ -172,4 +259,10 @@ document.addEventListener('DOMContentLoaded', () => { | ||||
|         const grid = new ArticleGrid(element, metadata); | ||||
|         grid.init(); | ||||
|     }); | ||||
|  | ||||
|     // Initialize radial grids for profile images | ||||
|     document.querySelectorAll('.narrator__container').forEach(element => { | ||||
|         const grid = new RadialWompumGrid(element); | ||||
|         grid.init(); | ||||
|     }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user