### Install Dependencies with Yarn Source: https://github.com/electinth/election-live/blob/master/README.md This command installs all the necessary project dependencies using the Yarn package manager. It is a crucial step before running the development server or building the project. Ensure Node.js and Yarn are installed beforehand. ```bash yarn install ``` -------------------------------- ### Run Development Server with Yarn Source: https://github.com/electinth/election-live/blob/master/README.md This command starts the Gatsby development server, allowing you to view and test the project locally. It typically includes features like hot-reloading and error reporting. This command should be run after installing dependencies. ```bash yarn develop ``` -------------------------------- ### React-based Responsive Design with Responsive Component Source: https://github.com/electinth/election-live/blob/master/README.md Illustrates the React-based approach to responsive design using a `` component. This method renders different markup based on window size, which can lead to simpler code but prevents server-side pre-rendering. Use this when components require significantly different structures for different screen sizes. ```javascript import { Responsive } from "../styles" function Thing() { return ( } wide={} /> ) } ``` -------------------------------- ### Emotion Styling with Object Styles Source: https://github.com/electinth/election-live/blob/master/README.md Demonstrates how to use Emotion's `css` prop with object styles for component styling, including media query support. Object styles are preferred for better developer experience and tooling integration. ```jsx function Component() { return (
) } ``` -------------------------------- ### CSS-based Responsive Design with Media Queries Source: https://github.com/electinth/election-live/blob/master/README.md Demonstrates the CSS-based approach to responsive design using inline styles and a `media` helper function. This method renders the same HTML but applies different styles based on screen width, allowing for pre-rendering. It's suitable when components have similar markup across screen sizes. ```javascript import { media } from "../styles" function Thing() { return (
...
) } ``` -------------------------------- ### JSDoc for Component Props - Detailed Definition Source: https://github.com/electinth/election-live/blob/master/README.md Demonstrates defining component props using JSDoc with individual `@param` tags, allowing for more detailed descriptions and type specifications for each prop. This approach is beneficial for components with multiple props or props requiring specific documentation, such as custom types or units. ```javascript /** * @param {object} props * @param {IParty} props.party * @param {number} props.changeRate - The rate of change in score */ export default function MyComponent(props) { ``` -------------------------------- ### Subscribe to Per-Zone Election Data (JavaScript) Source: https://context7.com/electinth/election-live/llms.txt This snippet shows how to subscribe to live election data for specific provinces and zones using React hooks. It demonstrates fetching and displaying zone statistics, candidate information, and party scores within a zone. It depends on the 'usePerProvinceData' and 'usePerZoneData' hooks from '../models/LiveDataSubscription'. ```javascript import { usePerProvinceData, usePerZoneData } from "../models/LiveDataSubscription" function ZoneDetails({ provinceId, zoneNo }) { // Get province-level data (all zones in province) const provinceState = usePerProvinceData(provinceId) // Get specific zone data const zoneState = usePerZoneData(provinceId, zoneNo) if (zoneState.completed && zoneState.data) { const zoneData = zoneState.data // Zone statistics console.log('Progress:', zoneData.zoneStats.progress, '%') console.log('Total votes:', zoneData.zoneStats.votesTotal) console.log('Eligible voters:', zoneData.zoneStats.eligible) // Candidate information zoneData.candidates.forEach(candidate => { console.log(`${candidate.firstName} ${candidate.lastName}`) console.log(` Party: ${candidate.partyName}`) console.log(` Votes: ${candidate.score}`) console.log(` Status: ${candidate.status}`) }) // Party scores in this zone Object.entries(zoneData.zonePartyScoreMap).forEach(([partyId, score]) => { console.log(`Party ${partyId}: ${score} votes`) }) return
Zone {zoneNo} in {provinceId}
} return
Loading zone data...
} ``` -------------------------------- ### Responsive UI Components - JavaScript (React) Source: https://context7.com/electinth/election-live/llms.txt Implements responsive design patterns using both CSS-based and React-based approaches with a mobile-first strategy. The CSS-based method pre-renders the same HTML for all devices, while the React-based method conditionally renders different markup client-side. ```javascript import { media } from "../styles" import { Responsive } from "../styles" // CSS-based responsive (pre-rendered, same HTML for all devices) function ResponsiveButton() { return ( ) } // React-based responsive (different markup, client-side only) function ResponsiveView() { const breakpoint = 768 return (
} wide={} />
) } // Note: components mount after JavaScript loads // Use CSS-based approach for critical above-the-fold content ``` -------------------------------- ### Hybrid Responsive Design for Layout Stability Source: https://github.com/electinth/election-live/blob/master/README.md Combines CSS-based and React-based approaches to handle responsive components that might cause layout shifts due to differing heights. It pre-allocates space using CSS styles and then mounts the appropriate component using the `` component, ensuring a stable layout during loading. ```javascript import { Responsive } from "../styles" function Thing() { const breakpoint = 600 return (
} wide={} />
) } ``` -------------------------------- ### Adding TODO comments with 0pdd Source: https://github.com/electinth/election-live/blob/master/README.md This snippet demonstrates how to add TODO comments in JavaScript code that are managed by the 0pdd tool. It specifies the format for single-line and multi-line TODOs, linking them to GitHub issues for better tracking. This helps in maintaining code quality and tracking outstanding tasks. ```javascript // @todo #1 Add Analytics, e.g. Google Analytics. // Check out Gatsby docs for how to add analytics // - Main Guide: https://www.gatsbyjs.org/docs/adding-analytics/ // - Google Analytics: https://www.gatsbyjs.org/docs/adding-analytics/#using-gatsby-plugin-google-analytics // - Google Tag Manager: https://www.gatsbyjs.org/packages/gatsby-plugin-google-tagmanager/ ``` -------------------------------- ### Fetch Data with Cache Busting - JavaScript Source: https://context7.com/electinth/election-live/llms.txt Fetches the latest election data using Axios, implementing a 30-second cache busting strategy for the pointer file and leveraging long cache durations for immutable data files. This pattern is crucial for real-time updates without overwhelming the server. ```javascript import axios from "axios" // Data architecture: // 1. /data/latest.json - Pointer to current data directory (refreshes every 30s) // 2. /data/{timestamp}/SummaryJSON.json - Nationwide summary (immutable) // 3. /data/{timestamp}/PerProvinceJSON/{provinceId}.json - Province data (immutable) // Example latest.json structure: const latestFile = { pointers: [ { timestamp: 1553445600000, directory: "/20190324-220000" } ], control: { locked: "FALSE", // Set to "TRUE" to hide results until counting starts status: "Counting in progress..." // Optional status message } } // Fetch with cache busting (30-second window) const url = "/data/latest.json?cachebust=" + Math.floor(Date.now() / 30000) const response = await axios.get(url) // Immutable data files use max-age=31536000 (1 year) + immutable directive // Latest file uses max-age=30 with stale-while-revalidate=30 // Example SummaryJSON structure: const summaryJSON = { partyScoreMap: { "7": 8010134, // Party ID -> vote count "10": 7921422 }, zoneStatsMap: { "10": { // Province ID "1": { // Zone number progress: 100, votesTotal: 156789, eligible: 180000, finished: true, noVotes: 12345, badVotes: 234 } } }, zoneWinningCandidateMap: { "10": { "1": { partyId: 7, candidateId: 12345, score: 65432 } } } } ``` -------------------------------- ### Access Election Zone and Province Information API (JavaScript) Source: https://context7.com/electinth/election-live/llms.txt This snippet demonstrates how to access election zone and province data using the provided models. It covers fetching all provinces, specific zone information, party details, checking filters, and generating URLs for zones and parties. Dependencies include the '../models/information' module. ```javascript import { provinces, zones, parties, getZoneByProvinceIdAndZoneNo, getPartyById, checkFilter, filters, zonePath, partyPath } from "../models/information" // Get all provinces provinces.forEach(province => { console.log(`${province.id}: ${province.name} (${province.regionId})`) }) // Get specific zone information const zone = getZoneByProvinceIdAndZoneNo(10, 3) // Bangkok zone 3 console.log(`${zone.provinceId}-${zone.no}: ${zone.provinceName}`) // Get party information const party = getPartyById(7) // Pheu Thai console.log(`Party: ${party.name}, Color: ${party.color}`) // Check if zone matches filter const bangkokZone = zones.find(z => z.provinceId === 10) if (checkFilter(filters.bangkok, bangkokZone)) { console.log('This zone is in Bangkok') } // Generate URLs const zoneUrl = zonePath(bangkokZone) // "/zone/10/3" const partyUrl = partyPath(party) // "/party/7" // Available filters: all, region-central, region-northern, region-northeastern, // region-southern, bangkok, and individual province filters console.log('Available filters:', Object.keys(filters)) ``` -------------------------------- ### JSDoc for Component Props - Single Line Definition Source: https://github.com/electinth/election-live/blob/master/README.md Shows how to define component props using JSDoc in a single line for concise type annotation. This method is useful for components with a small number of simple props, improving code readability and enabling better IDE support. ```javascript /** * @param {{ party: IParty, hidden: boolean }} props */ export default function Unimplemented(props) { ``` -------------------------------- ### Gatsby Page Generation for Election Data (JavaScript) Source: https://context7.com/electinth/election-live/llms.txt This snippet details how to configure Gatsby to dynamically generate pages for all zones, parties, and filters during the build process. It utilizes Gatsby's 'createPages' API and requires access to the project's information models and path generation functions. It also includes a post-build step to write version metadata. ```javascript // In gatsby-node.js const { provinces, zones, parties, partyPath, zonePath, filterPath, filters } = require("./src/models/information") exports.createPages = async ({ actions }) => { const { createPage } = actions // Generate party pages (e.g., /party/7 for party ID 7) for (const party of parties) { createPage({ path: partyPath(party), component: path.resolve(`src/pages/party.js`), context: { partyId: party.id } }) } // Generate zone pages (e.g., /zone/10/3 for Bangkok zone 3) for (const province of provinces) { for (const zone of zones.filter(z => z.provinceId === province.id)) { createPage({ path: zonePath(zone), component: path.resolve(`src/pages/index.js`), context: { zoneView: { provinceId: province.id, zoneNo: zone.no } } }) } } // Generate filter pages (e.g., /about/region-northern) for (const filterName of Object.keys(filters)) { createPage({ path: filterPath(filterName), component: path.resolve(`src/pages/index.js`), context: { filterName: filterName } }) } } // Post-build: Generate version metadata exports.onPostBuild = async () => { fs.writeFileSync('public/version.info.json', JSON.stringify({ version: require('./package').version })) } ``` -------------------------------- ### React Hook for Live Election Data Subscription Source: https://context7.com/electinth/election-live/llms.txt This React hook, `useSummaryData`, provides reactive subscription to live election results. It handles loading, error, and success states, automatically polling for updates every 60 seconds. It relies on the `LiveDataSubscription` model for data fetching and state management. ```javascript import { useSummaryData } from "../models/LiveDataSubscription" function ElectionResults() { // Subscribe to live election summary data const summaryState = useSummaryData() // Handle different states if (summaryState.loading) { return
Loading election results...
} if (summaryState.failed) { return
Error: {summaryState.error.message}
} if (summaryState.completed && summaryState.data) { const summary = summaryState.data console.log('Total party scores:', summary.partyScoreMap) console.log('Zone statistics:', summary.zoneStatsMap) console.log('Winning candidates:', summary.zoneWinningCandidateMap) return
Results loaded successfully
} return null } // Data automatically refreshes every 60 seconds // Returns: { loading: boolean, failed: boolean, completed: boolean, data: SummaryJSON, error: Error } ``` -------------------------------- ### Party Seat Distribution Calculation using Thailand's Formula Source: https://context7.com/electinth/election-live/llms.txt This Javascript function, `calculateElectionResults`, utilizes the `thailand-party-list-calculator` library to compute party seat distribution. It supports filtered calculations (e.g., by region) and projected results, factoring in both constituency and party-list seats according to Thailand's specific electoral formula. It also includes utility functions to check zone data display readiness and completion status. ```javascript import { partyStatsFromSummaryJSON, isZoneFinished, shouldDisplayZoneData } from "../models/PartyStats" import { filters } from "../models/information" // Calculate nationwide party statistics function calculateElectionResults(summaryData) { // Basic calculation - all zones const allStats = partyStatsFromSummaryJSON(summaryData) // Filtered calculation - e.g., only Bangkok zones const bangkokStats = partyStatsFromSummaryJSON(summaryData, { filter: filters.bangkok }) // Projected results with phantom votes for uncounted zones const projectedStats = partyStatsFromSummaryJSON(summaryData, { fillAllSeats: true, expectedVotersCount: 20000000 }) // Each row contains: { party, constituencySeats, partyListSeats, score, seatsCeiling } allStats.forEach(row => { const totalSeats = row.constituencySeats + row.partyListSeats const seatLimit = Math.floor(row.seatsCeiling) // ยง 128 seat ceiling console.log(`${row.party.name}: ${totalSeats} seats (${row.constituencySeats} constituency + ${row.partyListSeats} party-list)`) console.log(` Votes: ${row.score.toLocaleString()}, Ceiling: ${row.seatsCeiling.toFixed(2)}`) }) return allStats } // Check if zone results should be displayed (>1% votes counted) const zoneStats = { finished: false, progress: 5, votesTotal: 15000, eligible: 100000 } if (shouldDisplayZoneData(zoneStats)) { console.log('Zone has sufficient data to display') } // Check if zone counting is complete (>80% or finished) if (isZoneFinished(zoneStats)) { console.log('Zone counting completed') } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.