-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fff8c4c
Showing
17 changed files
with
12,124 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
misc | ||
.DS_Store | ||
*.log | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# 211 | ||
|
||
**What's the 2-1-1?** | ||
|
||
211s are short, simple descriptions of an idea that are no more than 211 words long, and use only the 2^11 most common english words. | ||
|
||
The goal isn't to make it impossible or a big challenge to write. We just want a gut check on how much jargon we're using, and a nudge towards writing more simply. | ||
|
||
This doesn't focus on tracking character count because the abbreviations you see on twitter inhibit comprehension more than aid. | ||
|
||
**Next Steps** | ||
|
||
- Originally the editor was built as simple flat html/js files. This worked fine for the editor, but I then decided to add in 'Posts', and the management of that as flat HTML is brittle. If we wind up using this, we'll want a cleaner way to add simple markdown files that we can build into a post directory, and auto-populate the Post listing on the landing page. The simplest path is probably just to pick a templating framework and add a couple config/layout files. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<script type="text/javascript" src="/editor/words.js"></script> | ||
<script type="text/javascript" src="/editor/script.js" defer></script> | ||
<link rel="icon" type="image/png" href="/favicon.png" /> | ||
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> | ||
<link rel="stylesheet" href="/style.css" /> | ||
<title>211 Editor</title> | ||
<meta | ||
name="description" | ||
content="211s are short, simple statements of an idea that are no more than 211 words long, and use only the 2^11 most common English words." | ||
/> | ||
</head> | ||
<body> | ||
<nav> | ||
<div><a href="/">211</a></div> | ||
<ul> | ||
<li><a href="/">Posts</a></li> | ||
<li><a href="/editor">Editor</a></li> | ||
</ul> | ||
</nav> | ||
<main class="editor"> | ||
<div class="description"> | ||
211s are short, simple statements of an idea that are no more than 211 words long, | ||
and use only the 2<sup>11</sup> most common English words. | ||
</div> | ||
<div id="editor-wrapper"> | ||
<div id="editor"> | ||
<textarea id="text" autofocus></textarea> | ||
<div id="mask"></div> | ||
</div> | ||
</div> | ||
<div class="details"> | ||
<div class="count"> | ||
<div class="detail-title">Word count</div> | ||
<div id="word-count"></div> | ||
</div> | ||
<div class="word-list" id="word-list"> | ||
<div class="detail-header"> | ||
<div class="detail-title hide-on-all">Words to Change</div> | ||
<div class="detail-title show-on-all">All Words</div> | ||
<div> | ||
<label for="allwords">All words</label> | ||
<input type="checkbox" id="allwords" name="allwords" value="All" /> | ||
</div> | ||
</div> | ||
<div id="jargon"></div> | ||
</div> | ||
</div> | ||
</main> | ||
<footer> | ||
<a href="https://github.com/knowledgefutures/211">Code</a> | ||
<span>·</span> | ||
Word data from <a href="https://www.wordfrequency.info/">wordfrequency.info</a> | ||
</footer> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { parse } from 'csv-parse/sync'; | ||
import fs from 'fs'; | ||
|
||
const fileBuffer = fs.readFileSync('editor/wordforms.csv'); | ||
const records = parse(fileBuffer, { | ||
columns: true, | ||
}); | ||
|
||
const words = {}; | ||
records | ||
// .filter((record) => { | ||
// return Number(record.lemRank) < 2049; | ||
// }) | ||
.forEach((record) => { | ||
if (!words[record.word]) { | ||
// The source CSV seems to have some duplicates at higher ranks. | ||
// e.g. "this" | ||
words[record.word] = { rank: Number(record.lemRank), lemma: record.lemma }; | ||
} | ||
}); | ||
|
||
const data = `const words = ${JSON.stringify(words)};`; | ||
|
||
fs.writeFile('editor/words.js', data, (err) => { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('JSON data is saved.'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
const textareaNode = document.getElementById('text'); | ||
const maskNode = document.getElementById('mask'); | ||
const jargonNode = document.getElementById('jargon'); | ||
const wordCountNode = document.getElementById('word-count'); | ||
const allwordsNode = document.getElementById('allwords'); | ||
const wordListNode = document.getElementById('word-list'); | ||
|
||
const parseWords = () => { | ||
const jargonList = document.createElement('ul'); | ||
const input = textareaNode.value; | ||
const inputWords = input | ||
.trim() | ||
.toLowerCase() | ||
.replace(/[\r\n]+/g, ' ') | ||
.replace(/[.,\/#!?$%\^&\*;:{}=\_`~()]/g, '') | ||
.split(' ') | ||
.filter((word) => word.length); | ||
const wordCount = inputWords.length; | ||
wordCountNode.innerHTML = wordCount > 211 ? `<span>${wordCount}</span>` : wordCount; | ||
const seenWords = {}; | ||
let hasInvalidWords = false; | ||
inputWords | ||
.filter((word) => { | ||
// Make sure it has at least one letter. | ||
// We have to do this for leading hyphens, which | ||
// are included for the sake of hyphenated words. | ||
return word.match(/\b([\w]+)\b/g); | ||
}) | ||
.filter((word) => { | ||
if (seenWords[word]) { | ||
return false; | ||
} | ||
seenWords[word] = true; | ||
return true; | ||
}) | ||
.forEach((word) => { | ||
const wordObject = words[word]; | ||
const wordNode = document.createElement('li'); | ||
const textnode = document.createElement('div'); | ||
textnode.innerHTML = word; | ||
textnode.className = "text"; | ||
const isValid = wordObject && wordObject.rank <= 2048; | ||
if (!isValid) { | ||
hasInvalidWords = true; | ||
} | ||
const countNode = document.createElement('span'); | ||
countNode.textContent = wordObject ? wordObject.rank : '5000+'; | ||
wordNode.className = isValid ? 'valid' : 'not-valid'; | ||
wordNode.appendChild(textnode); | ||
wordNode.appendChild(countNode); | ||
jargonList.appendChild(wordNode); | ||
}); | ||
jargonNode.innerHTML = ''; | ||
if (hasInvalidWords || allwordsNode.checked) { | ||
jargonNode.appendChild(jargonList); | ||
} else { | ||
jargonNode.innerHTML = "<div class='shadow'>All words are valid!</div>"; | ||
} | ||
}; | ||
const overlayMask = () => { | ||
const newItems = textareaNode.value.replaceAll(/\b([\w-']+)\b/g, (word) => { | ||
const cleanedWord = word | ||
.toLowerCase() | ||
.replace(/[\r\n]+/g, ' ') | ||
.replace(/[.,\/#!?$%\^&\*;:{}=\_`~()]/g, ''); | ||
const wordObject = words[cleanedWord]; | ||
const isValid = wordObject && wordObject.rank < 2048; | ||
if (!isValid) { | ||
return `<span>${word}</span>`; | ||
} | ||
return word; | ||
}); | ||
maskNode.innerHTML = newItems; | ||
}; | ||
|
||
const auto_grow = () => { | ||
textareaNode.style.height = '0px'; | ||
textareaNode.style.height = textareaNode.scrollHeight + 'px'; | ||
}; | ||
|
||
const handleCheck = () => { | ||
const isChecked = allwordsNode.checked; | ||
wordListNode.className = isChecked ? 'word-list all' : 'word-list'; | ||
parseWords(); | ||
}; | ||
|
||
textareaNode.addEventListener('keyup', parseWords); | ||
textareaNode.addEventListener('input', overlayMask); | ||
textareaNode.addEventListener('input', auto_grow); | ||
allwordsNode.addEventListener('input', handleCheck); | ||
auto_grow(); | ||
parseWords(); | ||
overlayMask(); | ||
handleCheck(); |
Oops, something went wrong.