feat: add sample content and styling

This commit is contained in:
log101 2024-05-06 22:36:07 +03:00
parent 5fa72ed63e
commit f68fc049ea
11 changed files with 450 additions and 345 deletions

1
.gitignore vendored
View File

@ -22,3 +22,4 @@ pnpm-debug.log*
# jetbrains setting folder # jetbrains setting folder
.idea/ .idea/
TODO

View File

@ -18,7 +18,7 @@
<div> <div>
<ul class="nav-links undecorated-anchor"> <ul class="nav-links undecorated-anchor">
<li><a href="#">Teknik</a></li> <li><a href="#">Teknik</a></li>
<li><a href="#">Felsefi</a></li> <li><a href="#">Fikir</a></li>
<li><a href="#">Babür'ün Serüvenleri</a></li> <li><a href="#">Babür'ün Serüvenleri</a></li>
<li><a href="#">Ansiklopedi</a></li> <li><a href="#">Ansiklopedi</a></li>
</ul> </ul>

View File

@ -1,6 +1,8 @@
--- ---
title: "Atatürk ve Demokratik Türkiye" title: "Atatürk ve Demokratik Türkiye"
summary: Halil İnalcık'ın kaleminden Türkiye Cumhuriyet'nin kuruluş hikayesi ve inkılapların toplumdaki akisleri. summary: Halil İnalcık'ın kaleminden Türkiye Cumhuriyet'nin kuruluş hikayesi ve Atatürk inkılaplarının toplumdaki akisleri.
category: Kitap İncelemesi
date: 2024-03-15
tags: tags:
- kitap - kitap
- atatürk - atatürk

View File

@ -1,6 +1,8 @@
--- ---
title: "5. Bölüm: Kaptan ile Mücadele" title: "5. Bölüm: Kaptan ile Mücadele"
summary: "Babür'ün önünde yalnızca tek bir engel kalmıştır: Komutan." summary: "Babür'ün önünde yalnızca tek bir engel kalmıştır: Komutan."
category: Öykü
date: 2024-03-03
tags: tags:
- babür - babür
--- ---

View File

@ -1,6 +1,8 @@
--- ---
title: "Bir Komponentin Serüveni: Astro" title: "Bir Komponentin Serüveni: Astro"
summary: Yazdığınız komponentlere ne olur? Bu yazıda Astro komponentlerinin serüvenlerin bir göz atıyoruz! summary: Yazdığınız komponentlere ne olur? Bu yazıda Astro komponentlerinin serüvenlerin bir göz atıyoruz!
category: Teknik Yazı
date: 2024-04-01
tags: tags:
- astro - astro
- javascript - javascript

View File

@ -1,15 +1,16 @@
// 1. Import utilities from `astro:content`
import { z, defineCollection } from "astro:content"; import { z, defineCollection } from "astro:content";
// 2. Define your collection(s)
const teknikCollection = defineCollection({ const blogCollection = defineCollection({
type: "content", type: "content",
schema: z.object({ schema: z.object({
title: z.string(), title: z.string(),
summary: z.string(),
tags: z.array(z.string()), tags: z.array(z.string()),
summary: z.string(),
date: z.date(),
category: z.enum(["Kitap İncelemesi", "Teknik Yazı", "Öykü"]),
}), }),
}); });
export const collections = { export const collections = {
teknik: teknikCollection, blog: blogCollection,
}; };

View File

@ -23,11 +23,16 @@ const { title } = Astro.props;
<style is:global> <style is:global>
:root { :root {
--h1-desktop: 3.815rem; --h1-desktop: 3.815rem;
--h2-desktop: 3.052rem;
--h3-desktop: 2.441rem;
--h4-desktop: 1.953rem;
--h5-desktop: 1.563rem;
--h6-desktop: 1.25rem; --h6-desktop: 1.25rem;
--small-desktop: 0.8rem; --small-desktop: 0.8rem;
font-size: 18px; font-size: 18px;
font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS",
sans-serif; sans-serif;
background-color: #f5fffa;
} }
body { body {
display: flex; display: flex;

View File

@ -2,17 +2,37 @@
import Header from "../components/Header.astro"; import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro"; import Footer from "../components/Footer.astro";
import Layout from "../layouts/Layout.astro"; import Layout from "../layouts/Layout.astro";
import "../styles/gol.css"; import "../styles/header.css";
import "../styles/home.css";
import { getCollection, getEntry } from 'astro:content'; import { getCollection, getEntry } from "astro:content";
const allTeknikPosts = await getCollection('teknik') const allTeknikPosts = await getCollection("blog");
--- ---
<Layout title="log101"> <Layout title="log101">
<div class="container"> <div class="container">
<Header /> <Header />
{allTeknikPosts.map(p => <p>{p.data.summary}</p>)} <div class="posts">
{
allTeknikPosts
.sort((p1, p2) => p2.data.date.getTime() - p1.data.date.getTime())
.map((p) => (
<div class="post">
<p class="post-category">{p.data.category}</p>
<h4 class="post-title">{p.data.title}</h4>
<p class="post-date">
{p.data.date.toLocaleDateString("tr-TR", {
day: "numeric",
month: "long",
year: "numeric",
})}
</p>
<p class="post-summary">{p.data.summary}</p>
</div>
))
}
</div>
<Footer /> <Footer />
</div> </div>
</Layout> </Layout>

View File

@ -1,392 +1,418 @@
import { heavyWeightSpaceshipCell } from './utils' import { heavyWeightSpaceshipCell } from "./utils";
/* /*
A wrapper for an HTML <canvas> based visualizatiuon of Conway's Game of Life. A wrapper for an HTML <canvas> based visualizatiuon of Conway's Game of Life.
*/ */
export default class ConwaySimulator { export default class ConwaySimulator {
/*
/*
Create a new simulation. A simulation is comprised of a Create a new simulation. A simulation is comprised of a
2D data grid (rows-by-cols) of ConwayPixels, a canvas element, 2D data grid (rows-by-cols) of ConwayPixels, a canvas element,
and a canvas context. and a canvas context.
*/ */
constructor(rows, cols, pixelSize, interRoundDelay) { constructor(rows, cols, pixelSize, interRoundDelay) {
this.rows = rows; this.rows = rows;
this.cols = cols; this.cols = cols;
this.pixelSize = pixelSize; this.pixelSize = pixelSize;
this.interRoundDelay = interRoundDelay; this.interRoundDelay = interRoundDelay;
this.mouseIsDown = false; this.mouseIsDown = false;
this.paused = false; this.paused = false;
this.intervalId = null; this.intervalId = null;
// Make the grid // Make the grid
this.grid = []; this.grid = [];
for (let i = 0; i < rows; i++) { for (let i = 0; i < rows; i++) {
this.grid.push([]); this.grid.push([]);
for (let j = 0; j < cols; j++) { for (let j = 0; j < cols; j++) {
let alive = heavyWeightSpaceshipCell(j, i) let alive = heavyWeightSpaceshipCell(j, i);
this.grid[i].push(new ConwayPixel(alive)); this.grid[i].push(new ConwayPixel(alive));
} }
}
// Inform each pixel who it's neighbors are (performance optimization)
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.grid[i][j].neighbors = this.getNeighbors(i, j);
}
}
// Setup the canvas
let width = this.pixelSize * this.cols
let height = this.pixelSize * this.rows
this.canvas = document.createElement('canvas');
this.canvas.width = width;
this.canvas.height = height;
this.canvasCtx = this.canvas.getContext('2d', { alpha: true });
} }
/* // Inform each pixel who it's neighbors are (performance optimization)
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.grid[i][j].neighbors = this.getNeighbors(i, j);
}
}
// Setup the canvas
let width = this.pixelSize * this.cols;
let height = this.pixelSize * this.rows;
this.canvas = document.createElement("canvas");
this.canvas.width = width;
this.canvas.height = height;
this.canvasCtx = this.canvas.getContext("2d", { alpha: true });
}
/*
Starts the simulation via setInterval if it's not running Starts the simulation via setInterval if it's not running
*/ */
start() { start() {
if (this.intervalId) { if (this.intervalId) {
return; return;
}
this.intervalId = setInterval(() => {
this.advanceRound();
this.repaint();
}, this.interRoundDelay);
} }
/* this.intervalId = setInterval(() => {
this.advanceRound();
this.repaint();
}, this.interRoundDelay);
}
/*
If the simulation is running, stop it using clearInterval If the simulation is running, stop it using clearInterval
*/ */
stop() { stop() {
if (this.intervalId) { if (this.intervalId) {
clearInterval(this.intervalId); clearInterval(this.intervalId);
this.intervalId = null; this.intervalId = null;
}
} }
}
/* /*
Return the neighbors of a particular grid location Return the neighbors of a particular grid location
*/ */
getNeighbors(row, col) { getNeighbors(row, col) {
let neighbors = []; let neighbors = [];
for (let i = row - 1; i <= row + 1; i++) { for (let i = row - 1; i <= row + 1; i++) {
for (let j = col - 1; j <= col + 1; j++) { for (let j = col - 1; j <= col + 1; j++) {
if (i === row && j === col) continue; if (i === row && j === col) continue;
if (this.grid[i] && this.grid[i][j]) { if (this.grid[i] && this.grid[i][j]) {
neighbors.push(this.grid[i][j]); neighbors.push(this.grid[i][j]);
}
}
} }
}
return neighbors;
} }
/* return neighbors;
}
/*
Update the grid according to the rules for each SimEntity Update the grid according to the rules for each SimEntity
*/ */
advanceRound() { advanceRound() {
if (this.mouseIsDown) return; if (this.mouseIsDown) return;
// First prepare each pixel (give it a next state) // First prepare each pixel (give it a next state)
for (let i = 0; i < this.rows; i++) { for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) { for (let j = 0; j < this.cols; j++) {
this.grid[i][j].prepareUpdate(); this.grid[i][j].prepareUpdate();
} }
}
// Then actually advance them, once all the new states are computed
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.grid[i][j].update();
}
}
} }
/* // Then actually advance them, once all the new states are computed
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
this.grid[i][j].update();
}
}
}
/*
Optimized repaint that only updates pixels that have changed, and paints Optimized repaint that only updates pixels that have changed, and paints
in batches by color. Using force will repaint all pixels regardless of their in batches by color. Using force will repaint all pixels regardless of their
state/previousState/nextState, which is slower. state/previousState/nextState, which is slower.
*/ */
repaint(force = false) { repaint(force = false) {
if (this.mouseIsDown && !force) return; if (this.mouseIsDown && !force) return;
// Canvas optimization -- it's faster to paint by color than placement. // Canvas optimization -- it's faster to paint by color than placement.
let byColor = {}; let byColor = {};
for (let i = 0; i < this.rows; i++) { for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) { for (let j = 0; j < this.cols; j++) {
let pixel = this.grid[i][j]; let pixel = this.grid[i][j];
if (!force && !pixel.forceRepaint && pixel.alive === pixel.previousState) { if (
continue; // No need to repaint if the pixel didn't change !force &&
} !pixel.forceRepaint &&
pixel.alive === pixel.previousState
let color = pixel.alive ? pixel.lifeStyle : pixel.deathStyle; ) {
if (byColor[color] === undefined) { continue; // No need to repaint if the pixel didn't change
byColor[color] = []
}
byColor[color].push([i, j]);
pixel.forceRepaint = false; // Once a pixel is painted, reset it's forced state
}
} }
for (let color in byColor) { let color = pixel.alive ? pixel.lifeStyle : pixel.deathStyle;
this.canvasCtx.fillStyle = color; if (byColor[color] === undefined) {
for (let [row, col] of byColor[color]) { byColor[color] = [];
this.canvasCtx.fillRect(
col * this.pixelSize,
row * this.pixelSize,
this.pixelSize,
this.pixelSize
);
}
} }
byColor[color].push([i, j]);
pixel.forceRepaint = false; // Once a pixel is painted, reset it's forced state
}
} }
/* for (let color in byColor) {
this.canvasCtx.fillStyle = color;
for (let [row, col] of byColor[color]) {
this.canvasCtx.fillRect(
col * this.pixelSize,
row * this.pixelSize,
this.pixelSize,
this.pixelSize,
);
}
}
}
/*
Paint an individual pixel. This is not used by repaint because of a batch Paint an individual pixel. This is not used by repaint because of a batch
optimziation. painting an individual pixel does take place when click events optimziation. painting an individual pixel does take place when click events
happen. happen.
*/ */
paintPixel(row, col) { paintPixel(row, col) {
this.grid[row][col].setPaintStyles(this.canvasCtx); this.grid[row][col].setPaintStyles(this.canvasCtx);
this.canvasCtx.fillRect( this.canvasCtx.fillRect(
col * this.pixelSize, col * this.pixelSize,
row * this.pixelSize, row * this.pixelSize,
this.pixelSize, this.pixelSize,
this.pixelSize this.pixelSize,
); );
} }
/* ============= /* =============
Visualizatiuon Modifiers Visualizatiuon Modifiers
================ */ ================ */
/* /*
Give each entity in the grid an alive style such that when all pixels are alive Give each entity in the grid an alive style such that when all pixels are alive
the grid would be a rainbow gradient. the grid would be a rainbow gradient.
*/ */
setRainbowScheme() { setRainbowScheme() {
let rows = this.grid.length; let rows = this.grid.length;
let cols = this.grid[0].length; let cols = this.grid[0].length;
let diagonalLength = Math.sqrt((this.rows * this.rows) + (this.cols * this.cols)); let diagonalLength = Math.sqrt(
let hueIncrement = 360 / diagonalLength; this.rows * this.rows + this.cols * this.cols,
);
let hueIncrement = 360 / diagonalLength;
for (let i = 0; i < this.rows; i++) { for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) { for (let j = 0; j < this.cols; j++) {
let h = Math.floor(Math.sqrt((i * i) + (j * j)) * hueIncrement); let h = Math.floor(Math.sqrt(i * i + j * j) * hueIncrement);
let px = this.grid[i][j]; let px = this.grid[i][j];
px.lifeStyle = `hsl(${h}, 100%, 60%)`; px.lifeStyle = `hsl(${h}, 100%, 60%)`;
px.deathStyle = `#000000`; px.deathStyle = `#000000`;
px.forceRepaint = true; px.forceRepaint = true;
} }
}
} }
}
/* /*
Give each entity in the specified area of the grid an alive style Give each entity in the specified area of the grid an alive style
such that when all pixels are alive the area would be a rainbow gradient. such that when all pixels are alive the area would be a rainbow gradient.
*/ */
setRainbowSchemeWithin(startRow, stopRow, startCol, stopCol) { setRainbowSchemeWithin(startRow, stopRow, startCol, stopCol) {
let rows = stopRow - startRow; let rows = stopRow - startRow;
let cols = stopCol - startCol; let cols = stopCol - startCol;
let diagonalLength = Math.sqrt((rows * rows) + (cols * cols)); let diagonalLength = Math.sqrt(rows * rows + cols * cols);
let hueIncrement = 360 / diagonalLength; let hueIncrement = 360 / diagonalLength;
for (let i = startRow; i < stopRow; i++) { for (let i = startRow; i < stopRow; i++) {
for (let j = startCol; j < stopCol; j++) { for (let j = startCol; j < stopCol; j++) {
let h = Math.floor(Math.sqrt((i * i) + (j * j)) * hueIncrement); let h = Math.floor(Math.sqrt(i * i + j * j) * hueIncrement);
let px = this.grid[i][j]; let px = this.grid[i][j];
px.lifeStyle = `hsl(${h}, 100%, 60%)`; px.lifeStyle = `hsl(${h}, 100%, 60%)`;
px.deathStyle = `#000000`; px.deathStyle = `#000000`;
px.forceRepaint = true; px.forceRepaint = true;
} }
}
} }
}
/* /*
set colors to the provided parameters set colors to the provided parameters
*/ */
setPixelColors(lifeStyle, deathStyle) { setPixelColors(lifeStyle, deathStyle) {
this.grid.forEach((row) => { this.grid.forEach((row) => {
row.forEach((entity) => { row.forEach((entity) => {
entity.lifeStyle = lifeStyle; entity.lifeStyle = lifeStyle;
entity.deathStyle = deathStyle; entity.deathStyle = deathStyle;
entity.forceRepaint = true; entity.forceRepaint = true;
}); });
}); });
} }
/* /*
Give the board random semi-complementary colors. Give the board random semi-complementary colors.
*/ */
setRandomPixelColors() { setRandomPixelColors() {
let baseHue = randomInteger(1, 360); let baseHue = randomInteger(1, 360);
let complementaryHue = (baseHue + randomInteger(90, 270) % 360); let complementaryHue = baseHue + (randomInteger(90, 270) % 360);
this.setPixelColors(`hsl(${baseHue}, 100%, 60%)`, `hsl(${complementaryHue}, 100%, 60%)`) this.setPixelColors(
} `hsl(${baseHue}, 100%, 60%)`,
`hsl(${complementaryHue}, 100%, 60%)`,
);
}
/* /*
Given a bounding box, apply the currently selected rules to ONLY the Given a bounding box, apply the currently selected rules to ONLY the
pixels within the provided box. pixels within the provided box.
*/ */
applyColorsWithin(rowStart, rowStop, colStart, colStop, lifeStyle, deathStyle) { applyColorsWithin(
for (let i = rowStart; i < rowStop; i++) { rowStart,
for (let j = colStart; j < colStop; j++) { rowStop,
let pixel = this.grid[i][j]; colStart,
pixel.lifeStyle = lifeStyle; colStop,
pixel.deathStyle = deathStyle; lifeStyle,
pixel.forceRepaint = true; deathStyle,
} ) {
} for (let i = rowStart; i < rowStop; i++) {
for (let j = colStart; j < colStop; j++) {
let pixel = this.grid[i][j];
pixel.lifeStyle = lifeStyle;
pixel.deathStyle = deathStyle;
pixel.forceRepaint = true;
}
} }
}
/* /*
Give a sopecific area of the board random semi-complementary colors. Give a sopecific area of the board random semi-complementary colors.
*/ */
applyRandomColorsWithin(rowStart, rowStop, colStart, colStop) { applyRandomColorsWithin(rowStart, rowStop, colStart, colStop) {
let baseHue = randomInteger(1, 360); let baseHue = randomInteger(1, 360);
let complementaryHue = (baseHue + randomInteger(90, 270) % 360); let complementaryHue = baseHue + (randomInteger(90, 270) % 360);
this.applyColorsWithin(rowStart, rowStop, colStart, `hsl(${baseHue}, 100%, 60%)`, `hsl(${complementaryHue}, 100%, 60%)`) this.applyColorsWithin(
} rowStart,
rowStop,
colStart,
`hsl(${baseHue}, 100%, 60%)`,
`hsl(${complementaryHue}, 100%, 60%)`,
);
}
/* /*
Set all the pixels to alive=false Set all the pixels to alive=false
*/ */
resetLife(chanceOfLife) { resetLife(chanceOfLife) {
this.grid.forEach((row) => { this.grid.forEach((row) => {
row.forEach((pixel) => { row.forEach((pixel) => {
pixel.previousState = pixel.alive; pixel.previousState = pixel.alive;
pixel.alive = Math.random() < chanceOfLife; pixel.alive = Math.random() < chanceOfLife;
}); });
}); });
this.repaint(); this.repaint();
} }
/*
/*
Given a bounding box, apply the currently selected rules to ONLY the Given a bounding box, apply the currently selected rules to ONLY the
pixels within the provided box. pixels within the provided box.
*/ */
resetLifeWithin(rowStart, rowStop, colStart, colStop, chanceOfLife = .1) { resetLifeWithin(rowStart, rowStop, colStart, colStop, chanceOfLife = 0.1) {
for (let i = rowStart; i < rowStop; i++) { for (let i = rowStart; i < rowStop; i++) {
for (let j = colStart; j < colStop; j++) { for (let j = colStart; j < colStop; j++) {
let pixel = this.grid[i][j]; let pixel = this.grid[i][j];
if (pixel) { if (pixel) {
pixel.previousState = pixel.alive; pixel.previousState = pixel.alive;
pixel.alive = Math.random() < chanceOfLife; pixel.alive = Math.random() < chanceOfLife;
}
}
} }
}
this.repaint();
} }
/* this.repaint();
}
/*
Update the rules for all the pixels Update the rules for all the pixels
*/ */
setRules(underpopulation, overpopulation, reproductionMin, reproductionMax) { setRules(underpopulation, overpopulation, reproductionMin, reproductionMax) {
this.grid.forEach((row) => { this.grid.forEach((row) => {
row.forEach((pixel) => { row.forEach((pixel) => {
pixel.underpopulation = underpopulation; pixel.underpopulation = underpopulation;
pixel.overpopulation = overpopulation; pixel.overpopulation = overpopulation;
pixel.reproductionMin = reproductionMin; pixel.reproductionMin = reproductionMin;
pixel.reproductionMax = reproductionMax; pixel.reproductionMax = reproductionMax;
}); });
}); });
} }
/* /*
Swap life and death styles across the center of the grid. Swap life and death styles across the center of the grid.
*/ */
setYinYangMode() { setYinYangMode() {
for (let i = 0; i < this.rows; i++) { for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols / 2; j++) { for (let j = 0; j < this.cols / 2; j++) {
let t = this.grid[i][j].lifeStyle; let t = this.grid[i][j].lifeStyle;
this.grid[i][j].lifeStyle = this.grid[i][j].deathStyle; this.grid[i][j].lifeStyle = this.grid[i][j].deathStyle;
this.grid[i][j].deathStyle = t; this.grid[i][j].deathStyle = t;
} }
}
this.repaint(true);
} }
/* this.repaint(true);
}
/*
Given a bounding box, apply the currently selected rules to ONLY the Given a bounding box, apply the currently selected rules to ONLY the
pixels within the provided box. pixels within the provided box.
*/ */
setRulesWithin(rowStart, rowStop, colStart, colStop, underpopulation, overpopulation, reproductionMin, reproductionMax) { setRulesWithin(
for (let i = rowStart; i < rowStop; i++) { rowStart,
for (let j = colStart; j < colStop; j++) { rowStop,
let pixel = this.grid[i][j]; colStart,
pixel.underpopulation = underpopulation; colStop,
pixel.overpopulation = overpopulation; underpopulation,
pixel.reproductionMin = reproductionMin; overpopulation,
pixel.reproductionMax = reproductionMax; reproductionMin,
pixel.forceRepaint = true; reproductionMax,
} ) {
} for (let i = rowStart; i < rowStop; i++) {
for (let j = colStart; j < colStop; j++) {
let pixel = this.grid[i][j];
pixel.underpopulation = underpopulation;
pixel.overpopulation = overpopulation;
pixel.reproductionMin = reproductionMin;
pixel.reproductionMax = reproductionMax;
pixel.forceRepaint = true;
}
} }
}
/* /*
The grid has click, and click-and-drag functionality. Entities define their The grid has click, and click-and-drag functionality. Entities define their
own behavior when clicked, and this function ensures the proper entity is own behavior when clicked, and this function ensures the proper entity is
updated when it is clicked (or dragged-over) updated when it is clicked (or dragged-over)
*/ */
registerMouseListeners() { registerMouseListeners() {
bindMultipleEventListener(this.canvas, ['mousemove', 'touchmove'], (e) => { bindMultipleEventListener(this.canvas, ["mousemove", "touchmove"], (e) => {
e.preventDefault(); e.preventDefault();
if (this.mouseIsDown) { if (this.mouseIsDown) {
let x, y; let x, y;
if (e.touches) { if (e.touches) {
let rect = e.target.getBoundingClientRect(); let rect = e.target.getBoundingClientRect();
x = Math.floor((e.touches[0].pageX - rect.left) / this.pixelSize); x = Math.floor((e.touches[0].pageX - rect.left) / this.pixelSize);
y = Math.floor((e.touches[0].pageY - rect.top) / this.pixelSize); y = Math.floor((e.touches[0].pageY - rect.top) / this.pixelSize);
} } else {
else { x = Math.floor(e.offsetX / this.pixelSize);
x = Math.floor(e.offsetX / this.pixelSize); y = Math.floor(e.offsetY / this.pixelSize);
y = Math.floor(e.offsetY / this.pixelSize); }
}
this.grid[y][x].handleClick(); this.grid[y][x].handleClick();
this.paintPixel(y, x); this.paintPixel(y, x);
} }
}); });
// Capture mouse state for click and drag features // Capture mouse state for click and drag features
bindMultipleEventListener(this.canvas, ['mousedown', 'touchstart'], (e) => { bindMultipleEventListener(this.canvas, ["mousedown", "touchstart"], (e) => {
e.preventDefault(); e.preventDefault();
let rect = e.target.getBoundingClientRect(); let rect = e.target.getBoundingClientRect();
let x, y; let x, y;
if (e.touches) { if (e.touches) {
let rect = e.target.getBoundingClientRect(); let rect = e.target.getBoundingClientRect();
x = Math.floor((e.touches[0].pageX - rect.left) / this.pixelSize); x = Math.floor((e.touches[0].pageX - rect.left) / this.pixelSize);
y = Math.floor((e.touches[0].pageY - rect.top) / this.pixelSize); y = Math.floor((e.touches[0].pageY - rect.top) / this.pixelSize);
} } else {
else { x = Math.floor(e.offsetX / this.pixelSize);
x = Math.floor(e.offsetX / this.pixelSize); y = Math.floor(e.offsetY / this.pixelSize);
y = Math.floor(e.offsetY / this.pixelSize); }
}
this.grid[y][x].handleClick(); this.grid[y][x].handleClick();
this.paintPixel(y, x); this.paintPixel(y, x);
this.mouseIsDown = true; this.mouseIsDown = true;
}); });
bindMultipleEventListener(this.canvas, ['mouseup', 'touchend'], (e) => { bindMultipleEventListener(this.canvas, ["mouseup", "touchend"], (e) => {
e.preventDefault(); e.preventDefault();
this.mouseIsDown = false; this.mouseIsDown = false;
}); });
} }
} }
/* /*
A single pixel within a greater ConwaySimulator. Each ConwayPixel has it's own rules for evolution, A single pixel within a greater ConwaySimulator. Each ConwayPixel has it's own rules for evolution,
and for performance reason's maintains a list of it's neighbors inside of it's simulator. and for performance reason's maintains a list of it's neighbors inside of it's simulator.
@ -395,32 +421,31 @@ export default class ConwaySimulator {
ConwayPixels outside of the ConwaySimulator class is not advised. ConwayPixels outside of the ConwaySimulator class is not advised.
*/ */
class ConwayPixel { class ConwayPixel {
/*
/*
Constuct a default ConwayPixel, which follows the original Game of Life rules. Constuct a default ConwayPixel, which follows the original Game of Life rules.
*/ */
constructor(alive) { constructor(alive) {
this.alive = alive; this.alive = alive;
this.lifeStyle = '#000000'; this.lifeStyle = "#000000";
this.deathStyle = '#FFFFFF'; this.deathStyle = "#F5FFFA";
this.underpopulation = 2; this.underpopulation = 2;
this.overpopulation = 3; this.overpopulation = 3;
this.reproductionMin = 3; this.reproductionMin = 3;
this.reproductionMax = 3; this.reproductionMax = 3;
// Experimental improvement... // Experimental improvement...
this.neighbors = []; this.neighbors = [];
this.nextState = null; this.nextState = null;
this.previousState = null; this.previousState = null;
this.forceRepaint = true; this.forceRepaint = true;
// Reproduction min cannot be more than reproduction max // Reproduction min cannot be more than reproduction max
if (this.reproductionMax < this.reproductionMin) { if (this.reproductionMax < this.reproductionMin) {
this.reproductionMin = this.reproductionMax this.reproductionMin = this.reproductionMax;
}
} }
}
/* /*
In order to process whole rounds at a time, update returns In order to process whole rounds at a time, update returns
a replacement entity, it does not edit the entity in place. a replacement entity, it does not edit the entity in place.
@ -438,48 +463,50 @@ class ConwayPixel {
a live cell, as if by reproduction. a live cell, as if by reproduction.
*/ */
prepareUpdate() { prepareUpdate() {
let sum = 0; let sum = 0;
let nextState = this.alive; let nextState = this.alive;
for (let n of this.neighbors) { for (let n of this.neighbors) {
if (n.alive && n !== this) sum++; if (n.alive && n !== this) sum++;
}
if (nextState && sum < this.underpopulation) {
nextState = false;
}
else if (nextState && sum > this.overpopulation) {
nextState = false;
}
else if (!nextState && sum >= this.reproductionMin && sum <= this.reproductionMax) {
nextState = true;
}
this.nextState = nextState;
} }
/* if (nextState && sum < this.underpopulation) {
nextState = false;
} else if (nextState && sum > this.overpopulation) {
nextState = false;
} else if (
!nextState &&
sum >= this.reproductionMin &&
sum <= this.reproductionMax
) {
nextState = true;
}
this.nextState = nextState;
}
/*
Advance this pixel to it's nextState. Advance this pixel to it's nextState.
*/ */
update() { update() {
this.previousState = this.alive; this.previousState = this.alive;
this.alive = this.nextState; this.alive = this.nextState;
this.nextState = null; this.nextState = null;
} }
/* /*
The calling context infers that a click HAS occured, this is not a mouse; The calling context infers that a click HAS occured, this is not a mouse;
this is not an event listener. this is not an event listener.
*/ */
handleClick() { handleClick() {
this.alive = true; this.alive = true;
} }
/* /*
Provided with a canvas context, paint ourselves! Provided with a canvas context, paint ourselves!
*/ */
setPaintStyles(canvasCtx) { setPaintStyles(canvasCtx) {
canvasCtx.fillStyle = this.alive ? this.lifeStyle : this.deathStyle; canvasCtx.fillStyle = this.alive ? this.lifeStyle : this.deathStyle;
} }
} }

View File

@ -1,5 +1,9 @@
.container { .container {
width: 710px; width: 710px;
display: flex;
flex-direction: column;
gap: 24px;
margin: 24px 0px;
} }
.header { .header {
@ -49,9 +53,14 @@
gap: 8px; gap: 8px;
} }
.title-and-nav hr {
margin-bottom: 0;
}
.title-and-gol { .title-and-gol {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 16px;
align-items: center; align-items: center;
height: 110px; height: 110px;
} }
@ -62,6 +71,7 @@
max-width: 250; max-width: 250;
margin: 0; margin: 0;
padding: 0; padding: 0;
padding-bottom: 8px;
} }
.footer { .footer {

35
src/styles/home.css Normal file
View File

@ -0,0 +1,35 @@
.posts {
display: flex;
flex-direction: column;
gap: 48px;
}
.post {
display: flex;
flex-direction: column;
gap: 8px;
}
.post-category {
margin: 0;
padding: 0;
color: #2f4f4f;
}
.post-title {
font-size: var(--h4-desktop);
font-weight: normal;
margin: 0;
padding: 0;
}
.post-summary {
margin: 0;
padding: 0;
}
.post-date {
margin: 0;
padding: 0;
color: gray;
}