### 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
}
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.