diff --git a/README.md b/README.md index 06351ab..260faad 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,15 @@ Combines your avatar, role, bio, skills, and handle into a clean profile header. Quote Preview -### 6. Location & Timezone +### 6. Word of the Day + +```md +![Word of the Day](https://readmeme.eu.cc/api/word.svg?theme=paper&label=Vocabulary&showOrigin=1) +``` + +Word of the Day Preview + +### 7. Location & Timezone ```md ![Country Flag](https://readmeme.eu.cc/api/flag.svg?theme=forest&country=JP&label=Based+In) @@ -285,6 +293,10 @@ Procedural sky & ocean widgets that shift color palettes dynamically based on yo * `unit` * `platform` +### Word of the Day + +* `showOrigin` + ## Local Development Clone the repository: diff --git a/api/widget.js b/api/widget.js index 92e97da..ec1d971 100644 --- a/api/widget.js +++ b/api/widget.js @@ -22,7 +22,7 @@ const FALLBACK_AVATAR = `data:image/svg+xml;base64,${Buffer.from(`
- 8 + 10
Widget Types @@ -525,6 +525,7 @@

Stylish Readme

{ id:'clock', label:'Digital Clock', icon:'watch' }, { id:'date', label:'Date Stamp', icon:'calendar' }, { id:'quote', label:'Daily Quote', icon:'quote' }, + { id:'word', label:'Word of the Day', icon:'book-open' }, { id:'flag', label:'Country Flag', icon:'flag' }, { id:'timezone',label:'Timezone Banner', icon:'globe' }, { id:'streak', label:'Coding Streak', icon:'flame' }, @@ -729,6 +730,19 @@

Stylish Readme

{ q:'Simplicity is the soul of efficiency.', a:'Austin Freeman' } ]; + const WORDS = [ + { word:'Serendipity', pronunciation:'/ser-en-DIP-i-tee/', partOfSpeech:'Noun', definition:'The occurrence of finding something valuable or pleasant by chance.', example:'Meeting my mentor at the conference was pure serendipity.', synonyms:'chance, fortune, luck', origin:'Coined from The Three Princes of Serendip, a tale about accidental discoveries.' }, + { word:'Eloquent', pronunciation:'/EL-uh-kwent/', partOfSpeech:'Adjective', definition:'Fluent, expressive, and persuasive in speech or writing.', example:'Her eloquent README made the project feel instantly approachable.', synonyms:'expressive, articulate, persuasive', origin:'From Latin eloqui, meaning to speak out.' }, + { word:'Resilient', pronunciation:'/ri-ZIL-yent/', partOfSpeech:'Adjective', definition:'Able to recover quickly from difficulty or change.', example:'The resilient team shipped a cleaner fix after the outage.', synonyms:'adaptable, tough, flexible', origin:'From Latin resilire, meaning to spring back.' }, + { word:'Lucid', pronunciation:'/LOO-sid/', partOfSpeech:'Adjective', definition:'Clear, easy to understand, or rational.', example:'A lucid explanation can make complex code feel friendly.', synonyms:'clear, coherent, intelligible', origin:'From Latin lucidus, meaning bright or clear.' }, + { word:'Meticulous', pronunciation:'/meh-TIK-yuh-lus/', partOfSpeech:'Adjective', definition:'Showing great attention to detail.', example:'The meticulous review caught a subtle accessibility issue.', synonyms:'careful, precise, thorough', origin:'From Latin meticulosus, originally meaning fearful or timid.' }, + { word:'Ephemeral', pronunciation:'/ih-FEM-er-uhl/', partOfSpeech:'Adjective', definition:'Lasting for a very short time.', example:'The ephemeral preview refreshed as soon as the settings changed.', synonyms:'brief, fleeting, temporary', origin:'From Greek ephemeros, meaning lasting only a day.' }, + { word:'Pragmatic', pronunciation:'/prag-MAT-ik/', partOfSpeech:'Adjective', definition:'Focused on practical results and real-world usefulness.', example:'A pragmatic design kept the widget simple to customize.', synonyms:'practical, realistic, sensible', origin:'From Greek pragmatikos, meaning fit for action.' }, + { word:'Tenacious', pronunciation:'/tuh-NAY-shus/', partOfSpeech:'Adjective', definition:'Persistent and determined, especially when facing obstacles.', example:'Her tenacious debugging turned a vague error into a clear fix.', synonyms:'persistent, determined, steadfast', origin:'From Latin tenere, meaning to hold.' }, + { word:'Nuance', pronunciation:'/NOO-ahns/', partOfSpeech:'Noun', definition:'A subtle difference in meaning, feeling, or expression.', example:'Good documentation captures the nuance behind each option.', synonyms:'subtlety, shade, distinction', origin:'From French nuance, meaning shade or subtle variation.' }, + { word:'Candid', pronunciation:'/KAN-did/', partOfSpeech:'Adjective', definition:'Truthful, direct, and sincere.', example:'The candid changelog explained both the fix and the tradeoff.', synonyms:'honest, frank, open', origin:'From Latin candidus, meaning white or shining.' } + ]; + const SONGS = [ // Bollywood { title:'Tum Hi Ho', artist:'Arijit Singh', year:'2013', genre:'Bollywood' }, @@ -763,6 +777,8 @@

Stylish Readme

country: 'IN', // Quote quoteCategory: 'programming', + // Word of the day + showOrigin: true, // Clock style clockStyle: 'digital', // Streak @@ -949,6 +965,27 @@

Stylish Readme

`; } + else if (state.widget==='word'){ + html += ` +
+ + ${themeSwatches()} +
+
+ + +
+
+ +
+
+ Note: A new vocabulary word is selected each day with pronunciation, definition, example, and synonyms. +
+ `; + } else if (state.widget==='flag'){ html += `
@@ -1520,6 +1557,58 @@

Stylish Readme

`; } + function wordLines(text, maxLen, maxLines){ + const words = String(text||'').split(/\s+/).filter(Boolean); + const lines=[]; let line=''; + words.forEach(w=>{ + if(lines.length>=maxLines) return; + if((line+' '+w).trim().length>maxLen){ + if(line) lines.push(line.trim()); + line=w; + } else { + line=(line+' '+w).trim(); + } + }); + if(line && lines.length + + + ${(state.label||'WORD OF THE DAY').toUpperCase()} + ${item.word} + ${item.pronunciation} + + ${item.partOfSpeech.toUpperCase()} + + DEFINITION + ${definition.map((line,i)=>`${line}`).join('')} + EXAMPLE + ${example.map((line,i)=>`${line}`).join('')} + SYNONYMS + ${item.synonyms} + ${state.showOrigin?` + ORIGIN + ${origin.map((line,i)=>`${line}`).join('')} + `:''} + `; + } + function svgFlag(){ const theme = themeObj(state.theme); const country = COUNTRIES.find(c=>c.code===state.country) || COUNTRIES[0]; @@ -2739,6 +2828,7 @@

Stylish Readme

case 'clock': return svgClock(); case 'date': return svgDate(); case 'quote': return svgQuote(); + case 'word': return svgWord(); case 'flag': return svgFlag(); case 'timezone': return svgTimezone(); case 'streak': return svgStreak(); @@ -2767,6 +2857,7 @@

Stylish Readme

clock: ['timezone','theme','timeFormat','showSeconds','label'], date: ['timezone','theme','label'], quote: ['theme','quoteCategory','label'], + word: ['theme','label','showOrigin'], flag: ['country','theme','label'], timezone: ['timezone','theme','timeFormat'], streak: ['startDate','unit','theme','customLabel','platform'], @@ -2845,6 +2936,7 @@

Stylish Readme

{ title:'Tokyo Time', w:'time', overrides:{timezone:'Asia/Tokyo',theme:'terminal',label:'Tokyo'} }, { title:'New York Clock', w:'clock', overrides:{timezone:'America/New_York',theme:'paper',label:'Eastern'} }, { title:'Daily Quote', w:'quote', overrides:{theme:'crimson',label:'Today'} }, + { title:'Word of the Day', w:'word', overrides:{theme:'paper',label:'Vocabulary',showOrigin:true} }, { title:'London Date', w:'date', overrides:{theme:'retro',timezone:'Europe/London',label:'Today'} }, { title:'NYC Timezone', w:'timezone', overrides:{theme:'ocean',timezone:'America/New_York'} }, { title:'India Flag', w:'flag', overrides:{country:'IN',theme:'forest',label:'From'} }, diff --git a/lib/widgets.js b/lib/widgets.js index 31b677d..2328499 100644 --- a/lib/widgets.js +++ b/lib/widgets.js @@ -291,6 +291,19 @@ function shuffle(array) { } } +const WORDS = [ + { word:'Serendipity', pronunciation:'/ser-en-DIP-i-tee/', partOfSpeech:'Noun', definition:'The occurrence of finding something valuable or pleasant by chance.', example:'Meeting my mentor at the conference was pure serendipity.', synonyms:'chance, fortune, luck', origin:'Coined from The Three Princes of Serendip, a tale about accidental discoveries.' }, + { word:'Eloquent', pronunciation:'/EL-uh-kwent/', partOfSpeech:'Adjective', definition:'Fluent, expressive, and persuasive in speech or writing.', example:'Her eloquent README made the project feel instantly approachable.', synonyms:'expressive, articulate, persuasive', origin:'From Latin eloqui, meaning to speak out.' }, + { word:'Resilient', pronunciation:'/ri-ZIL-yent/', partOfSpeech:'Adjective', definition:'Able to recover quickly from difficulty or change.', example:'The resilient team shipped a cleaner fix after the outage.', synonyms:'adaptable, tough, flexible', origin:'From Latin resilire, meaning to spring back.' }, + { word:'Lucid', pronunciation:'/LOO-sid/', partOfSpeech:'Adjective', definition:'Clear, easy to understand, or rational.', example:'A lucid explanation can make complex code feel friendly.', synonyms:'clear, coherent, intelligible', origin:'From Latin lucidus, meaning bright or clear.' }, + { word:'Meticulous', pronunciation:'/meh-TIK-yuh-lus/', partOfSpeech:'Adjective', definition:'Showing great attention to detail.', example:'The meticulous review caught a subtle accessibility issue.', synonyms:'careful, precise, thorough', origin:'From Latin meticulosus, originally meaning fearful or timid.' }, + { word:'Ephemeral', pronunciation:'/ih-FEM-er-uhl/', partOfSpeech:'Adjective', definition:'Lasting for a very short time.', example:'The ephemeral preview refreshed as soon as the settings changed.', synonyms:'brief, fleeting, temporary', origin:'From Greek ephemeros, meaning lasting only a day.' }, + { word:'Pragmatic', pronunciation:'/prag-MAT-ik/', partOfSpeech:'Adjective', definition:'Focused on practical results and real-world usefulness.', example:'A pragmatic design kept the widget simple to customize.', synonyms:'practical, realistic, sensible', origin:'From Greek pragmatikos, meaning fit for action.' }, + { word:'Tenacious', pronunciation:'/tuh-NAY-shus/', partOfSpeech:'Adjective', definition:'Persistent and determined, especially when facing obstacles.', example:'Her tenacious debugging turned a vague error into a clear fix.', synonyms:'persistent, determined, steadfast', origin:'From Latin tenere, meaning to hold.' }, + { word:'Nuance', pronunciation:'/NOO-ahns/', partOfSpeech:'Noun', definition:'A subtle difference in meaning, feeling, or expression.', example:'Good documentation captures the nuance behind each option.', synonyms:'subtlety, shade, distinction', origin:'From French nuance, meaning shade or subtle variation.' }, + { word:'Candid', pronunciation:'/KAN-did/', partOfSpeech:'Adjective', definition:'Truthful, direct, and sincere.', example:'The candid changelog explained both the fix and the tradeoff.', synonyms:'honest, frank, open', origin:'From Latin candidus, meaning white or shining.' } +]; + // ----- Country flag SVG fragments (viewBox 60x40) ----- const FLAGS = { IN: ` @@ -719,6 +732,61 @@ function renderQuote(p) { `, "'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace"); } +function wrapText(text, maxLen, maxLines) { + const words = String(text || '').split(/\s+/).filter(Boolean); + const lines = []; + let line = ''; + words.forEach(w => { + if (lines.length >= maxLines) return; + if ((line + ' ' + w).trim().length > maxLen) { + if (line) lines.push(line.trim()); + line = w; + } else { + line = (line + ' ' + w).trim(); + } + }); + if (line && lines.length < maxLines) lines.push(line.trim()); + return lines; +} + +function pickWord() { + const dayKey = Math.floor(Date.now() / 86400000); + return WORDS[dayKey % WORDS.length]; +} + +function renderWord(p) { + const th = theme(p.theme); + const rx = p.radius; + const bgFill = p.bgColor || th.bg; + const border = p.borderColor ? `stroke="${p.borderColor}" stroke-width="2"` : (th.border ? `stroke="${th.fg}" stroke-width="2"` : ''); + const item = pickWord(); + const W = 560, H = 270; + const definition = wrapText(item.definition, 48, 2); + const example = wrapText(item.example, 50, 2); + const origin = wrapText(item.origin, 58, 2); + return svgWrap(W, H, ` + ${shadowFilter('sh', p.shadow)} + + + ${escXml((p.label || 'Word of the Day').toUpperCase())} + ${escXml(item.word)} + ${escXml(item.pronunciation)} + + ${escXml(item.partOfSpeech.toUpperCase())} + + DEFINITION + ${definition.map((line, i) => `${escXml(line)}`).join('')} + EXAMPLE + ${example.map((line, i) => `${escXml(line)}`).join('')} + SYNONYMS + ${escXml(item.synonyms)} + ${p.showOrigin ? ` + ORIGIN + ${origin.map((line, i) => `${escXml(line)}`).join('')} + ` : ''} + `); +} + function renderFlag(p) { const th = theme(p.theme); const rx = p.radius; @@ -2517,6 +2585,7 @@ function normalizeParams(q) { borderColor: validateBorderColor(q.borderColor), country: q.country || 'IN', quoteCategory: q.quoteCategory || 'programming', + showOrigin: normalizeBool(q.showOrigin, true), clockStyle: q.clockStyle || 'digital', startDate: (() => { const raw = q.startDate || '2024-01-01'; @@ -2716,6 +2785,7 @@ async function renderWidget(type, query) { case 'clock': return renderClock(p); case 'date': return renderDate(p); case 'quote': return renderQuote(p); + case 'word': return renderWord(p); case 'flag': return renderFlag(p); case 'timezone': return renderTimezone(p); case 'streak': return renderStreak(p); diff --git a/vercel.json b/vercel.json index 462e8ee..c46878b 100644 --- a/vercel.json +++ b/vercel.json @@ -11,6 +11,17 @@ { "source": "/api/(time|clock|timezone|skyline).svg", "headers": [ + { "key": "Content-Type", "value": "image/svg+xml; charset=utf-8" }, + { "key": "Cache-Control", "value": "public, max-age=60, s-maxage=60, stale-while-revalidate=30" }, + { "key": "Vary", "value": "Accept-Encoding" }, + { "key": "Access-Control-Allow-Origin", "value": "*" } + ] + }, + { + "source": "/api/(date|quote|word|streak|profile).svg", + "headers": [ + { "key": "Content-Type", "value": "image/svg+xml; charset=utf-8" }, + { "key": "Cache-Control", "value": "public, max-age=3600, s-maxage=3600, stale-while-revalidate=600" }, { "key": "Content-Type", "value": "image/svg+xml; charset=utf-8" }, { "key": "Cache-Control", "value": "public, max-age=60, s-maxage=60, stale-while-revalidate=30" }, { "key": "Vary", "value": "Accept-Encoding" }, @@ -45,4 +56,4 @@ ] } ] -} \ No newline at end of file +}