├── .babelrc ├── .datignore ├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── assets ├── fonts │ ├── AUTHENTIC-Sans.woff │ ├── AUTHENTIC-Sans.woff2 │ ├── AUTHENTIC-Untitled.woff │ ├── AUTHENTIC-Untitled.woff2 │ ├── Astloch-Regular.ttf │ ├── CoolS-Regular.otf │ ├── DSEG7Classic-Bold.woff │ ├── DSEG7Classic-Bold.woff2 │ ├── DSEG7Classic-Light.woff │ ├── DSEG7Classic-Light.woff2 │ ├── JRUG_PUNK.ttf │ ├── Pecita.otf │ ├── Reglo-Bold.otf │ ├── SFMono-Regular.otf │ ├── SpaceMono-Regular.ttf │ ├── Spectral-Bold.ttf │ ├── Spectral-ExtraLight.ttf │ ├── Spectral-Regular.ttf │ ├── Sporting_Grotesque-Bold_web.woff │ ├── Sporting_Grotesque-Bold_web.woff2 │ ├── Sporting_Grotesque-Regular_web.woff │ ├── Sporting_Grotesque-Regular_web.woff2 │ ├── UnifrakturMaguntia.ttf │ ├── WorkSans-Black.woff │ ├── WorkSans-Black.woff2 │ ├── WorkSans-Regular.woff │ ├── WorkSans-Regular.woff2 │ ├── WorkSans-Thin.woff │ ├── WorkSans-Thin.woff2 │ ├── Wremena-Bold.woff │ ├── Wremena-Light.woff │ ├── Yatra-Regular.ttf │ ├── YoungSerif-Regular.otf │ ├── junicode-boldcondensed-webfont.woff │ ├── junicode-boldcondensed-webfont.woff2 │ ├── junicode-regularcondensed-webfont.woff │ ├── junicode-regularcondensed-webfont.woff2 │ ├── labmono-regular-web.woff │ ├── labmono-regular-web.woff2 │ ├── lunchtype22-light-webfont.woff │ ├── lunchtype22-light-webfont.woff2 │ ├── lunchtype22-medium-webfont.woff │ ├── lunchtype22-medium-webfont.woff2 │ ├── lunchtype24-light-expanded-webfont.woff │ ├── lunchtype24-light-expanded-webfont.woff2 │ ├── lunchtype24-medium-expanded-webfont.woff │ ├── lunchtype24-medium-expanded-webfont.woff2 │ ├── lunchtype25-light_condensed-webfont.woff │ ├── lunchtype25-light_condensed-webfont.woff2 │ ├── lunchtype25-medium-condensed-webfont.woff │ ├── lunchtype25-medium-condensed-webfont.woff2 │ ├── manifont-grotesk_book-dot.woff │ ├── manifont-grotesk_book.woff │ ├── terminal-grotesque-webfont.woff │ ├── terminal-grotesque-webfont.woff2 │ ├── ume-gothic-webfont.woff │ └── ume-mincho-webfont.woff ├── icon-eye.svg ├── icon-settings.svg ├── icon-trash.svg ├── img │ ├── bg.jpg │ ├── big-data-no-thanks.png │ ├── customizable.svg │ ├── garden.jpg │ ├── posterframe.jpg │ ├── posterframe2.jpg │ ├── screenshot-2.png │ ├── screenshot-3.png │ ├── screenshot-4.png │ ├── screenshot-5.png │ ├── screenshot-6.png │ └── screenshot.png ├── plyr.svg └── social-image.png ├── content ├── about │ └── index.txt ├── blog │ ├── 001-list-jon-kyle │ │ ├── desktop.png │ │ ├── index.txt │ │ ├── obs.astro.ucla.edu.png │ │ ├── ofhouses.com.png │ │ ├── primitivetechnology.jpg │ │ └── walkinginla.com.png │ ├── 002-list-laurel │ │ ├── billwurtz.com.png │ │ ├── delinear.info.png │ │ ├── gossipsweb.net.png │ │ ├── index.txt │ │ └── thecreativeindependent.com.png │ ├── 003-two-point-oh │ │ └── index.txt │ ├── 004-list-lily │ │ ├── a.carapetis.com_csf.png │ │ ├── digitalfire.com.png │ │ ├── flow.png │ │ ├── index.txt │ │ └── parks.ca.gov_live_lakeorovillesra_emergency_spillway.png │ ├── 005-list-carly │ │ ├── gmail.com.png │ │ ├── index.txt │ │ ├── prostheticknowledge.tumblr.com.png │ │ ├── things-editors-like.png │ │ └── unti-tled.com.png │ ├── 006-toby │ │ ├── arena.png │ │ ├── currentcondition.org.png │ │ ├── granolashotgun.com.png │ │ ├── index.txt │ │ └── wagon.png │ ├── 007-seth │ │ ├── glittering.blue.png │ │ ├── index.txt │ │ ├── media.ccc.de.png │ │ ├── nigelslaterrecipes.png │ │ └── paradisebackyard.blogspost.com.png │ ├── 008-jon │ │ ├── bringatrailer.com.png │ │ ├── howmanyofme.com.png │ │ ├── index.txt │ │ ├── n2yo.com_space-station.png │ │ └── wikipedia.featured.png │ ├── 009-yosh │ │ ├── blog.acolyer.org.png │ │ ├── cookingwithdog.png │ │ ├── doc.rust-lang.org.png │ │ ├── index.txt │ │ └── lwn.net.png │ ├── 010-andrew │ │ ├── index.txt │ │ ├── insecam.org.png │ │ ├── shadertoy.com.png │ │ ├── siggraph.png │ │ └── thingsmagazine.net.png │ ├── 011-olly │ │ ├── gx1000.png │ │ ├── honestjons.com.png │ │ ├── index.txt │ │ ├── milesdavis.png │ │ └── olafureliasson.net.png │ ├── 012-authentic │ │ ├── authentic.svg │ │ └── index.txt │ ├── 013-emma │ │ ├── horvitz.png │ │ ├── index.txt │ │ ├── no-home-like-place.com.png │ │ ├── radio.garden.png │ │ └── savedbythe-bellhooks.tumblr.com.png │ ├── 014-matthew │ │ ├── chneukirchen.org_trivium.png │ │ ├── democracynow.org.png │ │ ├── diaxa.com.png │ │ ├── index.txt │ │ └── treemap.png │ ├── 015-hassan │ │ ├── ebay.com.png │ │ ├── index.txt │ │ ├── mixesdb.com.png │ │ ├── sharknosemeeting.com.png │ │ └── wallothnesch.com.png │ ├── 016-update │ │ ├── custom-css.png │ │ └── index.txt │ ├── 017-paul │ │ ├── aaaaarg.fail.png │ │ ├── athology.rhizome.org.png │ │ ├── gifcities.org.png │ │ ├── index.txt │ │ └── twitch.com.png │ ├── 018-ezra │ │ ├── deverloper.mozilla.org.png │ │ ├── index.txt │ │ ├── mrleckey.png │ │ ├── residentadvisor.net.png │ │ └── taborrobak.com.png │ ├── 019-gemma │ │ ├── arena.png │ │ ├── humunivers.png │ │ ├── index.txt │ │ ├── thegradient.png │ │ └── tree-fall.png │ ├── 020-dat │ │ ├── 1-data-storage.svg │ │ ├── 2-data-storage.svg │ │ ├── 3-data-storage.svg │ │ ├── data-storage.svg │ │ └── index.txt │ ├── 021-ben │ │ ├── bdif.png │ │ ├── index.txt │ │ ├── manifestos.png │ │ ├── reddit.png │ │ └── surfstation.png │ ├── 022-lukas │ │ ├── bit-player.png │ │ ├── gimmickbook.png │ │ ├── index.txt │ │ ├── noaa.png │ │ └── truisms.png │ ├── 023-kalli │ │ ├── earth.png │ │ ├── if-you-leave.png │ │ ├── index.txt │ │ ├── propspaper.png │ │ └── worrydream.png │ ├── 024-uli │ │ ├── 032c-manifesto.png │ │ ├── arena-explore.png │ │ ├── babel.png │ │ ├── index.txt │ │ └── webshit.png │ ├── 025-entropy │ │ ├── entropy.svg │ │ └── index.txt │ └── index.txt ├── faq │ └── index.txt └── intro │ ├── index.txt │ └── loop.vtt ├── index.html ├── package.json └── src ├── components ├── css.js ├── entry-blog.js ├── entry.js ├── format.js ├── input │ ├── checkbox.js │ ├── color.js │ ├── data.js │ ├── dropdown.js │ ├── index.js │ ├── range.js │ ├── tags.js │ ├── text.js │ ├── textarea.js │ └── typography.js ├── intro-slideshow.js ├── intro-video.js ├── loading.js └── search.js ├── containers ├── blog.js ├── content.js ├── entry-list.js ├── entry-navigation.js ├── intro.js ├── notification.js ├── notifications │ ├── customize-design.js │ ├── index.js │ └── p2p.js ├── panel-container.js ├── panel-entry.js ├── panel-options.js ├── suggestions.js └── wrapper.js ├── db ├── dat.js ├── entries.js ├── index.js ├── localstorage.js ├── options.js └── user.js ├── design ├── fonts.css ├── index.css ├── index.js ├── simplecolorpicker.css ├── typography.js ├── user.css └── utils.js ├── helpers ├── scale.js └── time.js ├── index.js ├── lib ├── blog.js ├── design.js ├── designs.js ├── entries.js ├── scale.js └── time.js ├── plugins ├── app.js ├── data-storage.js ├── entries.js ├── features.js ├── index.js ├── logger.js ├── notifications.js ├── options-typography.json ├── options.js ├── scroll.js ├── search.js ├── staging.js ├── ui.js └── user.js ├── sandbox ├── index.js ├── input.js └── interface.js └── templates ├── about.js ├── blog-entry.js ├── blog.js ├── data.js ├── faq.js ├── home.js ├── intro.js ├── panel.js ├── reset.js └── suggestions.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "sourceMap": false, 3 | "presets": [ 4 | ["@babel/preset-env", { 5 | "targets": { 6 | "browsers": ["last 2 versions"] 7 | } 8 | }] 9 | ], 10 | "plugins": [ 11 | "@babel/plugin-transform-async-to-generator" 12 | ] 13 | } -------------------------------------------------------------------------------- /.datignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # system 2 | .DS_Store 3 | .well-known 4 | 5 | # logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # dependency directories 11 | node_modules 12 | 13 | # database 14 | .db 15 | .dat 16 | 17 | # directories 18 | bundles 19 | 20 | # files 21 | credentials.json 22 | bundle.css 23 | bundle.js 24 | dat.json 25 | *.mp4 26 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

🕗 hardly everything

2 |
your feed with a cadence
3 |
hardlyeverything.com
4 | 5 | ## Features 6 | 7 | - **amplify**: be reminded of the quiet things 8 | - **suppress**: rate limit the loud things 9 | - **prioritize**: use periods of rest with custom intervals 10 | - **customize**: choose your own colors and typography 11 | - **ownership**: no database; only local-storage 12 | 13 | ## Philosophy 14 | 15 | Popular apps and sites often share a common element today; *the feed*. It looks like Facebook’s timeline, or Buzzfeed’s homepage—an endlessly updating stream of content, designed to keep you returning, and spending more time. 16 | 17 | **Hardly Everything** attempts to circumvent these corporate feeds by supplying you with an *anti-feed*. Your feed closely resembles those already familiar—a scrolling list, at essence. You add things to this list, but when doing so prioritize their importance to you by defining a period of **rest**. 18 | 19 | After clicking an entry, it disappears from your feed for the duration of it’s rest. Your feed updates once per day, there is never something new until tomorrow, a natural cycle, shared by a period of another kind of rest. 20 | 21 | Your entries can rest anywhere from a day to a year. Link to a page you like to revisit often, or a page you want to remember in a few months. Link to something once every year, to free you from the impulse, if you’d like. 22 | 23 | This tool is not a rejection of an interface, but a prompt to question who the interface serves, and why. It is also meant to be immediately useful, and hopefully you will find it that way, too. 24 | 25 | ## Access 26 | 27 | You can use Hardly Everything by visiting [https://hardlyeverything.com](https://hardlyeverything.com), [dat://hardlyeverything.com](dat://hardlyeverything.com), and it’s [unique Dat hash](dat://a1c54e094020e2f898b6061ed9c0dbe60d4d18612b4226d9c916011c415f7875). [Dat](http://datproject.org) is a distributed data protocol being used to build the future of the p2p/decentralized web. 28 | 29 | ## Todo 30 | 31 | Hardly Everything is in active development: 32 | 33 | ### 2.2.0 34 | 35 | - [ ] Better p2p/local ui 36 | - [ ] Internationalization 37 | - [ ] Entropy option 38 | - [ ] Auto-hide option 39 | -------------------------------------------------------------------------------- /assets/fonts/AUTHENTIC-Sans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/AUTHENTIC-Sans.woff -------------------------------------------------------------------------------- /assets/fonts/AUTHENTIC-Sans.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/AUTHENTIC-Sans.woff2 -------------------------------------------------------------------------------- /assets/fonts/AUTHENTIC-Untitled.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/AUTHENTIC-Untitled.woff -------------------------------------------------------------------------------- /assets/fonts/AUTHENTIC-Untitled.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/AUTHENTIC-Untitled.woff2 -------------------------------------------------------------------------------- /assets/fonts/Astloch-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Astloch-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/CoolS-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/CoolS-Regular.otf -------------------------------------------------------------------------------- /assets/fonts/DSEG7Classic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/DSEG7Classic-Bold.woff -------------------------------------------------------------------------------- /assets/fonts/DSEG7Classic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/DSEG7Classic-Bold.woff2 -------------------------------------------------------------------------------- /assets/fonts/DSEG7Classic-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/DSEG7Classic-Light.woff -------------------------------------------------------------------------------- /assets/fonts/DSEG7Classic-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/DSEG7Classic-Light.woff2 -------------------------------------------------------------------------------- /assets/fonts/JRUG_PUNK.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/JRUG_PUNK.ttf -------------------------------------------------------------------------------- /assets/fonts/Pecita.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Pecita.otf -------------------------------------------------------------------------------- /assets/fonts/Reglo-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Reglo-Bold.otf -------------------------------------------------------------------------------- /assets/fonts/SFMono-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/SFMono-Regular.otf -------------------------------------------------------------------------------- /assets/fonts/SpaceMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/SpaceMono-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Spectral-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Spectral-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Spectral-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Spectral-ExtraLight.ttf -------------------------------------------------------------------------------- /assets/fonts/Spectral-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Spectral-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Sporting_Grotesque-Bold_web.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Sporting_Grotesque-Bold_web.woff -------------------------------------------------------------------------------- /assets/fonts/Sporting_Grotesque-Bold_web.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Sporting_Grotesque-Bold_web.woff2 -------------------------------------------------------------------------------- /assets/fonts/Sporting_Grotesque-Regular_web.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Sporting_Grotesque-Regular_web.woff -------------------------------------------------------------------------------- /assets/fonts/Sporting_Grotesque-Regular_web.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Sporting_Grotesque-Regular_web.woff2 -------------------------------------------------------------------------------- /assets/fonts/UnifrakturMaguntia.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/UnifrakturMaguntia.ttf -------------------------------------------------------------------------------- /assets/fonts/WorkSans-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/WorkSans-Black.woff -------------------------------------------------------------------------------- /assets/fonts/WorkSans-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/WorkSans-Black.woff2 -------------------------------------------------------------------------------- /assets/fonts/WorkSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/WorkSans-Regular.woff -------------------------------------------------------------------------------- /assets/fonts/WorkSans-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/WorkSans-Regular.woff2 -------------------------------------------------------------------------------- /assets/fonts/WorkSans-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/WorkSans-Thin.woff -------------------------------------------------------------------------------- /assets/fonts/WorkSans-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/WorkSans-Thin.woff2 -------------------------------------------------------------------------------- /assets/fonts/Wremena-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Wremena-Bold.woff -------------------------------------------------------------------------------- /assets/fonts/Wremena-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Wremena-Light.woff -------------------------------------------------------------------------------- /assets/fonts/Yatra-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/Yatra-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/YoungSerif-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/YoungSerif-Regular.otf -------------------------------------------------------------------------------- /assets/fonts/junicode-boldcondensed-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/junicode-boldcondensed-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/junicode-boldcondensed-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/junicode-boldcondensed-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/junicode-regularcondensed-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/junicode-regularcondensed-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/junicode-regularcondensed-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/junicode-regularcondensed-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/labmono-regular-web.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/labmono-regular-web.woff -------------------------------------------------------------------------------- /assets/fonts/labmono-regular-web.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/labmono-regular-web.woff2 -------------------------------------------------------------------------------- /assets/fonts/lunchtype22-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype22-light-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/lunchtype22-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype22-light-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/lunchtype22-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype22-medium-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/lunchtype22-medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype22-medium-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/lunchtype24-light-expanded-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype24-light-expanded-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/lunchtype24-light-expanded-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype24-light-expanded-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/lunchtype24-medium-expanded-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype24-medium-expanded-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/lunchtype24-medium-expanded-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype24-medium-expanded-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/lunchtype25-light_condensed-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype25-light_condensed-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/lunchtype25-light_condensed-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype25-light_condensed-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/lunchtype25-medium-condensed-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype25-medium-condensed-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/lunchtype25-medium-condensed-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/lunchtype25-medium-condensed-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/manifont-grotesk_book-dot.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/manifont-grotesk_book-dot.woff -------------------------------------------------------------------------------- /assets/fonts/manifont-grotesk_book.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/manifont-grotesk_book.woff -------------------------------------------------------------------------------- /assets/fonts/terminal-grotesque-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/terminal-grotesque-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/terminal-grotesque-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/terminal-grotesque-webfont.woff2 -------------------------------------------------------------------------------- /assets/fonts/ume-gothic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/ume-gothic-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/ume-mincho-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/fonts/ume-mincho-webfont.woff -------------------------------------------------------------------------------- /assets/icon-eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | eye 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/icon-settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/icon-trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/bg.jpg -------------------------------------------------------------------------------- /assets/img/big-data-no-thanks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/big-data-no-thanks.png -------------------------------------------------------------------------------- /assets/img/garden.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/garden.jpg -------------------------------------------------------------------------------- /assets/img/posterframe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/posterframe.jpg -------------------------------------------------------------------------------- /assets/img/posterframe2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/posterframe2.jpg -------------------------------------------------------------------------------- /assets/img/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/screenshot-2.png -------------------------------------------------------------------------------- /assets/img/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/screenshot-3.png -------------------------------------------------------------------------------- /assets/img/screenshot-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/screenshot-4.png -------------------------------------------------------------------------------- /assets/img/screenshot-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/screenshot-5.png -------------------------------------------------------------------------------- /assets/img/screenshot-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/screenshot-6.png -------------------------------------------------------------------------------- /assets/img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/img/screenshot.png -------------------------------------------------------------------------------- /assets/plyr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/social-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/assets/social-image.png -------------------------------------------------------------------------------- /content/about/index.txt: -------------------------------------------------------------------------------- 1 | title: About 2 | ---- 3 | visible: true 4 | ---- 5 | credit: 6 | - title: Open source libraries 7 | libraries: 8 | - title: Choo 9 | url: https://github.com/choojs/choo 10 | - title: Nanocomponent 11 | url: https://github.com/choojs/nanocomponent 12 | - title: Sheetify 13 | url: https://github.com/stackcss/sheetify 14 | - title: Browserify 15 | url: https://github.com/browserify/browserify 16 | - title: Dayjs 17 | url: https://github.com/iamkun/dayjs 18 | - title: Gr8 19 | url: https://gr8.style 20 | ---- 21 | text: 22 | 23 | Most popular apps and sites today often share a common element; the feed. It looks like Facebook’s timeline, or Buzzfeed’s homepage—an endlessly updating stream of content, designed to keep you returning, and spending more time. 24 | 25 | You frequently hear of us feeling burnt out by this “drinking from a firehose.” Of course, these products know that, and are increasingly implementing steps to filter what you see and what you don’t based in part on what keeps you returning—a perpetually shifting mix, creating what has become known as the filter bubble, an endless source of FOMO (fear of missing out), and other things. 26 | 27 | Hardly Everything attempts to circumnavigate these corporate feeds by supplying you with a feed of your own. 28 | 29 | Your feed closely resembles those already familiar—a scrolling list, at essence, but rather than algorithms determining what’s displayed we introduce timescales. You add things to this list, but when doing so prioritize their importance to you by defining a period of rest, long and short and everywhere in-between. 30 | 31 | The notion of a rest is borrowed from musical notation—a determined period of time between notes. Just as music has a cadence, consider your attention’s rhythm while consuming a feed. This is why your feed has a pulse, or a pace, defined by you. 32 | 33 | After clicking an entry, it disappears from your feed for the duration of it’s rest. Your feed updates once per day, there is never something new until tomorrow, a natural cycle, partitioned by a period of another kind of rest; sleep. 34 | 35 | Your entries can rest anywhere from a day to a year. Link to a page you like to revisit often, or a page you want to remember in a few months. 36 | 37 | Link directly to someone’s Instagram page, instead of scrolling through Instagram’s feed, and be reminded of it once every two weeks. 38 | 39 | Link to something once every year, to free you from the impulse, if you’d like. 40 | 41 | This tool is not a rejection of an interface, but a prompt to question who the interface serves, and why. It is also meant to be immediately useful, and hopefully you’ll find it that way, too. 42 | 43 | Hardly Everything was created and is maintained by [Jon-Kyle](https://jon-kyle.com). 44 | 45 | ---- -------------------------------------------------------------------------------- /content/blog/001-list-jon-kyle/desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/001-list-jon-kyle/desktop.png -------------------------------------------------------------------------------- /content/blog/001-list-jon-kyle/index.txt: -------------------------------------------------------------------------------- 1 | title: Jon-Kyle’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-05-30 6 | ---- 7 | author: Jon-Kyle 8 | ---- 9 | authorUrl: https://jon-kyle.com 10 | ---- 11 | category: list 12 | ---- 13 | image: true 14 | ---- 15 | links: 16 | day: 17 | title: Mount Wilson Tower Cam 18 | url: http://obs.astro.ucla.edu/towercam.htm 19 | img: obs.astro.ucla.edu.png 20 | week: 21 | title: Walking in LA 22 | url: http://walkinginla.com 23 | img: walkinginla.com.png 24 | month: 25 | title: Primitive Technology 26 | url: https://youtube.com/channel/UCAL3JXZSzSm8AlZyD3nQdBA 27 | img: primitivetechnology.jpg 28 | year: 29 | title: ofHouses 30 | url: http://ofhouses.com 31 | img: ofhouses.com.png 32 | -------------------------------------------------------------------------------- /content/blog/001-list-jon-kyle/obs.astro.ucla.edu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/001-list-jon-kyle/obs.astro.ucla.edu.png -------------------------------------------------------------------------------- /content/blog/001-list-jon-kyle/ofhouses.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/001-list-jon-kyle/ofhouses.com.png -------------------------------------------------------------------------------- /content/blog/001-list-jon-kyle/primitivetechnology.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/001-list-jon-kyle/primitivetechnology.jpg -------------------------------------------------------------------------------- /content/blog/001-list-jon-kyle/walkinginla.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/001-list-jon-kyle/walkinginla.com.png -------------------------------------------------------------------------------- /content/blog/002-list-laurel/billwurtz.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/002-list-laurel/billwurtz.com.png -------------------------------------------------------------------------------- /content/blog/002-list-laurel/delinear.info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/002-list-laurel/delinear.info.png -------------------------------------------------------------------------------- /content/blog/002-list-laurel/gossipsweb.net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/002-list-laurel/gossipsweb.net.png -------------------------------------------------------------------------------- /content/blog/002-list-laurel/index.txt: -------------------------------------------------------------------------------- 1 | title: Laurel’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-01 6 | ---- 7 | author: Laurel Schwulst 8 | ---- 9 | authorUrl: http://laurelschwulst.com/ 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Delinear 16 | url: http://delinear.info 17 | img: delinear.info.png 18 | week: 19 | title: The Creative Independent 20 | url: https://thecreativeindependent.com 21 | img: thecreativeindependent.com.png 22 | month: 23 | title: Bill Wurtz 24 | url: http://billwurtz.com 25 | img: billwurtz.com.png 26 | year: 27 | title: Gossip Web 28 | url: http://gossipsweb.net 29 | img: gossipsweb.net.png 30 | -------------------------------------------------------------------------------- /content/blog/002-list-laurel/thecreativeindependent.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/002-list-laurel/thecreativeindependent.com.png -------------------------------------------------------------------------------- /content/blog/003-two-point-oh/index.txt: -------------------------------------------------------------------------------- 1 | title: Hardly an Update; What’s New? 2 | ---- 3 | date: 2018-06-15 4 | ---- 5 | category: update 6 | ---- 7 | text: 8 | 9 | Fresh release! Lots of new stuff and all sorts of fixes. 10 | 11 | ### New features 12 | 13 | - Fresh new homepage for new visitors. 14 | - The **Blog**, an area for updates and notes. 15 | - The [**FAQ**](/faq). 16 | - Tons of new **open source fonts**. 17 | - New options like **uppercase** and hyphenate. 18 | - Too many interface updates to mention. 19 | 20 | ### Technical details 21 | 22 | - Swapped Preact for [**Choo**](https://github.com/choojs/choo)! 🎉 23 | - Swapped moment.js for [**day.js**](https://github.com/iamkun/dayjs). 24 | - Deploys over [**Dat**](https://datproject.org) for p2p goodness and offline accessibility. 25 | - Lighterweight [color picker](https://github.com/superguigui/simple-color-picker) and [tag](https://github.com/developit/tags-input) fields. 26 | - Removed Google Fonts. -------------------------------------------------------------------------------- /content/blog/004-list-lily/a.carapetis.com_csf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/004-list-lily/a.carapetis.com_csf.png -------------------------------------------------------------------------------- /content/blog/004-list-lily/digitalfire.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/004-list-lily/digitalfire.com.png -------------------------------------------------------------------------------- /content/blog/004-list-lily/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/004-list-lily/flow.png -------------------------------------------------------------------------------- /content/blog/004-list-lily/index.txt: -------------------------------------------------------------------------------- 1 | title: Lily’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-10 6 | ---- 7 | author: Lily Clark 8 | ---- 9 | authorUrl: http://lily-clark.com/ 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Curve Shortening Flow 16 | url: http://a.carapetis.com/csf 17 | img: a.carapetis.com_csf.png 18 | week: 19 | title: Lake Oroville SRA Spillway Live Stream 20 | url: http://parks.ca.gov/live/lakeorovillesra_emergency_spillway 21 | img: parks.ca.gov_live_lakeorovillesra_emergency_spillway.png 22 | month: 23 | title: Digital Fire 24 | url: https://digitalfire.com/4sight/education 25 | img: digitalfire.com.png 26 | year: 27 | title: Low-Reynolds-Number Flows 28 | url: https://youtube.com/watch?list=PLnW2cf4eywXPjEIA21qOJ7_rCWVEcsHdC&time_continue=1045&v=51-6QCJTAjU 29 | img: flow.png 30 | -------------------------------------------------------------------------------- /content/blog/004-list-lily/parks.ca.gov_live_lakeorovillesra_emergency_spillway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/004-list-lily/parks.ca.gov_live_lakeorovillesra_emergency_spillway.png -------------------------------------------------------------------------------- /content/blog/005-list-carly/gmail.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/005-list-carly/gmail.com.png -------------------------------------------------------------------------------- /content/blog/005-list-carly/index.txt: -------------------------------------------------------------------------------- 1 | title: Carly Ayres’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-9 6 | ---- 7 | author: Carly Ayres 8 | ---- 9 | authorUrl: http://carlyayres.com/ 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Gmail 16 | url: https://mail.google.com/mail 17 | img: gmail.com.png 18 | week: 19 | title: Things Editors Like 20 | url: https://nytimes.com/column/things-editors-like 21 | img: things-editors-like.png 22 | month: 23 | title: Unti-titled New York 24 | url: http://unti-tled.com/new-york 25 | img: unti-tled.com.png 26 | year: 27 | title: Prosthetic Knowledge 28 | url: http://prostheticknowledge.tumblr.com 29 | img: prostheticknowledge.tumblr.com.png 30 | -------------------------------------------------------------------------------- /content/blog/005-list-carly/prostheticknowledge.tumblr.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/005-list-carly/prostheticknowledge.tumblr.com.png -------------------------------------------------------------------------------- /content/blog/005-list-carly/things-editors-like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/005-list-carly/things-editors-like.png -------------------------------------------------------------------------------- /content/blog/005-list-carly/unti-tled.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/005-list-carly/unti-tled.com.png -------------------------------------------------------------------------------- /content/blog/006-toby/arena.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/006-toby/arena.png -------------------------------------------------------------------------------- /content/blog/006-toby/currentcondition.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/006-toby/currentcondition.org.png -------------------------------------------------------------------------------- /content/blog/006-toby/granolashotgun.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/006-toby/granolashotgun.com.png -------------------------------------------------------------------------------- /content/blog/006-toby/index.txt: -------------------------------------------------------------------------------- 1 | title: Toby Shorin’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-11 6 | ---- 7 | author: Toby Shorin 8 | ---- 9 | authorUrl: https://tobyshorin.com/ 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Are.na / Toby Shorin / Index 16 | url: https://are.na/toby-shorin/index 17 | img: arena.png 18 | week: 19 | title: Granola Shotgun 20 | url: https://granolashotgun.com 21 | img: granolashotgun.com.png 22 | month: 23 | title: Current Condition 24 | url: http://currentcondition.org 25 | img: currentcondition.org.png 26 | year: 27 | title: How to Fall Off the Wagon 28 | url: https://ribbonfarm.com/2014/09/03/how-to-fall-off-the-wagon 29 | img: wagon.png 30 | -------------------------------------------------------------------------------- /content/blog/006-toby/wagon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/006-toby/wagon.png -------------------------------------------------------------------------------- /content/blog/007-seth/glittering.blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/007-seth/glittering.blue.png -------------------------------------------------------------------------------- /content/blog/007-seth/index.txt: -------------------------------------------------------------------------------- 1 | title: Seth Thompson’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-12 6 | ---- 7 | author: Seth Thompson 8 | ---- 9 | authorUrl: https://seththompson.org/ 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Glittering Blue 16 | url: https://glittering.blue 17 | img: glittering.blue.png 18 | week: 19 | title: Nigel Slater recipes 20 | url: https://theguardian.com/lifeandstyle/series/nigelslaterrecipes 21 | img: nigelslaterrecipes.png 22 | month: 23 | title: Paradise Backyard 24 | url: https://paradisebackyard.blogspot.com 25 | img: paradisebackyard.blogspost.com.png 26 | year: 27 | title: media.ccc.de 28 | url: https://media.ccc.de/c/34c3 29 | img: media.ccc.de.png 30 | -------------------------------------------------------------------------------- /content/blog/007-seth/media.ccc.de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/007-seth/media.ccc.de.png -------------------------------------------------------------------------------- /content/blog/007-seth/nigelslaterrecipes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/007-seth/nigelslaterrecipes.png -------------------------------------------------------------------------------- /content/blog/007-seth/paradisebackyard.blogspost.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/007-seth/paradisebackyard.blogspost.com.png -------------------------------------------------------------------------------- /content/blog/008-jon/bringatrailer.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/008-jon/bringatrailer.com.png -------------------------------------------------------------------------------- /content/blog/008-jon/howmanyofme.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/008-jon/howmanyofme.com.png -------------------------------------------------------------------------------- /content/blog/008-jon/index.txt: -------------------------------------------------------------------------------- 1 | title: Jon Gacnik’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-13 6 | ---- 7 | author: Jon Gacnik 8 | ---- 9 | authorUrl: https://jongacnik.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: n2yo / space station 16 | url: https://n2yo.com/space-station 17 | img: n2yo.com_space-station.png 18 | week: 19 | title: Bring A Trailer 20 | url: https://bringatrailer.com 21 | img: bringatrailer.com.png 22 | month: 23 | title: Wikipedia Featured Content 24 | url: https://en.wikipedia.org/wiki/Portal:Featured_content 25 | img: wikipedia.featured.png 26 | year: 27 | title: How Many of Me 28 | url: http://howmanyofme.com 29 | img: howmanyofme.com.png 30 | -------------------------------------------------------------------------------- /content/blog/008-jon/n2yo.com_space-station.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/008-jon/n2yo.com_space-station.png -------------------------------------------------------------------------------- /content/blog/008-jon/wikipedia.featured.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/008-jon/wikipedia.featured.png -------------------------------------------------------------------------------- /content/blog/009-yosh/blog.acolyer.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/009-yosh/blog.acolyer.org.png -------------------------------------------------------------------------------- /content/blog/009-yosh/cookingwithdog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/009-yosh/cookingwithdog.png -------------------------------------------------------------------------------- /content/blog/009-yosh/doc.rust-lang.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/009-yosh/doc.rust-lang.org.png -------------------------------------------------------------------------------- /content/blog/009-yosh/index.txt: -------------------------------------------------------------------------------- 1 | title: Yoshua Wuyts’ list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-13 6 | ---- 7 | author: Yoshua Wuyts 8 | ---- 9 | authorUrl: https://yoshuawuyts.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: LWN.net 16 | url: https://lwn.net 17 | img: lwn.net.png 18 | week: 19 | title: The Morning Paper 20 | url: https://blog.acolyer.org 21 | img: blog.acolyer.org.png 22 | month: 23 | title: Rust Documentation 24 | url: https://doc.rust-lang.org/std 25 | img: doc.rust-lang.org.png 26 | year: 27 | title: Cooking With Dog 28 | url: https://youtube.com/user/cookingwithdog 29 | img: cookingwithdog.png 30 | -------------------------------------------------------------------------------- /content/blog/009-yosh/lwn.net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/009-yosh/lwn.net.png -------------------------------------------------------------------------------- /content/blog/010-andrew/index.txt: -------------------------------------------------------------------------------- 1 | title: Andrew Ohlmann’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-22 6 | ---- 7 | author: Andrew Ohlmann 8 | ---- 9 | authorUrl: https://andrewohlmann.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Shadertoy 16 | url: https://shadertoy.com/results?query=&sort=newest 17 | img: shadertoy.com.png 18 | week: 19 | title: Things Magazine 20 | url: http://thingsmagazine.net 21 | img: thingsmagazine.net.png 22 | month: 23 | title: Insecam 24 | url: https://insecam.org/en/bytag/River 25 | img: insecam.org.png 26 | year: 27 | title: Siggraph Youtube 28 | url: https://youtube.com/results?search_query=siggraph 29 | img: siggraph.png 30 | -------------------------------------------------------------------------------- /content/blog/010-andrew/insecam.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/010-andrew/insecam.org.png -------------------------------------------------------------------------------- /content/blog/010-andrew/shadertoy.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/010-andrew/shadertoy.com.png -------------------------------------------------------------------------------- /content/blog/010-andrew/siggraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/010-andrew/siggraph.png -------------------------------------------------------------------------------- /content/blog/010-andrew/thingsmagazine.net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/010-andrew/thingsmagazine.net.png -------------------------------------------------------------------------------- /content/blog/011-olly/gx1000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/011-olly/gx1000.png -------------------------------------------------------------------------------- /content/blog/011-olly/honestjons.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/011-olly/honestjons.com.png -------------------------------------------------------------------------------- /content/blog/011-olly/index.txt: -------------------------------------------------------------------------------- 1 | title: Olly Bromham’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-27 6 | ---- 7 | author: Olly Bromham 8 | ---- 9 | authorUrl: https://ollybromham.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Honest Jons 16 | url: https://honestjons.com 17 | img: honestjons.com.png 18 | week: 19 | title: Olafur Eliasson 20 | url: http://olafureliasson.net 21 | img: olafureliasson.net.png 22 | month: 23 | title: gx1000 24 | url: https://instagram.com/gx1000 25 | img: gx1000.png 26 | year: 27 | title: Door Does Impression of Miles Davis 28 | url: https://youtube.com/watch?v=wwOipTXvNNo 29 | img: milesdavis.png 30 | -------------------------------------------------------------------------------- /content/blog/011-olly/milesdavis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/011-olly/milesdavis.png -------------------------------------------------------------------------------- /content/blog/011-olly/olafureliasson.net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/011-olly/olafureliasson.net.png -------------------------------------------------------------------------------- /content/blog/012-authentic/index.txt: -------------------------------------------------------------------------------- 1 | title: Hardly Authentic 2 | ---- 3 | date: 2018-06-28 4 | ---- 5 | text: 6 | 7 | Removing the Google Fonts dependency was one of the most important new features of v2. While providing a convenient API for embedding some of the best open source type, it’s speculated the traffic provides an entry point1 into your site’s traffic through which Google can extract valuable data2. 8 | 9 | Choosing the type was made easier thanks to helpful tools like [Raphaël Bastide](https://raphaelbastide.com/)’s [Use & Modify](https://usemodify.com/), but one which immediately came to mind was [Authentic Sans](https://authentic.website/#sans) by Authentic. Imagine the gratitude felt when Authentic donated Authentic Untitled to the selection of available typography, too! 10 | 11 | Huge ups to the friends at [Authentic](https://authentic.website). Gratuitous type specimen below. 12 | 13 | 1. [Google Fonts GDPR Compliance](https://github.com/google/fonts/issues/1495) 14 | 2. [Host webfonts on your own server](http://kernelpanik.net/host-webfonts-on-own-server/) 15 | 16 |
17 | 18 | ![](/content/blog/012-authentic/authentic.svg) 19 | 20 |
-------------------------------------------------------------------------------- /content/blog/013-emma/horvitz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/013-emma/horvitz.png -------------------------------------------------------------------------------- /content/blog/013-emma/index.txt: -------------------------------------------------------------------------------- 1 | title: Emma Rae Norton’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-06-29 6 | ---- 7 | author: Emma Rae Norton 8 | ---- 9 | authorUrl: http://marceldochamp.net 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Radio Garden 16 | url: http://radio.garden/live 17 | img: radio.garden.png 18 | week: 19 | title: horvitz-457x500.jpg 20 | url: http://pietmondriaan.com/pm/wp-content/uploads/2010/04/horvitz-457x500.jpg 21 | img: horvitz.png 22 | month: 23 | title: Saved By The Bell Hooks 24 | url: https://savedbythe-bellhooks.tumblr.com 25 | img: savedbythe-bellhooks.tumblr.com.png 26 | year: 27 | title: No Home Like Place 28 | url: https://no-home-like-place.com 29 | img: no-home-like-place.com.png 30 | -------------------------------------------------------------------------------- /content/blog/013-emma/no-home-like-place.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/013-emma/no-home-like-place.com.png -------------------------------------------------------------------------------- /content/blog/013-emma/radio.garden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/013-emma/radio.garden.png -------------------------------------------------------------------------------- /content/blog/013-emma/savedbythe-bellhooks.tumblr.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/013-emma/savedbythe-bellhooks.tumblr.com.png -------------------------------------------------------------------------------- /content/blog/014-matthew/chneukirchen.org_trivium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/014-matthew/chneukirchen.org_trivium.png -------------------------------------------------------------------------------- /content/blog/014-matthew/democracynow.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/014-matthew/democracynow.org.png -------------------------------------------------------------------------------- /content/blog/014-matthew/diaxa.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/014-matthew/diaxa.com.png -------------------------------------------------------------------------------- /content/blog/014-matthew/index.txt: -------------------------------------------------------------------------------- 1 | title: Matthew Spencer’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-07-03 6 | ---- 7 | author: Matthew Spencer 8 | ---- 9 | authorUrl: https://matthewspencer.me 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Democracy Now 16 | url: https://democracynow.org 17 | img: democracynow.org.png 18 | week: 19 | title: Trivium 20 | url: http://chneukirchen.org/trivium 21 | img: chneukirchen.org_trivium.png 22 | month: 23 | title: NYC Tree Map 24 | url: https://tree-map.nycgovparks.org 25 | img: treemap.png 26 | year: 27 | title: Diaxa 28 | url: http://diaxa.com 29 | img: diaxa.com.png 30 | -------------------------------------------------------------------------------- /content/blog/014-matthew/treemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/014-matthew/treemap.png -------------------------------------------------------------------------------- /content/blog/015-hassan/ebay.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/015-hassan/ebay.com.png -------------------------------------------------------------------------------- /content/blog/015-hassan/index.txt: -------------------------------------------------------------------------------- 1 | title: Hassan Rahim’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-07-05 6 | ---- 7 | author: Hassan Rahim 8 | ---- 9 | authorUrl: http://hassanrahim.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Ebay 16 | url: https://ebay.com 17 | img: ebay.com.png 18 | week: 19 | title: MixesDB 20 | url: https://mixesdb.com 21 | img: mixesdb.com.png 22 | month: 23 | title: Wallothnesch 24 | url: https://wallothnesch.com 25 | img: wallothnesch.com.png 26 | year: 27 | title: Sharknose Meeting 28 | url: http://sharknosemeeting.com 29 | img: sharknosemeeting.com.png 30 | -------------------------------------------------------------------------------- /content/blog/015-hassan/mixesdb.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/015-hassan/mixesdb.com.png -------------------------------------------------------------------------------- /content/blog/015-hassan/sharknosemeeting.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/015-hassan/sharknosemeeting.com.png -------------------------------------------------------------------------------- /content/blog/015-hassan/wallothnesch.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/015-hassan/wallothnesch.com.png -------------------------------------------------------------------------------- /content/blog/016-update/custom-css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/016-update/custom-css.png -------------------------------------------------------------------------------- /content/blog/016-update/index.txt: -------------------------------------------------------------------------------- 1 | title: Hardly a New Feature: Custom CSS 2 | ---- 3 | date: 2018-07-08 4 | ---- 5 | text: 6 | 7 | If you navigate to your [Options](/panel/options) you’ll see something fresh—**Edit your custom CSS**. Clicking this new option will expand to display CSS you can modify to tweak your design beyond the capabilities provided by the interface. 8 | 9 | ![](/content/blog/016-update/custom-css.png) 10 | 11 | All of the values are made available to you via CSS variables, which you can always revert back to by clicking **reset**. You can use handy CSS methods like `calc`, which is for doing simple mathematic operations on variables such as `spacing`. 12 | 13 | Possibilities include setting a background image, or selecting any font installed on your local machine. For instance: 14 | 15 | ``` 16 | .design-container { 17 | font-family: "Suisse Intl Mono"; 18 | } 19 | ``` 20 | 21 | Hopefully this is useful making your feed even more personalized! 22 | -------------------------------------------------------------------------------- /content/blog/017-paul/aaaaarg.fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/017-paul/aaaaarg.fail.png -------------------------------------------------------------------------------- /content/blog/017-paul/athology.rhizome.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/017-paul/athology.rhizome.org.png -------------------------------------------------------------------------------- /content/blog/017-paul/gifcities.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/017-paul/gifcities.org.png -------------------------------------------------------------------------------- /content/blog/017-paul/index.txt: -------------------------------------------------------------------------------- 1 | title: Paul Soulellis ’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-07-07 6 | ---- 7 | author: Paul Soulellis 8 | ---- 9 | authorUrl: http://soulellis.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Twitch / IRL 16 | url: https://www.twitch.tv/directory/game/IRL 17 | img: twitch.com.png 18 | week: 19 | title: Net Art Anthology 20 | url: https://anthology.rhizome.org 21 | img: athology.rhizome.org.png 22 | month: 23 | title: aaaaarg 24 | url: https://aaaaarg.fail 25 | img: aaaaarg.fail.png 26 | year: 27 | title: GifCities 28 | url: https://gifcities.org 29 | img: gifcities.org.png 30 | -------------------------------------------------------------------------------- /content/blog/017-paul/twitch.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/017-paul/twitch.com.png -------------------------------------------------------------------------------- /content/blog/018-ezra/deverloper.mozilla.org.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/018-ezra/deverloper.mozilla.org.png -------------------------------------------------------------------------------- /content/blog/018-ezra/index.txt: -------------------------------------------------------------------------------- 1 | title: Ezra Miller’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-07-13 6 | ---- 7 | author: Ezra Miller 8 | ---- 9 | authorUrl: http://ezramiller.biz/ 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: MDN web docs 16 | url: https://developer.mozilla.org 17 | img: deverloper.mozilla.org.png 18 | week: 19 | title: Resident Advisor 20 | url: https://residentadvisor.net 21 | img: residentadvisor.net.png 22 | month: 23 | title: Tabor Robak 24 | url: http://taborrobak.com 25 | img: taborrobak.com.png 26 | year: 27 | title: Mark Leckey 28 | url: https://youtube.com/user/mrleckey 29 | img: mrleckey.png 30 | -------------------------------------------------------------------------------- /content/blog/018-ezra/mrleckey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/018-ezra/mrleckey.png -------------------------------------------------------------------------------- /content/blog/018-ezra/residentadvisor.net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/018-ezra/residentadvisor.net.png -------------------------------------------------------------------------------- /content/blog/018-ezra/taborrobak.com.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/018-ezra/taborrobak.com.png -------------------------------------------------------------------------------- /content/blog/019-gemma/arena.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/019-gemma/arena.png -------------------------------------------------------------------------------- /content/blog/019-gemma/humunivers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/019-gemma/humunivers.png -------------------------------------------------------------------------------- /content/blog/019-gemma/index.txt: -------------------------------------------------------------------------------- 1 | title: Gemma Copeland’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-07-16 6 | ---- 7 | author: Gemma Copeland 8 | ---- 9 | authorUrl: http://gemmacope.land 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Arena / Explore 16 | url: http://are.na/explore 17 | img: arena.png 18 | week: 19 | title: The Gradient 20 | url: https://walkerart.org/magazine/categories/design 21 | img: thegradient.png 22 | month: 23 | title: At Some Point This Tree Will Fall 24 | url: http://at-some-point-this-tree-will-fall.jack-wild.com 25 | img: tree-fall.png 26 | year: 27 | title: Human Universals 28 | url: https://condor.depaul.edu/mfiddler/hyphen/humunivers.htm 29 | img: humunivers.png 30 | -------------------------------------------------------------------------------- /content/blog/019-gemma/thegradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/019-gemma/thegradient.png -------------------------------------------------------------------------------- /content/blog/019-gemma/tree-fall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/019-gemma/tree-fall.png -------------------------------------------------------------------------------- /content/blog/020-dat/index.txt: -------------------------------------------------------------------------------- 1 | title: Enhanced Data Ownership 2 | ---- 3 | date: 2018-07-22 4 | ---- 5 | text: 6 | 7 | There’s a problem with sites and apps today. It’s almost guaranteed your personal data is stored with the service, and not with you. This makes it difficult to use your data elsewhere, and almost impossible to leave or use with other services. 8 | 9 | Since `v2`, Hardly Everything has supported saving your data locally with Dat when visiting in [Beaker Browser](https://beakerbrowser.org). Your data is written to your device, and you grant Hardly Everything permission to read and update it. Although functional, the interface hasn’t yet provided feedback about what form of storage is active, or a way to hot-swap between Dat archives. 10 | 11 | This update introduces a new **Data storage** option in the panel, and does just that. 12 | 13 |
14 | 15 |
16 | 17 | ![](/content/blog/020-dat/1-data-storage.svg) 18 | 19 |
20 | 21 |
22 | 23 | ![](/content/blog/020-dat/2-data-storage.svg) 24 | 25 |
26 | 27 |
28 | 29 | When visiting over HTTP your data is saved with [Localstorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), which stores your data locally, but isolated to the browser you’re visiting from. This avoids sending your data to a remote database, but also limits you from accessing it elsewhere, or sharing it with others should you choose. 30 | 31 | The updated **Data storage** option reflects your browser’s capabilities. *Local browser* indicates Dat is unavailable and Localstorage is used, however if Dat is available it reads *Select an archive*. 32 | 33 |
34 | 35 | ![](/content/blog/020-dat/3-data-storage.svg) 36 | 37 |
38 | 39 | Selecting an archive by clicking the option allows you to either select an existing archive containing Hardly Everything data, or to create a new archive. This archive is then loaded whenever visiting Hardly Everything. You can also load another archive anytime you’d like, which is sort of like managing multiple libraries. 40 | 41 | What was once the **Data** tab is now accessible by clicking *View*, containing options for exporting and importing your raw data. This is handy for manually backing up your data, or to transfer between environments. Soon Dat will be adding multi-writer, which will enable you to read/write to the same archive across devices. Until then, this will likely come in handy. 42 | 43 | Clearly Hardly Everything takes a simple and experimental approach to user data. Although it’s possible to export your data from platforms like Facebook or Twitter, it doesn’t do much good when no other application interfaces with it. Instead, it’s important to change the defaults and begin cultivating a set of loose standards which facilitate user owned data and permissions based access across fungible tools. 44 | 45 | Hopefully this update is useful for you, too! -------------------------------------------------------------------------------- /content/blog/021-ben/bdif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/021-ben/bdif.png -------------------------------------------------------------------------------- /content/blog/021-ben/index.txt: -------------------------------------------------------------------------------- 1 | title: Ben Pieratt’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-08-13 6 | ---- 7 | author: Ben Pieratt 8 | ---- 9 | authorUrl: http://pieratt.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Reddit TIL 16 | url: https://reddit.com/r/todayilearned 17 | img: reddit.png 18 | week: 19 | title: But Does it Float 20 | url: http://butdoesitfloat.com 21 | img: bdif.png 22 | month: 23 | title: Manifestos 24 | url: https://github.com/greyscalepress/manifestos/tree/master/content/manifestos 25 | img: manifestos.png 26 | year: 27 | title: Surfstation 28 | url: https://surfstation.lu 29 | img: surfstation.png 30 | -------------------------------------------------------------------------------- /content/blog/021-ben/manifestos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/021-ben/manifestos.png -------------------------------------------------------------------------------- /content/blog/021-ben/reddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/021-ben/reddit.png -------------------------------------------------------------------------------- /content/blog/021-ben/surfstation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/021-ben/surfstation.png -------------------------------------------------------------------------------- /content/blog/022-lukas/bit-player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/022-lukas/bit-player.png -------------------------------------------------------------------------------- /content/blog/022-lukas/gimmickbook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/022-lukas/gimmickbook.png -------------------------------------------------------------------------------- /content/blog/022-lukas/index.txt: -------------------------------------------------------------------------------- 1 | title: Lukas T WinklerPrins’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-08-09 6 | ---- 7 | author: Lukas T WinklerPrins 8 | ---- 9 | authorUrl: http://ltwp.net 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: NOAA Pacific Surface Analysis 16 | url: http://www.opc.ncep.noaa.gov/Pac_tab.shtml 17 | img: noaa.png 18 | week: 19 | title: Gimmick Book 20 | url: http://gimmickbook.com 21 | img: gimmickbook.png 22 | month: 23 | title: bit-player 24 | url: http://bit-player.org 25 | img: bit-player.png 26 | year: 27 | title: Jenny Holzer, Truisms 28 | url: https://www.cs.utexas.edu/~field/holzer/truisms.txt 29 | img: truisms.png 30 | -------------------------------------------------------------------------------- /content/blog/022-lukas/noaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/022-lukas/noaa.png -------------------------------------------------------------------------------- /content/blog/022-lukas/truisms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/022-lukas/truisms.png -------------------------------------------------------------------------------- /content/blog/023-kalli/earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/023-kalli/earth.png -------------------------------------------------------------------------------- /content/blog/023-kalli/if-you-leave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/023-kalli/if-you-leave.png -------------------------------------------------------------------------------- /content/blog/023-kalli/index.txt: -------------------------------------------------------------------------------- 1 | title: Kallirroi Retzepi’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-08-18 6 | ---- 7 | author: Kallirroi Retzepi 8 | ---- 9 | authorUrl: https://kalli-retzepi.com 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Earth 16 | url: https://earth.nullschool.net 17 | img: earth.png 18 | week: 19 | title: If You Leave 20 | url: http://if-you-leave.tumblr.com 21 | img: if-you-leave.png 22 | month: 23 | title: Props 24 | url: http://propspaper.com 25 | img: propspaper.png 26 | year: 27 | title: Worry Dream 28 | url: http://worrydream.com/refs 29 | img: worrydream.png 30 | -------------------------------------------------------------------------------- /content/blog/023-kalli/propspaper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/023-kalli/propspaper.png -------------------------------------------------------------------------------- /content/blog/023-kalli/worrydream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/023-kalli/worrydream.png -------------------------------------------------------------------------------- /content/blog/024-uli/032c-manifesto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/024-uli/032c-manifesto.png -------------------------------------------------------------------------------- /content/blog/024-uli/arena-explore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/024-uli/arena-explore.png -------------------------------------------------------------------------------- /content/blog/024-uli/babel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/024-uli/babel.png -------------------------------------------------------------------------------- /content/blog/024-uli/index.txt: -------------------------------------------------------------------------------- 1 | title: Uli Schöberl’s list 2 | ---- 3 | visible: true 4 | ---- 5 | date: 2018-09-24 6 | ---- 7 | author: Uli Schöberl 8 | ---- 9 | authorUrl: http://aplusplus.org/ 10 | ---- 11 | category: list 12 | ---- 13 | links: 14 | day: 15 | title: Are.na Explore 16 | url: https://www.are.na/explore 17 | img: arena-explore.png 18 | week: 19 | title: Webshit Weekly 20 | url: http://n-gate.com 21 | img: webshit.png 22 | month: 23 | title: 032c Manifesto 24 | url: https://032c.com/what-we-believe 25 | img: 032c-manifesto.png 26 | year: 27 | title: Library of Babel 28 | url: https://libraryofbabel.info 29 | img: babel.png 30 | -------------------------------------------------------------------------------- /content/blog/024-uli/webshit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondashkyle/hardly-everything/8eb0cc468fef5145dd5625d038d77a933cfde80b/content/blog/024-uli/webshit.png -------------------------------------------------------------------------------- /content/blog/025-entropy/index.txt: -------------------------------------------------------------------------------- 1 | title: Introducing a Little Entropy 2 | ---- 3 | date: 2018-12-18 4 | ---- 5 | category: update 6 | ---- 7 | text: 8 | 9 | Hardly Everything considers a sensitivity to time — interval, duration, tempo — critically underdeveloped in the design of everyday products. In response, Hardly Everything exists as an effort to nudge along an evolution in familiar design patterns by introducing this sensitivity, and not at the expense of immediate utility to the user. Its uncompromising in its attempt to be useful, but this goal does not prevent us from questioning fundamental issues of the feed. Should it scroll forever? Should it update continuously? 10 | 11 | There is a simple sophistication in choosing not to continuously maximize. To not just observe but actively nurture nuance. 12 | 13 | Rather than rigidly implementing time, as in a schedule where specific moments are defined, Hardly Everything utilizes duration—a more abstract figure when a day can feel like a week, and vice versa. One problem with this form of definition is the elimination of offset phase over time. 14 | 15 |
16 | 17 | ![](/content/blog/025-entropy/entropy.svg) 18 | 19 |
20 | 21 | For example, say you added several links with an interval of seven days—a link on Monday, a link on Tuesday, and so on. If you go a week without visiting one of the links, they will all appear in your feed at once. If you click them all on a single day, say Friday, they will now all reappear the following Friday instead of being staggered as they were when first added. 22 | 23 | To assist in avoiding this reduction in serendipity, there is now a new feature: *Entropy*, for introducing a little chaos. This is defined by navigating to [**Options**](/options) and adjusting the value for *Randomly offset rest duration*. Now, when clicking a link, a day between zero and your defined level of entropy will be generated and summed into your period of rest. 24 | 25 | Hopefully this will be useful, and just the right amount of friction. All feedback is encouraged. -------------------------------------------------------------------------------- /content/blog/index.txt: -------------------------------------------------------------------------------- 1 | title: Blog 2 | ---- 3 | visible: true 4 | ---- 5 | categories: 6 | - essay 7 | - list 8 | - update 9 | ---- 10 | text: This is the blog! -------------------------------------------------------------------------------- /content/faq/index.txt: -------------------------------------------------------------------------------- 1 | title: FAQ 2 | ---- 3 | visible: true 4 | ---- 5 | text: 6 | 7 | ## How do I join? 8 | 9 | There are no invites, no accounts, no passwords, no signup. Just start [using it](/panel/entry). 10 | 11 | ## What is this for? 12 | 13 | Getting peace of mind from social media burnout and the anxiety around managing a large library of bookmarks. I don’t want to live in a social desert, I just want some mental solitude. Here’s some stuff I care about, remind it of me infrequently, done. 14 | 15 | You shouldn’t use Hardly Everything for more than 2 minutes/day. 16 | 17 | ## Where does my data go? 18 | 19 | In a normal browser? It’s saved in local storage. Look out though, because clearing your browser’s data will erase that. You can back that up by [exporting your data](/data) and later importing it. 20 | 21 | ## Managing my own data sounds archaic. 22 | 23 | Yeah, so does all of this two factor login stuff we have to deal with these days. Misplace your phone? Oh too bad! 24 | 25 | Tbh, just copying some JSON into a plaintext file you can do whatever you want with once every few weeks feels like less of a hassle at this point, even if you don’t know what you’re doing. 26 | 27 | The slowness lends a certain type of honesty to the practices involved. 28 | 29 | ## What if I don’t want to manage my data? 30 | 31 | Use Hardly Everything in a browser which supports the peer-to-peer protocol [Dat](https://datproject.org), like [Beaker Browser](https://beakerbrowser.com). Better yet, use it either way. You can save your data locally, access it offline, and even fork the entire application to customize however you’d like. 32 | 33 | ## What about mobile. 34 | 35 | Get off your damn phone. 36 | 37 | Don’t hold your breathe for a native app. Honestly though, this works fine on mobile, but syncing data between devices is a pain. But really, put your phone down already. 38 | 39 | ## Can I add images or video? 40 | 41 | Nah, not for now. This is for links. Focus is on text. Just make a link to a photo or video or whatever. 42 | 43 | ## RSS support please? 44 | 45 | Could be cool, but part the reasoning behind creating links out to sites is to retain a sense of context. Pulling in content from across the internet and applying uniform formatting only helps in homogenization, which sucks. 46 | 47 | ## Why update once a day? 48 | 49 | That way you’re not mindlessly refreshing and revisiting the site all day to get that serotonin hit. Visited once already today? Great. That’s how it’s gonna be all day. No rush to look at everything now, so go do better things. 50 | 51 | ## It’d be cool to share things with friends on here. 52 | 53 | This is a tool, not a social network. Just send your friend a link with whatever messaging app you use and get on with your day. 54 | 55 | ## I want feature X 56 | 57 | Cool, go fork [the repository](https://github.com/jondashkyle/hardly-everything) and create a pull request. -------------------------------------------------------------------------------- /content/intro/index.txt: -------------------------------------------------------------------------------- 1 | title: Intro 2 | ---- 3 | visible: false -------------------------------------------------------------------------------- /content/intro/loop.vtt: -------------------------------------------------------------------------------- 1 | WEBVTT 2 | 3 | 00:01.000 --> 00:04.000 4 | Video coming soon 5 | 6 | 00:05.000 --> 00:09.000 7 | That photo was a placeholder 8 | 9 | 00:10.000 --> 00:15.000 10 | So is this video 11 | I shot it in Japan -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hardly Everything 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardly-an-app", 3 | "version": "2.1.0", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "content": "enoki content", 8 | "build": "enoki content && browserify src/index.js -t [ envify --NODE_ENV production ] -t [ sheetify -u sheetify-cssnext ] -p [ css-extract -o bundles/bundle.css ] -t babelify -o bundles/bundle.js", 9 | "start": "enoki content --watch & budo src/index.js --dir . -s bundles/bundle.js -P -- -t sheetify -p [ css-extract -o bundles/bundle.css ]", 10 | "dev": "enoki content --watch & watchify src/index.js -t sheetify -p [ css-extract -o bundles/bundle.css ] -o bundles/bundle.js", 11 | "serve": "python3 -m http.server 9000", 12 | "test": "standard" 13 | }, 14 | "author": "Jon-Kyle Mohr", 15 | "license": "Apache-2.0", 16 | "devDependencies": { 17 | "@babel/core": "^7.0.0-beta.49", 18 | "@babel/plugin-transform-async-to-generator": "^7.0.0-beta.49", 19 | "@babel/preset-env": "^7.0.0-beta.49", 20 | "babel-polyfill": "^6.26.0", 21 | "babel-runtime": "^6.26.0", 22 | "babelify": "^9.0.0", 23 | "browserify": "^16.2.2", 24 | "css-extract": "^1.3.0", 25 | "envify": "^4.1.0", 26 | "lilcss": "0.0.0", 27 | "sheetify": "^7.3.2", 28 | "sheetify-cssnext": "^2.0.0", 29 | "standard": "^11.0.1", 30 | "tape": "^4.6.3", 31 | "tinyify": "^2.4.1", 32 | "uglify-js": "^3.3.28", 33 | "watchify": "^3.11.0", 34 | "yo-yoify": "^4.3.0" 35 | }, 36 | "dependencies": { 37 | "choo": "^6.11.0", 38 | "clone-deep": "^0.2.4", 39 | "dayjs": "^1.6.4", 40 | "deep-equal": "^1.0.1", 41 | "enoki": "^2.2.0-next4", 42 | "fastclick": "^1.0.6", 43 | "gr8": "^3.1.5", 44 | "intersection-observer": "^0.5.0", 45 | "lodash.throttle": "^4.1.1", 46 | "marked": "^0.4.0", 47 | "monoimage": "^0.1.2", 48 | "nanobus": "^4.3.3", 49 | "nanoreset": "^2.0.0", 50 | "normalize-url": "^1.6.1", 51 | "object-keys": "^1.0.11", 52 | "object-values": "^1.0.0", 53 | "plyr": "^3.3.9", 54 | "recsst": "^1.1.2", 55 | "simple-color-picker": "^0.1.2", 56 | "tags-input": "^1.1.1", 57 | "tinycolor2": "^1.4.1", 58 | "uuid": "^3.0.1", 59 | "valid-url": "^1.0.9", 60 | "webfontloader": "^1.6.26", 61 | "xtend": "^4.0.1" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/components/css.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var { linearConversion } = require('../lib/scale') 3 | 4 | module.exports = css 5 | 6 | function css (state, emit) { 7 | var blockPadding = linearConversion({ 8 | value: state.options.values.spacing, 9 | out: { min: 0.5, max: 5 } 10 | }) 11 | 12 | var fontSize = linearConversion({ 13 | value: state.options.values.scale, 14 | out: { min: 0.5, max: 10 } 15 | }) 16 | 17 | var colors = { 18 | bg: state.options.values.colorBg || { r: 255, g: 255, b: 255 }, 19 | fg: state.options.values.colorText || { r: 0, g: 0, b: 0 } 20 | } 21 | 22 | var background = `${colors.bg.r}, ${colors.bg.g}, ${colors.bg.b}` 23 | var foreground = `${colors.fg.r}, ${colors.fg.g}, ${colors.fg.b}` 24 | 25 | return html` 26 | 45 | ` 46 | } 47 | -------------------------------------------------------------------------------- /src/components/entry-blog.js: -------------------------------------------------------------------------------- 1 | var Monoimage = require('monoimage') 2 | var objectKeys = require('object-keys') 3 | var html = require('choo/html') 4 | var format = require('../components/format') 5 | 6 | module.exports = entryBlog 7 | 8 | function entryBlog (state, emit, props) { 9 | switch (props.category) { 10 | case 'list': 11 | return createList(state, emit, props) 12 | default: 13 | return createDefault(props) 14 | } 15 | } 16 | 17 | function createList (state, emit, props) { 18 | props.image = false // temp disable 19 | var links = (typeof props.links === 'object') ? props.links : { } 20 | 21 | return html` 22 |
23 |
24 | ${props.author}, what is a link you want to remember once every… 25 |
26 |
27 | ${objectKeys(links).map(createThumb)} 28 |
29 |
30 | ` 31 | 32 | function createThumb (key) { 33 | var thumb = props.links[key] 34 | var image = '/content' + props.files[thumb.img] 35 | var url = thumb.url.replace(/(^\w+:|^)\/\//, '') 36 | 37 | return html` 38 |
39 |
${key}
40 | 41 |
42 |
${thumb.title}
43 |
44 |
45 | ${state.cache(Monoimage, image).render({ 46 | sizes: { 100: image }, 47 | dimensions: { ratio: 75 } 48 | })} 49 |
50 |
51 |
52 | ` 53 | } 54 | } 55 | 56 | function createDefault (props) { 57 | return html` 58 |
59 |
60 | ${props.title} 61 |
62 |
63 |
64 | ${format(props.text)} 65 |
66 |
67 |
68 | ` 69 | } 70 | -------------------------------------------------------------------------------- /src/components/entry.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | module.exports = Entry 4 | 5 | function Entry (state, data, emit) { 6 | return html` 7 |
8 |
9 | ${data.title} 15 |
19 |
20 |
24 |
28 |
32 |
33 |
34 |
35 | ` 36 | 37 | function handleClick (event) { 38 | emit('entries:dismiss', { id: data.id }) 39 | } 40 | 41 | function handleClickEdit (event) { 42 | var staging = state.entries.all[data.id] 43 | 44 | // toggle 45 | if (data.id === state.staging.entry.id) { 46 | emit('staging:reset') 47 | emit('ui:panel', { view: '' }) 48 | } else { 49 | if (data.id !== undefined && staging !== undefined) { 50 | emit('staging:entry', staging) 51 | emit('ui:panel', { view: 'entry' }) 52 | } 53 | } 54 | 55 | event.preventDefault() 56 | } 57 | 58 | function handleClickDelete () { 59 | emit('staging:reset') 60 | emit('entries:remove', { id: data.id }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/components/format.js: -------------------------------------------------------------------------------- 1 | var raw = require('choo/html/raw') 2 | var md = require('marked') 3 | 4 | module.exports = format 5 | 6 | function format (str) { 7 | return raw(md(str || '')) 8 | } 9 | -------------------------------------------------------------------------------- /src/components/input/checkbox.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var html = require('choo/html') 3 | var xtend = require('xtend') 4 | 5 | module.exports = class Checkbox extends Component { 6 | constructor (name, state, emit) { 7 | super() 8 | 9 | this.local = { 10 | 11 | } 12 | 13 | this.handleChange = this.handleChange.bind(this) 14 | } 15 | 16 | handleChange () { 17 | if ( 18 | this.local && 19 | this.local.onChange && 20 | typeof this.local.onChange === 'function' 21 | ) { 22 | this.local.onChange({ 23 | value: !this.local.value 24 | }) 25 | } 26 | } 27 | 28 | createElement (props) { 29 | this.local = xtend(this.local, props) 30 | 31 | var input = Input({ 32 | onChange: this.handleChange, 33 | icon: this.local.icon || '✓', 34 | value: this.local.value 35 | }) 36 | 37 | return Container({ 38 | name: this.local.name || 'Untitled' 39 | }, input) 40 | } 41 | 42 | update (props) { 43 | return true 44 | } 45 | } 46 | 47 | function Container (props, children) { 48 | return html` 49 |
50 |
51 | ${props.name} 52 |
53 | ${children} 54 |
55 | ` 56 | } 57 | 58 | function Input (props = { }) { 59 | return [ 60 | html` 61 | 67 | `, 68 | html` 69 | 80 | ` 81 | ] 82 | } 83 | -------------------------------------------------------------------------------- /src/components/input/color.js: -------------------------------------------------------------------------------- 1 | var ColorPicker = require('simple-color-picker') 2 | var Component = require('choo/component') 3 | var tinycolor = require('tinycolor2') 4 | var html = require('choo/html') 5 | var xtend = require('xtend') 6 | 7 | class Picker extends Component { 8 | constructor (name, state, emit) { 9 | super() 10 | 11 | this.frame 12 | this.local = { 13 | active: false, 14 | color: '' 15 | } 16 | 17 | this.handleClickSwatch = this.handleClickSwatch.bind(this) 18 | } 19 | 20 | load (element) { 21 | var self = this 22 | 23 | // skip if we have a color picker 24 | if (this.colorPicker) return 25 | 26 | this.colorPicker = new ColorPicker({ 27 | color: tinycolor(this.local.color).toHexString(), 28 | el: element, 29 | width: 200, 30 | height: 200 31 | }) 32 | 33 | this.colorPicker.onChange(function (data) { 34 | var current = self.local.color 35 | var update = tinycolor(data).toRgb() 36 | if ( 37 | update.r === current.r && 38 | update.g === current.r && 39 | update.b === current.b 40 | ) return // skip if its the same 41 | self.local.color = tinycolor(data) 42 | if (typeof self.local.handleChange === 'function') { 43 | self.local.handleChange({ 44 | rgb: update 45 | }) 46 | } 47 | }) 48 | 49 | this.colorPicker.$el.style.display = 'none' 50 | } 51 | 52 | unload () { 53 | this.local.active = false 54 | this.colorPicker.$el.style.display = 'none' 55 | } 56 | 57 | handleClickSwatch () { 58 | var cover = this.element.querySelector('[data-cover]') 59 | this.local.active = !this.local.active 60 | this.colorPicker.$el.style.display = this.local.active ? '' : 'none' 61 | if (cover) cover.style.display = this.local.active ? 'block' : 'none' 62 | } 63 | 64 | elCover () { 65 | return html` 66 |
72 | ` 73 | } 74 | 75 | elCurrent () { 76 | var color = this.local.color 77 | return html` 78 |
82 | ${this.local.data.name} 83 |
94 |
95 | ` 96 | } 97 | 98 | createElement (props) { 99 | this.local = xtend(this.local, props) 100 | return html` 101 |
102 | ${this.elCurrent()} 103 | ${this.colorPicker ? this.colorPicker.$el : ''} 104 | ${this.elCover()} 105 |
106 | ` 107 | } 108 | 109 | update (props) { 110 | var elSwatch = this.element.querySelector('[data-swatch]') 111 | elSwatch.style.background = `rgb(${props.color.r}, ${props.color.g}, ${props.color.b})` 112 | this.local.color = props.color 113 | 114 | if (this.colorPicker) { 115 | this.colorPicker.setColor(tinycolor(props.color)) 116 | } 117 | 118 | return false 119 | } 120 | } 121 | 122 | module.exports = Picker 123 | -------------------------------------------------------------------------------- /src/components/input/data.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var html = require('choo/html') 3 | var xtend = require('xtend') 4 | 5 | module.exports = class Data extends Component { 6 | constructor (id, state, emit) { 7 | super(id, state, emit) 8 | 9 | this.state = state 10 | this.emit = emit 11 | this.local = { } 12 | 13 | this.handleClick = this.handleClick.bind(this) 14 | } 15 | 16 | update (props) { 17 | return true 18 | } 19 | 20 | createElement (props) { 21 | this.local = xtend(this.local, props) 22 | var isDat = this.state.datastorage.isDat 23 | 24 | return html` 25 |
26 |
27 |
Data storage
28 |
29 |
${this.getStorageName()}
30 | View 31 |
32 |
33 | ` 34 | } 35 | 36 | getStorageName () { 37 | var archiveTitle = this.state.datastorage.archive.title 38 | 39 | // is dat 40 | if (this.state.datastorage.isDat) { 41 | // archive loaded 42 | if (archiveTitle) return archiveTitle 43 | else return 'Select an archive' 44 | } else { 45 | return 'Local browser' 46 | } 47 | } 48 | 49 | handleClick (event) { 50 | if (this.state.datastorage.isDat) { 51 | this.emit(this.state.events.DATA_DAT_LOAD) 52 | } else { 53 | // if not dat, go to data management 54 | // this.emit(this.state.events.PUSHSTATE, '/data') 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/components/input/dropdown.js: -------------------------------------------------------------------------------- 1 | var objectValues = require('object-values') 2 | var Component = require('choo/component') 3 | var html = require('choo/html') 4 | var xtend = require('xtend') 5 | 6 | module.exports = class Dropdown extends Component { 7 | constructor (name, state, emit) { 8 | super() 9 | this.state = state 10 | this.emit = emit 11 | 12 | this.local = { 13 | active: false, 14 | current: { } 15 | } 16 | 17 | this.handleOptionClick = this.handleOptionClick.bind(this) 18 | this.handleCurrentClick = this.handleCurrentClick.bind(this) 19 | this.handleScroll = this.handleScroll.bind(this) 20 | } 21 | 22 | handleOptionClick (data, event) { 23 | if (this.local.handleOptionClick) { 24 | this.local.handleOptionClick(data) 25 | } 26 | } 27 | 28 | handleCurrentClick (event) { 29 | if (this.local.handleCurrentClick) { 30 | this.local.handleCurrentClick() 31 | } 32 | this.local.active = !this.local.active 33 | this.rerender() 34 | } 35 | 36 | handleScroll (event) { 37 | event.stopPropagation() 38 | } 39 | 40 | elOption (data) { 41 | return html` 42 |
this.handleOptionClick(event)} 45 | style=" 46 | font-family: ${data.value}, sans-serif; 47 | font-weight: ${data.weight || 400}; 48 | font-style: ${data.style || 'normal'}; 49 | " 50 | > 51 |
${data.name}
52 | ${data.author 53 | ? html` 54 |
55 | 60 |
61 | ` 62 | : '' 63 | } 64 |
65 | ` 66 | } 67 | 68 | elContainer () { 69 | var options = objectValues(this.local.options) 70 | return html` 71 |
77 | yo 78 |
79 | ` 80 | } 81 | 82 | elCurrent () { 83 | return html` 84 |
this.handleCurrentClick({ }, event)} 87 | > 88 |
89 | ${this.local.name} 90 |
91 |
92 | ` 93 | } 94 | 95 | createElement (props) { 96 | this.local = xtend(this.local, props) 97 | return html` 98 |
99 | ${this.elCurrent()} 100 | ${this.elContainer()} 101 |
102 | ` 103 | } 104 | 105 | update (props) { 106 | return ( 107 | props.current.key !== this.local.current.key || 108 | props.current.active !== this.local.current.active 109 | ) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/components/input/index.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var inputTypography = require('./typography') 4 | var inputCheckbox = require('./checkbox') 5 | var inputTextarea = require('./textarea') 6 | var inputColor = require('./color') 7 | var inputRange = require('./range') 8 | var inputData = require('./data') 9 | var inputText = require('./text') 10 | 11 | module.exports = componentInput 12 | 13 | function componentInput (state, emit, option) { 14 | switch (option.type) { 15 | case 'text': 16 | return state 17 | .cache(inputText, 'panel:' + option.key) 18 | .render({ 19 | key: option.key, 20 | name: option.name, 21 | value: state.options.values[option.key], 22 | onChange: function (data) { 23 | emit('options:values', { 24 | key: option.key, 25 | value: data.value 26 | }) 27 | } 28 | }) 29 | case 'textarea': 30 | return state 31 | .cache(inputTextarea, 'panel:' + option.key) 32 | .render({ 33 | key: option.key, 34 | name: option.name, 35 | value: state.options.values[option.key], 36 | onInput: function (data) { 37 | emit('options:values', { 38 | key: option.key, 39 | value: data.value 40 | }) 41 | } 42 | }) 43 | case 'checkbox': 44 | return state 45 | .cache(inputCheckbox, 'panel:' + option.key) 46 | .render({ 47 | key: option.key, 48 | name: option.name, 49 | value: state.options.values[option.key], 50 | onChange: function (data) { 51 | emit('options:values', { 52 | key: option.key, 53 | value: data.value 54 | }) 55 | } 56 | }) 57 | case 'color': 58 | var color = state.options.values[option.key] 59 | color = color || { r: 0, g: 0, b: 0 } 60 | return state 61 | .cache(inputColor, 'panel:' + option.key) 62 | .render({ 63 | data: option, 64 | color: color, 65 | handleChange: function (value) { 66 | emit('options:values', { 67 | key: option.key, 68 | value: value.rgb 69 | }) 70 | } 71 | }) 72 | case 'range': 73 | return state 74 | .cache(inputRange, 'panel:' + option.key) 75 | .render({ 76 | name: option.name, 77 | value: state.options.values[option.key], 78 | scaleValue: option.scaleValue, 79 | unit: option.unit, 80 | min: option.min, 81 | max: option.max, 82 | showValue: option.showValue, 83 | onInput: function (data) { 84 | emit('options:values', { 85 | key: option.key, 86 | value: data.value 87 | }) 88 | } 89 | }) 90 | case 'typography': 91 | return state 92 | .cache(inputTypography, 'panel' + option.key) 93 | .render({ 94 | current: state.options.values.font, 95 | options: state.options.typography, 96 | children: option.children, 97 | handleCurrentClick: function () { 98 | emit('options:typography') 99 | }, 100 | handleOptionClick: function (data) { 101 | emit('options:values', { 102 | key: option.key, 103 | value: data 104 | }) 105 | } 106 | }) 107 | case 'data': 108 | return state 109 | .cache(inputData, 'panel' + option.key) 110 | .render({ }) 111 | default: 112 | return '' 113 | } 114 | } -------------------------------------------------------------------------------- /src/components/input/range.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var html = require('choo/html') 3 | var xtend = require('xtend') 4 | 5 | module.exports = class Range extends Component { 6 | constructor (name, state, emit) { 7 | super() 8 | this.local = { } 9 | this.handleInput = this.handleInput.bind(this) 10 | } 11 | 12 | handleInput (event) { 13 | if ( 14 | this.local && 15 | this.local.onInput && 16 | typeof this.local.onInput === 'function' 17 | ) { 18 | var value = Math.floor(parseInt(event.target.value) / 10) 19 | this.local.onInput({ 20 | value: value 21 | }) 22 | } 23 | } 24 | 25 | createElement (props) { 26 | this.local = xtend(this.local, props) 27 | 28 | var input = Input({ 29 | onInput: this.handleInput, 30 | value: this.local.value 31 | }) 32 | 33 | var value = this.local.showValue 34 | ? [Value({ value: this.local.value, max: props.max, unit: props.unit, scale: props.scaleValue })] 35 | : '' 36 | 37 | return Container({ 38 | name: this.local.name || 'Untitled' 39 | }, [input, value]) 40 | } 41 | 42 | update (props) { 43 | return props.value !== this.local.value 44 | } 45 | } 46 | 47 | function Container (props, children) { 48 | return html` 49 |
50 |
51 | ${props.name} 52 |
53 | ${children} 54 |
55 | ` 56 | } 57 | 58 | function Input (props = { }) { 59 | return [ 60 | html` 61 | 70 | `, 71 | html` 72 |
80 | ` 81 | ] 82 | } 83 | 84 | function Value (props = { }) { 85 | var value = props.scale ? Math.floor(props.value / 100 * props.max) : props.value 86 | if (props.unit) value += ' ' + props.unit 87 | return html` 88 |
89 | ${value} 90 |
91 | ` 92 | } 93 | -------------------------------------------------------------------------------- /src/components/input/tags.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var tagsInput = require('tags-input') 3 | var html = require('choo/html') 4 | var xtend = require('xtend') 5 | 6 | module.exports = class Tags extends Component { 7 | constructor (name, state, emit) { 8 | super() 9 | 10 | this.local = { 11 | value: [ ], 12 | valueStart: [ ] 13 | } 14 | 15 | this.handleChange = this.handleChange.bind(this) 16 | } 17 | 18 | load (element) { 19 | tagsInput(this.element.querySelector('input')) 20 | } 21 | 22 | createElement (props) { 23 | this.local = xtend(this.local, props) 24 | if (!this.local.valueStart) this.local.valueStart = this.local.value 25 | 26 | return Container( 27 | { name: this.local.name || 'Untitled' }, 28 | html`` 33 | ) 34 | } 35 | 36 | handleChange (event) { 37 | if ( 38 | this.local && 39 | this.local.onChange && 40 | typeof this.local.onChange === 'function' 41 | ) { 42 | var value = event.target.value.split(',') 43 | if (!arraysEqual(this.local.value, value)) { 44 | this.local.value = value 45 | this.local.onChange({ value: value }) 46 | } 47 | } 48 | } 49 | 50 | update (props) { 51 | var value = props.value || [ ] 52 | 53 | if (!arraysEqual(value, this.local.value)) { 54 | var el = this.element.querySelector('.tags-input') 55 | var elInput = this.element.querySelector('input') 56 | if (el) this.element.removeChild(el) 57 | this.local.value = value 58 | elInput.value = value 59 | tagsInput(elInput) 60 | } 61 | 62 | return false 63 | } 64 | } 65 | 66 | function Container (props, children) { 67 | return html` 68 |
69 | ${children} 70 |
71 | ` 72 | } 73 | 74 | function arraysEqual (a, b) { 75 | if (a === b) return true 76 | if (a == null || b == null) return false 77 | if (a.length != b.length) return false 78 | 79 | for (var i = 0; i < a.length; ++i) { 80 | if (a[i] !== b[i]) return false 81 | } 82 | 83 | return true 84 | } 85 | -------------------------------------------------------------------------------- /src/components/input/text.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var html = require('choo/html') 3 | var xtend = require('xtend') 4 | 5 | module.exports = class Text extends Component { 6 | constructor (name, state, emit) { 7 | super() 8 | 9 | this.local = { 10 | autofocus: false, 11 | required: false 12 | } 13 | 14 | this.handleInput = this.handleInput.bind(this) 15 | } 16 | 17 | load () { 18 | if (this.local.autofocus) { 19 | this.element.querySelector('input').focus() 20 | } 21 | } 22 | 23 | handleInput (event) { 24 | if ( 25 | this.local && 26 | this.local.onInput && 27 | typeof this.local.onInput === 'function' 28 | ) { 29 | this.local.onInput({ 30 | value: event.target.value 31 | }) 32 | } 33 | } 34 | 35 | update (props) { 36 | return true 37 | } 38 | 39 | createElement (props) { 40 | this.local = xtend(this.local, props) 41 | 42 | var input = Input({ 43 | key: this.local.key, 44 | name: this.local.name, 45 | style: this.local.style || '', 46 | value: this.local.value || '', 47 | onInput: this.handleInput 48 | }) 49 | 50 | return Container({ 51 | name: this.local.name || 'Untitled' 52 | }, input) 53 | } 54 | } 55 | 56 | function Container (props = { }, children) { 57 | return html` 58 |
59 | ${children} 60 |
61 | ` 62 | } 63 | 64 | function Input (props = { }) { 65 | return html` 66 | 75 | ` 76 | } 77 | -------------------------------------------------------------------------------- /src/components/input/textarea.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var raw = require('choo/html/raw') 3 | var html = require('choo/html') 4 | var xtend = require('xtend') 5 | 6 | var libDesign = require('../../lib/design') 7 | 8 | module.exports = class Text extends Component { 9 | constructor (name, state, emit) { 10 | super() 11 | 12 | this.local = { 13 | active: false, 14 | autofocus: false, 15 | required: false 16 | } 17 | 18 | this.handleKeydown = this.handleKeydown.bind(this) 19 | this.handleInput = this.handleInput.bind(this) 20 | this.handleToggle = this.handleToggle.bind(this) 21 | this.handleReset = this.handleReset.bind(this) 22 | } 23 | 24 | load () { 25 | if (this.local.autofocus) { 26 | this.element.querySelector('input').focus() 27 | } 28 | } 29 | 30 | handleInput (event) { 31 | if ( 32 | this.local && 33 | this.local.onInput && 34 | typeof this.local.onInput === 'function' 35 | ) { 36 | this.local.onInput({ 37 | value: event.target.value 38 | }) 39 | } 40 | } 41 | 42 | handleKeydown (event) { 43 | var keyCode = event.keyCode || event.which 44 | var element = event.target 45 | 46 | // only listen for tab 47 | if (keyCode !== 9) return 48 | 49 | event.preventDefault() 50 | var start = element.selectionStart 51 | var end = element.selectionEnd 52 | 53 | // set textarea value to: text before caret + tab + text after caret 54 | var spaces = " " 55 | element.value = element.value.substring(0, start) + spaces + element.value.substring(end) 56 | this.handleInput({ target: { value: element.value } }) 57 | 58 | // put caret at right position again 59 | element.selectionStart = element.selectionEnd = start + spaces.length 60 | } 61 | 62 | update (props) { 63 | return ( 64 | props.value !== this.local.value 65 | ) 66 | } 67 | 68 | createElement (props) { 69 | this.local = xtend(this.local, props) 70 | 71 | var input = Input({ 72 | key: this.local.key, 73 | name: this.local.name, 74 | style: this.local.style || '', 75 | value: this.local.value || '', 76 | onInput: this.handleInput, 77 | onKeydown: this.handleKeydown 78 | }) 79 | 80 | return html` 81 |
82 |
86 | ${this.local.name} 87 |
88 | ${this.local.active ? '↑' : '↓'} 89 |
90 |
91 | ${this.local.active ? this.createReset() : ''} 92 | ${this.local.active ? input : ''} 93 |
94 | ` 95 | } 96 | 97 | createReset () { 98 | return html` 99 |
Reset
103 | ` 104 | } 105 | 106 | handleReset () { 107 | this.handleInput({ target: { value: libDesign.getCssDefaults() } }) 108 | } 109 | 110 | handleToggle () { 111 | this.local.active = !this.local.active 112 | this.rerender() 113 | } 114 | } 115 | function Input (props) { 116 | return html` 117 | 126 | ` 127 | } 128 | -------------------------------------------------------------------------------- /src/components/input/typography.js: -------------------------------------------------------------------------------- 1 | var objectValues = require('object-values') 2 | var Component = require('choo/component') 3 | var html = require('choo/html') 4 | var xtend = require('xtend') 5 | 6 | var typography = require('../../design/typography') 7 | 8 | class Typography extends Component { 9 | constructor (name, state, emit) { 10 | super() 11 | this.state = state 12 | this.emit = emit 13 | 14 | this.local = { 15 | active: false, 16 | current: { } 17 | } 18 | 19 | this.handleOptionClick = this.handleOptionClick.bind(this) 20 | this.handleCurrentClick = this.handleCurrentClick.bind(this) 21 | this.handleScroll = this.handleScroll.bind(this) 22 | } 23 | 24 | handleOptionClick (data, event) { 25 | if (this.local.handleOptionClick) { 26 | this.local.handleOptionClick(data) 27 | } 28 | } 29 | 30 | handleCurrentClick (data, event) { 31 | if (this.local.handleCurrentClick) { 32 | this.local.handleCurrentClick() 33 | } 34 | this.local.active = !this.local.active 35 | this.rerender() 36 | } 37 | 38 | handleScroll (event) { 39 | event.stopPropagation() 40 | } 41 | 42 | elOption (data) { 43 | return html` 44 |
this.handleOptionClick(data, event)} 47 | style=" 48 | font-family: ${data.value}, sans-serif; 49 | font-weight: ${data.weight || 400}; 50 | font-style: ${data.style || 'normal'}; 51 | " 52 | > 53 |
${data.name}
54 | ${data.author 55 | ? html` 56 |
57 | 62 |
63 | ` 64 | : '' 65 | } 66 |
67 | ` 68 | } 69 | 70 | elContainer () { 71 | var options = objectValues(this.local.options) 72 | return html` 73 |
79 | ${this.local.children} 80 | ${options.map(option => this.elOption(option))} 81 |
82 | ` 83 | } 84 | 85 | elCurrent () { 86 | return html` 87 |
this.handleCurrentClick({ }, event)} 90 | > 91 | 94 |
95 | ${this.local.current.name} 96 |
97 |
98 | ` 99 | } 100 | 101 | createElement (props) { 102 | this.local = xtend(this.local, props) 103 | return html` 104 |
105 | ${this.elCurrent()} 106 | ${this.elContainer()} 107 |
108 | ` 109 | } 110 | 111 | update (props) { 112 | return ( 113 | props.current.key !== this.local.current.key || 114 | props.current.active !== this.local.current.active 115 | ) 116 | } 117 | } 118 | 119 | module.exports = Typography 120 | -------------------------------------------------------------------------------- /src/components/intro-slideshow.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var html = require('choo/html') 3 | var xtend = require('xtend') 4 | 5 | module.exports = class Slideshow extends Component { 6 | constructor (name, state, emit) { 7 | super() 8 | 9 | this.local = { 10 | index: 0, 11 | src: [ 12 | '/assets/img/screenshot.png', 13 | '/assets/img/screenshot-2.png', 14 | '/assets/img/screenshot-3.png', 15 | '/assets/img/screenshot-4.png', 16 | '/assets/img/screenshot-5.png', 17 | '/assets/img/screenshot-6.png' 18 | ] 19 | } 20 | 21 | // randomize the starting point 22 | this.local.index = Math.floor(Math.random() * this.local.src.length) 23 | 24 | // events 25 | this.handleClick = this.handleClick.bind(this) 26 | } 27 | 28 | load (element) { 29 | this.start() 30 | } 31 | 32 | unload (element) { 33 | this.stop() 34 | } 35 | 36 | start () { 37 | this.tick = setInterval(() => { 38 | this.local.index += 1 39 | this.rerender() 40 | }, 3000) 41 | } 42 | 43 | stop () { 44 | clearInterval(this.tick) 45 | } 46 | 47 | createElement (props) { 48 | props = props || { } 49 | this.local = xtend(this.local, props) 50 | 51 | var slide = mod(this.local.index, this.local.src.length) 52 | var next = mod(this.local.index + 1, this.local.src.length) 53 | 54 | return html` 55 |
56 | 61 | 62 |
63 | ` 64 | } 65 | 66 | handleClick () { 67 | this.local.index += 1 68 | this.stop() 69 | this.start() 70 | this.rerender() 71 | } 72 | 73 | update (props) { 74 | return false 75 | } 76 | } 77 | 78 | function mod (num, mod) { 79 | var remain = num % mod 80 | return Math.floor(remain >= 0 ? remain : remain + mod) 81 | } 82 | -------------------------------------------------------------------------------- /src/components/intro-video.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var html = require('choo/html') 3 | var css = require('sheetify') 4 | var Plyr = require('plyr') 5 | 6 | css('plyr/dist/plyr.css') 7 | 8 | module.exports = class IntroVideo extends Component { 9 | constructor (name, state, emit) { 10 | super() 11 | this.state = state 12 | this.emit = emit 13 | this.local = { } 14 | } 15 | 16 | createElement (props) { 17 | return html` 18 |
19 | 23 |
24 | ` 25 | } 26 | 27 | update (props) { 28 | return false 29 | } 30 | 31 | load (element) { 32 | setTimeout(() => { 33 | element.style.opacity = 1 34 | this.player = new Plyr(element.querySelector('video'), { 35 | controls: ['progress', /*'mute',*/ 'fullscreen'], 36 | captions: { active: true }, 37 | settings: false, 38 | loadSprite: false, 39 | iconUrl: '/assets/plyr.svg' 40 | }) 41 | 42 | this.player.toggleControls(false) 43 | 44 | this.player.on('play', () => { 45 | this.emit(this.state.events.UI_UPDATE, { introActive: true, introStarted: true }) 46 | }) 47 | 48 | this.player.on('pause', () => { 49 | this.emit(this.state.events.UI_UPDATE, { introActive: false }) 50 | }) 51 | 52 | this.player.on('controlsshown', () => { 53 | if (this.player.stopped) this.player.toggleControls(false) 54 | }) 55 | }, 400) 56 | } 57 | 58 | unload (element) { 59 | delete this.player 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/components/loading.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | module.exports = componentLoading 4 | 5 | function componentLoading (state, emit) { 6 | return html`
` 7 | } 8 | -------------------------------------------------------------------------------- /src/components/search.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | module.exports = Search 4 | 5 | function Search (props = { }) { 6 | return html` 7 |
search
8 | ` 9 | } 10 | -------------------------------------------------------------------------------- /src/containers/blog.js: -------------------------------------------------------------------------------- 1 | var Component = require('choo/component') 2 | var html = require('choo/html') 3 | var xtend = require('xtend') 4 | 5 | var entryBlog = require('../components/entry-blog') 6 | 7 | module.exports = class Blog extends Component { 8 | constructor (name, state, emit) { 9 | super() 10 | this.state = state 11 | this.emit = emit 12 | this.local = { 13 | entries: [ ] 14 | } 15 | } 16 | 17 | createElement (props) { 18 | this.local = xtend(this.local, props) 19 | return html` 20 |
21 | ${this.createEntries(this.local.entries)} 22 |
23 | ` 24 | } 25 | 26 | createEntries (entries) { 27 | var state = this.state 28 | var emit = this.emit 29 | return entries.map(function (props) { 30 | return html` 31 |
32 | ${entryBlog(state, emit, props)} 33 | ${createFooter(props)} 34 |
35 | ` 36 | }) 37 | } 38 | 39 | update (props) { 40 | return props.entries.length !== this.local.entries.length 41 | } 42 | } 43 | 44 | function createFooter (props) { 45 | return html` 46 |
47 | Published ${props.date}, Permalink 48 |
49 | ` 50 | } -------------------------------------------------------------------------------- /src/containers/content.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var Panel = require('../containers/panel-container') 4 | var loading = require('../components/loading') 5 | 6 | module.exports = containerContent 7 | 8 | function containerContent (state, emit, children) { 9 | var panelProps = { 10 | isHoverActive: true && !state.ui.mobile, 11 | view: state.ui.panel.view, 12 | navChildren: html` 13 | 14 | Feed 15 | 16 | ` 17 | } 18 | 19 | if ( 20 | state.ui.panel.view !== '' && 21 | !state.ui.panel.loadedContent 22 | ) { 23 | emit('ui:panel', { view: '', loadedContent: true }) 24 | setTimeout(() => emit(state.events.RENDER), 20) 25 | } 26 | 27 | if (!state.site.loaded) { 28 | emit(state.events.CONTENT_LOAD) 29 | } 30 | 31 | return [ 32 | Panel(state, panelProps, emit), 33 | createNavigation(state, emit), 34 | createContent() 35 | ] 36 | 37 | function createContent () { 38 | return html` 39 |
40 | ${state.site.loaded 41 | ? children 42 | : html`
${loading()}
` 43 | } 44 | ${createFooter(state, emit)} 45 |
46 | ` 47 | } 48 | } 49 | 50 | function createNavigation (state, emit) { 51 | var pages = state.page('/').pages().visible().sortBy('name', 'asc').toArray() 52 | 53 | return html` 54 |
60 |
61 |
62 | Hardly Everything 63 |
64 | ${pages.map(createLink)} 65 |
66 |
67 | ` 68 | 69 | function createLink (props) { 70 | var isActive = state.href.indexOf(props.url) >= 0 71 | return html` 72 |
73 | ${props.title} 77 |
78 | ` 79 | } 80 | } 81 | 82 | function createFooter (state, emit) { 83 | return html` 84 |
85 |
Hardly Everything
86 |
2018
87 |
88 | ` 89 | } 90 | -------------------------------------------------------------------------------- /src/containers/entry-list.js: -------------------------------------------------------------------------------- 1 | var objectValues = require('object-values') 2 | var html = require('choo/html') 3 | var dayjs = require('dayjs') 4 | 5 | var libEntries = require('../lib/entries') 6 | var Entry = require('../components/entry') 7 | 8 | module.exports = EntryList 9 | 10 | function EntryList (state, emit) { 11 | var entriesAll = Object.keys(state.entries.all) 12 | var elsEntries = entries() 13 | var isEntriesAll = entriesAll.length > 0 14 | 15 | var elContent = (isEntriesAll && elsEntries.length) 16 | ? elsEntries 17 | : (isEntriesAll && !elsEntries.length && !state.search.term) 18 | ? emptyEl() 19 | : (isEntriesAll && !elsEntries.length && state.search.term) 20 | ? emptySearchEl() 21 | : elEntriesNone(state, emit) 22 | 23 | var styleMobile = state.ui.mobile 24 | ? 'margin-top: 4.5rem;' 25 | : 'min-height: 100vh;' 26 | 27 | return html` 28 |
29 |
30 |
${elContent}
31 | ${isPaginatable() ? createPaginate() : ''} 32 |
33 |
34 | ` 35 | 36 | function isPaginatable () { 37 | return state.entries.active.length > elsEntries.length 38 | } 39 | 40 | function createCounter () { 41 | return html` 42 |
43 | ${elsEntries.length}/${entriesAll.length} 44 |
45 | ` 46 | } 47 | 48 | function createPaginate () { 49 | return html` 50 |
•••
55 | ` 56 | } 57 | 58 | function entries () { 59 | var end = state.ui.pagination.page * state.ui.pagination.limit 60 | return state.entries.active 61 | .slice(0, end) 62 | .map(entry => Entry(state, entry, emit)) 63 | } 64 | 65 | function handlePaginate (event) { 66 | emit(state.events.UI_PAGINATE, { 67 | page: state.ui.pagination.page + 1 68 | }) 69 | } 70 | } 71 | 72 | function emptyEl () { 73 | return html` 74 |
75 | Nothing more for today 76 |
77 | ` 78 | } 79 | 80 | function emptySearchEl () { 81 | return html` 82 |
83 | No matching entries 84 |
85 | ` 86 | } 87 | 88 | function elEntriesNone (state, emit) { 89 | return html` 90 |
No entries to see here!
91 | ` 92 | } 93 | -------------------------------------------------------------------------------- /src/containers/entry-navigation.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | module.exports = view 4 | 5 | function view(state, emit) { 6 | var shouldSearchHide = 7 | state.ui.entriesViewAll && !state.ui.mobile && state.entries.amount 8 | 9 | return html` 10 |
16 |
17 | ${state.ui.date} 18 |
19 |
20 | View all 30 |
31 |
${elSearch()}
32 |
33 | ` 34 | 35 | function handleAllClick() { 36 | emit('search:update', { value: '', render: false }) 37 | emit('ui:update', { entriesViewAll: !state.ui.entriesViewAll }) 38 | } 39 | 40 | function elSearch() { 41 | if (!state.features.search) { 42 | return '' 43 | } 44 | 45 | return html` 46 |
47 | ${navigationSearch({ 48 | value: state.search.term, 49 | onFocus: function () { 50 | emit('search:update', { 51 | hidePanel: true, 52 | }) 53 | }, 54 | onInput: function (data) { 55 | emit('search:update', { 56 | all: true, 57 | value: data.value, 58 | hidePanel: true, 59 | render: true, 60 | }) 61 | }, 62 | })} 63 |
64 | ` 65 | } 66 | } 67 | 68 | function navigationSearch(props = {}) { 69 | return html` 70 | 79 | ` 80 | 81 | function handleInput(event) { 82 | if (props.onInput) { 83 | props.onInput({ 84 | value: event.target.value, 85 | }) 86 | } 87 | } 88 | 89 | function handleFocus(event) { 90 | if (props.onFocus) { 91 | props.onFocus({ 92 | value: event.target.value, 93 | }) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/containers/notification.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var notifications = require('./notifications') 4 | 5 | module.exports = componentNotification 6 | 7 | function componentNotification (state, emit) { 8 | var notification = notifications[state.notifications.active] 9 | if (notification) return notification(state, emit) 10 | } 11 | -------------------------------------------------------------------------------- /src/containers/notifications/customize-design.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var libDesign = require('../../lib/design') 4 | 5 | module.exports = customizeDesign 6 | 7 | function customizeDesign (state, emit) { 8 | return html` 9 |
10 | Freshen things up by customizing or randomizing the designDismiss 11 |
12 | ` 13 | 14 | function handleDismissClick (event) { 15 | emit(state.events.USER_NOTIFIED, { id: 'customizeDesign' }) 16 | } 17 | 18 | function handleRandomClick (event) { 19 | var design = libDesign.getRandomDesign() 20 | emit('options:replace', design) 21 | } 22 | 23 | function handleOpenClick (event) { 24 | emit('ui:panel', { view: 'options'} ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/containers/notifications/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | customizeDesign: require('./customize-design'), 3 | p2p: require('./p2p') 4 | } 5 | -------------------------------------------------------------------------------- /src/containers/notifications/p2p.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var libDesign = require('../../lib/design') 4 | 5 | module.exports = customizeDesign 6 | 7 | function customizeDesign (state, emit) { 8 | return html` 9 |
10 | Enjoy offline accessibility and save data locally by visiting with Beaker BrowserDismiss 11 |
12 | ` 13 | 14 | function handleDismissClick (event) { 15 | emit(state.events.USER_NOTIFIED, { id: 'p2p' }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/containers/panel-container.js: -------------------------------------------------------------------------------- 1 | var objectValues = require('object-values') 2 | var html = require('choo/html') 3 | 4 | var panelOptions = require('../containers/panel-options') 5 | var panelEntry = require('../containers/panel-entry') 6 | 7 | var hideFrame 8 | 9 | module.exports = view 10 | 11 | function view (state, props, emit) { 12 | props = props || { } 13 | 14 | var views = { 15 | entry: { 16 | title: state.staging.entry.id 17 | ? 'Edit' 18 | : html`Follow`, 19 | path: 'entry', 20 | view: () => panelEntry(state, emit) 21 | }, 22 | options: { 23 | title: 'Options', 24 | path: 'options', 25 | view: () => panelOptions(state, emit) 26 | } 27 | } 28 | 29 | var view = views[props.view] 30 | var content = ( 31 | view && view.view && 32 | typeof view.view === 'function' 33 | ) ? html` 34 |
39 |
40 |
41 |
46 | ${view.view()} 47 |
48 |
49 |
50 | ` 51 | : '' 52 | 53 | return html` 54 |
59 |
63 |
${navigation()}
66 | ${content} 67 |
68 |
69 | ` 70 | 71 | function navigation () { 72 | return html` 73 |
74 | ${props.navChildren} 75 | ${objectValues(views) 76 | .filter(view => view.active !== false) 77 | .map(navigationLink) 78 | } 79 |
80 | ` 81 | } 82 | 83 | function navigationLink (view) { 84 | var active = view.path === props.view 85 | var href = active && state.href !== '' 86 | ? '/' 87 | : '/panel/' + view.path 88 | 89 | return html` 90 | ${view.title} 99 | ` 100 | 101 | function handleLinkEnter () { 102 | clearTimeout(hideFrame) 103 | if ( 104 | props.isHoverActive && 105 | view.path !== props.view 106 | ) { 107 | emit('ui:panel', { view: view.path }) 108 | } 109 | } 110 | } 111 | 112 | function handleContainerEnter () { 113 | clearTimeout(hideFrame) 114 | } 115 | 116 | function handleContainerClick (event) { 117 | if (event.target.hasAttribute('data-panel')) { 118 | emit('staging:reset') 119 | if (props.isHoverActive) { 120 | emit('ui:panel', { view: '' }) 121 | } else { 122 | emit('pushState', '/') 123 | } 124 | } 125 | } 126 | 127 | function handlePanelLeave (event) { 128 | if (props.isHoverActive && props.view) { 129 | clearTimeout(hideFrame) 130 | hideFrame = setTimeout(() => hide(), 750) 131 | } 132 | } 133 | 134 | function hide () { 135 | emit('staging:reset') 136 | emit('ui:panel', { view: '' }) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/containers/panel-entry.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var xtend = require('xtend') 3 | 4 | var { intToRest } = require('../lib/time') 5 | var InputRange = require('../components/input/range') 6 | var InputText = require('../components/input/text') 7 | var InputTags = require('../components/input/tags') 8 | 9 | module.exports = panelEntry 10 | 11 | function panelEntry (state, emit) { 12 | return html` 13 |
18 |
19 | ${state 20 | .cache(InputText, 'entry:url') 21 | .render({ 22 | key: 'url', 23 | name: 'http://', 24 | value: state.staging.entry.url, 25 | required: true, 26 | style: state.ui.mobile ? '' : 'brit', 27 | autofocus: true, 28 | onInput: function (data) { 29 | emit('staging:entry', { 30 | url: data.value 31 | }) 32 | } 33 | }) 34 | } 35 |
36 |
37 | ${state 38 | .cache(InputText, 'entry:title') 39 | .render({ 40 | key: 'title', 41 | name: 'Title', 42 | required: true, 43 | value: state.staging.entry.title, 44 | onInput: function (data) { 45 | emit('staging:entry', { 46 | title: data.value 47 | }) 48 | } 49 | }) 50 | } 51 |
52 |
53 |
54 |
55 | ${state 56 | .cache(InputRange, 'entry:rest') 57 | .render({ 58 | name: 'Rest', 59 | value: state.staging.entry.timeRange, 60 | valueShow: false, 61 | onInput: function (data) { 62 | emit('staging:entry', xtend(getTime(data.value), { 63 | timeRange: data.value 64 | })) 65 | } 66 | }) 67 | } 68 |
69 |
70 |
71 | emit('staging:entry', { 74 | timeRange: 0, 75 | duration: parseInt(e.target.value || 0) 76 | })} 77 | type="text" 78 | class="p0 c12 tac fs1 mono bg-white tc-black line" 79 | /> 80 |
81 |
82 | emit('staging:entry', { 85 | timeRange: 0, 86 | interval: e.target.value 87 | })} 88 | type="text" 89 | class="p0 c12 tac fs1 sans bg-white tc-black line" 90 | /> 91 |
92 |
93 |
94 |
95 | ${state 96 | .cache(InputTags, 'entry:tags') 97 | .render({ 98 | key: 'tags', 99 | name: 'Tags', 100 | value: state.staging.entry.tags || [ ], 101 | onChange: function (data) { 102 | emit('staging:entry', { 103 | tags: data.value 104 | }) 105 | } 106 | }) 107 | } 108 |
109 |
110 |
111 |
112 | 118 |
119 |
120 | remove(state.staging.entry.id)} 126 | type="button" 127 | /> 128 |
129 |
130 |
131 | ` 132 | 133 | function getTime (value) { 134 | return intToRest({ 135 | value: value 136 | }) 137 | } 138 | 139 | function handleSubmit (event) { 140 | if (state.staging.entry.id) { 141 | emit('entries:update', state.staging.entry) 142 | } else { 143 | emit('entries:add', state.staging.entry) 144 | } 145 | 146 | emit('ui:panel', { view: '' }) 147 | event.preventDefault() 148 | } 149 | 150 | function reset () { 151 | emit('staging:reset') 152 | emit('pushState', '/') 153 | } 154 | 155 | function remove (id) { 156 | reset() 157 | emit('ui:panel', { view: '' }) 158 | emit('entries:remove', { id: id }) 159 | } 160 | 161 | function isTagsVisible () { 162 | return state.features && state.features.tags 163 | } 164 | 165 | function isStepTwo () { 166 | return state.staging.entry.url 167 | } 168 | 169 | function isStepThree () { 170 | return state.staging.entry.url && state.staging.entry.title 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/containers/panel-options.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var xtend = require('xtend') 3 | 4 | var input = require('../components/input') 5 | 6 | module.exports = view 7 | 8 | function view (state, emit) { 9 | var disabled = isDisabled() 10 | 11 | return html` 12 |
16 |
17 |
18 | ${input(state, emit, xtend(state.options.design.font, { 19 | children: createFontOptions() 20 | }))} 21 |
22 |
23 |
24 |
25 |
26 | ${input(state, emit, state.options.design.scale)} 27 |
28 |
29 |
30 |
31 | ${input(state, emit, state.options.design.spacing)} 32 |
33 |
34 |
35 |
36 |
37 |
38 | ${input(state, emit, state.options.design.colorBg)} 39 |
40 |
41 | ${input(state, emit, state.options.design.colorText)} 42 |
43 |
44 |
45 |
46 | Invert 47 |
48 |
49 |
50 |
51 |
52 | ${input(state, emit, state.options.design.css)} 53 |
54 |
55 |
56 |
57 | ${input(state, emit, state.options.design.entropy)} 58 |
59 |
60 |
61 |
62 | ${input(state, emit, state.options.design.newTab)} 63 |
64 |
65 |
66 |
67 | ${input(state, emit, state.options.design.autoDismiss)} 68 |
69 |
70 |
71 |
72 | ${input(state, emit, state.options.data)} 73 |
74 |
75 |
76 | 81 | 86 |
87 | 88 | FAQ 89 | 90 |
91 |
92 | ${disabled ? createOverlay() : ''} 93 |
94 | ` 95 | 96 | function isDisabled () { 97 | return !state.entries.amount && state.href !== '/panel/options' 98 | } 99 | 100 | function createOverlay () { 101 | return html` 102 |
110 | ` 111 | } 112 | 113 | function createFontOptions () { 114 | return html` 115 |
116 |
117 | ${input(state, emit, state.options.design.uppercase)} 118 |
119 |
120 | ${input(state, emit, state.options.design.hyphenate)} 121 |
122 |
123 | ` 124 | } 125 | 126 | function handleInvertClick () { 127 | emit('options:invert') 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/containers/wrapper.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var css = require('../components/css') 3 | 4 | module.exports = wrapper 5 | 6 | function wrapper(view) { 7 | return function (state, emit) { 8 | return state.app.loaded 9 | ? container(view(state, emit)) 10 | : container(loading()) 11 | 12 | function container(content) { 13 | return html` 14 | 15 | ${!state.user.cyclesDismissed 16 | ? html` 17 |
21 | 27 | New and Improved Version at CycleMarks 28 | 29 | 36 |
37 | 42 | ` 43 | : ''} 44 | ${css(state, emit)} ${content} ${preloadFonts()} 45 | 46 | ` 47 | } 48 | } 49 | } 50 | 51 | function loading() { 52 | return html`
` 53 | } 54 | 55 | function preloadFonts() { 56 | return html` 57 |
58 |
mono
59 |
serif
60 |
61 | ` 62 | } 63 | -------------------------------------------------------------------------------- /src/db/dat.js: -------------------------------------------------------------------------------- 1 | var xtend = require('xtend') 2 | 3 | var saveTimeouts = { } 4 | var modalActive 5 | var archive 6 | 7 | module.exports = { get, save, reset } 8 | 9 | async function load () { 10 | // load from localstorage 11 | var archiveUrl = window.localStorage.archiveUrl 12 | if (modalActive) return // skip if already choosing 13 | 14 | if (!archiveUrl) { 15 | // modalActive = true 16 | archive = await DatArchive.selectArchive({ 17 | title: 'Select an archive to use as your user profile', 18 | buttonLabel: 'Select profile', 19 | filters: { isOwner: true } 20 | }) 21 | window.localStorage.archiveUrl = archive.url 22 | } else { 23 | archive = await DatArchive.load(archiveUrl) 24 | } 25 | // modalActive = false 26 | } 27 | 28 | async function reset () { 29 | // reset 30 | var currentUrl = window.localStorage.archiveUrl 31 | 32 | try { 33 | window.localStorage.archiveUrl = '' 34 | return await load() 35 | } catch (err) { 36 | window.localStorage.archiveUrl = currentUrl 37 | return false 38 | } 39 | } 40 | 41 | async function get (namespace, callback) { 42 | if (window.localStorage.archiveUrl) { 43 | // load 44 | if (!archive) await load() 45 | 46 | try { 47 | var state = await archive.readFile(namespace + '.json') 48 | var output = JSON.parse(state) 49 | if (typeof callback === 'function') callback(output) 50 | return output 51 | } catch (err) { 52 | if (typeof callback === 'function') callback({ }) 53 | } 54 | } else { 55 | // skip if no archive selected 56 | if (typeof callback === 'function') callback({ }) 57 | } 58 | } 59 | 60 | async function save (namespace, state, callback) { 61 | var output = { } 62 | 63 | // load 64 | if (!archive) { 65 | await load() 66 | output = await get(namespace) 67 | } 68 | 69 | // throttle saving 70 | clearTimeout(saveTimeouts[namespace]) 71 | saveTimeouts[namespace] = setTimeout(async function () { 72 | // write state 73 | await archive.writeFile( 74 | namespace + '.json', 75 | JSON.stringify(xtend(output, state), { }, 2) 76 | ) 77 | //callback 78 | if (typeof callback === 'function') callback() 79 | }, 500) 80 | } 81 | -------------------------------------------------------------------------------- /src/db/entries.js: -------------------------------------------------------------------------------- 1 | var db = require('./index') 2 | var namespace = 'entries' 3 | 4 | module.exports = { add, update, remove, dismiss, get } 5 | 6 | function add (data, state) { 7 | db.save(namespace, state) 8 | } 9 | 10 | function update (data, state) { 11 | db.save(namespace, state) 12 | } 13 | 14 | function remove (data, state) { 15 | db.save(namespace, state) 16 | } 17 | 18 | function dismiss (data, state) { 19 | db.save(namespace, state) 20 | } 21 | 22 | function get (cb) { 23 | db.get(namespace, cb) 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/db/index.js: -------------------------------------------------------------------------------- 1 | module.exports = load() 2 | 3 | function load () { 4 | return (typeof DatArchive !== 'undefined') 5 | ? require('./dat') 6 | : require('./localstorage') 7 | } 8 | -------------------------------------------------------------------------------- /src/db/localstorage.js: -------------------------------------------------------------------------------- 1 | var STORAGE_ID = 'asdf_' 2 | var dat = require('./dat') 3 | 4 | module.exports = { save, get } 5 | 6 | function get (namespace, cb) { 7 | try { 8 | var result = JSON.parse(window.localStorage[STORAGE_ID + namespace]) 9 | if (cb && typeof cb === 'function') cb(result) 10 | } catch (err) { 11 | if (cb && typeof cb === 'function') cb({ }) 12 | } 13 | } 14 | 15 | function save (namespace, state, cb) { 16 | window.localStorage[STORAGE_ID + namespace] = JSON.stringify(state) 17 | if (cb && typeof cb === 'function') cb() 18 | } 19 | -------------------------------------------------------------------------------- /src/db/options.js: -------------------------------------------------------------------------------- 1 | var db = require('./index') 2 | var namespace = 'options' 3 | 4 | module.exports = { get, update } 5 | 6 | function update (data, state) { 7 | db.save(namespace, state) 8 | } 9 | 10 | function get (cb) { 11 | db.get(namespace, cb) 12 | } 13 | -------------------------------------------------------------------------------- /src/db/user.js: -------------------------------------------------------------------------------- 1 | var db = require('./index') 2 | var namespace = 'user' 3 | 4 | module.exports = { get, update } 5 | 6 | function update (data, state) { 7 | db.save(namespace, state) 8 | } 9 | 10 | function get (cb) { 11 | db.get(namespace, cb) 12 | } 13 | -------------------------------------------------------------------------------- /src/design/index.js: -------------------------------------------------------------------------------- 1 | var css = require('sheetify') 2 | 3 | css('nanoreset') 4 | css('./index.css') 5 | css('./fonts.css') 6 | css('./utils.js') 7 | css('./simplecolorpicker.css') 8 | -------------------------------------------------------------------------------- /src/design/simplecolorpicker.css: -------------------------------------------------------------------------------- 1 | .Scp { 2 | -webkit-user-select: none; 3 | -moz-user-select: none; 4 | -ms-user-select: none; 5 | user-select: none; 6 | position: relative; 7 | background: #000; 8 | border-radius: 2px; 9 | padding: 2px!important; 10 | display: flex; 11 | position: absolute; 12 | top: -7rem; 13 | left: 2rem; 14 | z-index: 9999; 15 | } 16 | 17 | .Scp:before { 18 | content: ''; 19 | display: none; 20 | position: absolute; 21 | top: -1rem; 22 | left: 2rem; 23 | width: 0; 24 | height: 0; 25 | border-style: solid; 26 | border-width: 0 1rem 1rem 1rem; 27 | border-color: transparent transparent #000 transparent; 28 | } 29 | 30 | .Scp-saturation { 31 | position: relative; 32 | height: 100%; 33 | cursor: crosshair; 34 | background: linear-gradient(to right, #fff, #f00); 35 | } 36 | 37 | .Scp-brightness { 38 | width: 100%; 39 | height: 100%; 40 | background: linear-gradient(rgba(255,255,255,0), #000); 41 | } 42 | .Scp-sbSelector { 43 | border: 2px solid #fff; 44 | position: absolute; 45 | width: 14px; 46 | height: 14px; 47 | background: #fff; 48 | border-radius: 10px; 49 | top: -7px; 50 | left: -7px; 51 | box-sizing: border-box; 52 | z-index: 10; 53 | } 54 | .Scp-hue { 55 | width: 19px; 56 | margin-left: 2px; 57 | height: 100%; 58 | position: relative; 59 | background: linear-gradient(#f00 0%, #f0f 17%, #00f 34%, #0ff 50%, #0f0 67%, #ff0 84%, #f00 100%); 60 | cursor: ns-resize; 61 | } 62 | .Scp-hSelector { 63 | position: absolute; 64 | background: #fff; 65 | border-bottom: 1px solid #000; 66 | right: -3px; 67 | width: 10px; 68 | height: 2px; 69 | } 70 | -------------------------------------------------------------------------------- /src/design/typography.js: -------------------------------------------------------------------------------- 1 | var webfontloader = require('webfontloader') 2 | 3 | exports.local = (cb) => { 4 | if (cb && typeof cb === 'function') { 5 | cb() 6 | } 7 | } 8 | 9 | exports.load = (data, emit) => { 10 | switch (data.host) { 11 | case 'google': 12 | var value = data.weight 13 | ? data.value + ':' + data.weight + (data.style === 'italic' ? 'i' : '') 14 | : data.value 15 | return webfontloader.load({ 16 | google: { 17 | families: [value] 18 | }, 19 | fontactive: function () { 20 | emit('options:loaded', { typeCustom: true }) 21 | emit('options:typography', { 22 | key: data.key, 23 | value: { active: true } 24 | }) 25 | emit('app:render') 26 | } 27 | }) 28 | case 'local': 29 | return webfontloader.load({ 30 | custom: { families: [data.value] }, 31 | fontactive: function () { 32 | emit('options:loaded', { typeCustom: true }) 33 | emit('options:typography', { 34 | key: data.key, 35 | value: { active: true } 36 | }) 37 | emit('app:render') 38 | } 39 | }) 40 | default: 41 | emit('options:loaded', { typeCustom: true }) 42 | emit('app:render') 43 | return false 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/design/user.css: -------------------------------------------------------------------------------- 1 | .design-container { 2 | /* layout */ 3 | --gutter: calc(var(--spacing) * 0.8) var(--spacing); 4 | 5 | /* typography */ 6 | color: var(--foreground); 7 | font-family: var(--font-family); 8 | font-weight: var(--font-weight); 9 | font-style: var(--font-style); 10 | font-size: var(--font-size); 11 | text-transform: var(--font-uppercase); 12 | hyphens: var(--font-hyphenate); 13 | line-height: 1.2; 14 | } -------------------------------------------------------------------------------- /src/design/utils.js: -------------------------------------------------------------------------------- 1 | var gr8 = require('gr8') 2 | var lilcss = require('lilcss') 3 | 4 | var output = '' 5 | var utils = [ ] 6 | 7 | var lilsrc = [ 8 | 'containers/*.js', 9 | 'components/**/*.js', 10 | 'templates/*.js', 11 | 'sandbox/*.js', 12 | 'index.js' 13 | ].map(p => 'src/' + p) 14 | 15 | var lilopts = { 16 | ignore: ['psa', 'psr', 't0', 'b0', 'l0', 'r0'] 17 | } 18 | 19 | utils.push({ 20 | prop: { ps: 'position' }, 21 | vals: { st: 'sticky' } 22 | }) 23 | 24 | utils.push({ 25 | prop: 'width', 26 | unit: '%', 27 | vals: [50] 28 | }) 29 | 30 | utils.push({ 31 | prop: { wrem: 'width' }, 32 | unit: 'rem', 33 | vals: [40, 60] 34 | }) 35 | 36 | utils.push({ 37 | prop: { wmxrem: 'max-width' }, 38 | unit: 'rem', 39 | vals: [40, 50, 60, 70] 40 | }) 41 | 42 | utils.push({ 43 | prop: { mwrem: 'max-width' }, 44 | unit: 'rem', 45 | vals: [43] 46 | }) 47 | 48 | utils.push({ 49 | prop: { op: 'opacity' }, 50 | vals: [{ 33: 0.3 }] 51 | }) 52 | 53 | utils.push({ 54 | prop: { ptvh: 'padding-top' }, 55 | unit: 'vh', 56 | vals: [25, 50, 75, 100] 57 | }) 58 | 59 | utils.push({ 60 | prop: { mtpx: 'margin-top' }, 61 | unit: 'rem', 62 | vals: [0, 2].map(function (size) { return { [size]: size / 10 } }) 63 | }) 64 | 65 | output = gr8({ 66 | breakpoints: { 67 | sm: 600, 68 | md: 800, 69 | lg: 1000 70 | }, 71 | lineHeight: [1, 1.2, 1.5], 72 | fontSize: [0.7, 0.8, 1, 1.2, 1.4, 1.5, 1.6, 1.8, 2, 3, 4] 73 | .map(function (size) { 74 | return { [size.toString().replace('.', '-')]: size * 1.5 } 75 | }), 76 | spacing: [0, 0.25, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 3.6, 4, 4.5, 5] 77 | .map(function (size) { 78 | return { [size.toString().replace('.', '-')]: size * 1.25 } 79 | }), 80 | responsive: true, 81 | utils: utils 82 | }) 83 | 84 | // remove unused classes 85 | if (process.env.NODE_ENV === 'production') { 86 | output = lilcss(output, lilsrc, lilopts) 87 | } 88 | 89 | module.exports = output 90 | -------------------------------------------------------------------------------- /src/helpers/scale.js: -------------------------------------------------------------------------------- 1 | const x = require('xtend') 2 | 3 | const linearConversion = opts => { 4 | const options = x({ 5 | value: 30, 6 | in: { 7 | min: 0, 8 | max: 100 9 | }, 10 | out: { 11 | min: 25, 12 | max: 75 13 | } 14 | }, opts) 15 | 16 | const input = ((options.value - options.in.min) / (options.in.max - options.in.min)) 17 | const output = (options.out.max - options.out.min) 18 | const result = input * output + options.out.min 19 | 20 | return result 21 | } 22 | 23 | module.exports = { 24 | linearConversion 25 | } -------------------------------------------------------------------------------- /src/helpers/time.js: -------------------------------------------------------------------------------- 1 | const x = require('xtend') 2 | 3 | const intToRest = opts => { 4 | const options = x({ 5 | min: 1, 6 | max: 100, 7 | value: 4, 8 | breakpoints: [{ 9 | interval: 'days', 10 | result: { 11 | min: 1, 12 | max: 30 13 | }, 14 | range: { 15 | min: 0, 16 | max: 0.6 17 | } 18 | }, { 19 | interval: 'weeks', 20 | result: { 21 | min: 1, 22 | max: 6 23 | }, 24 | range: { 25 | min: 0.6, 26 | max: 0.8 27 | } 28 | }, { 29 | interval: 'months', 30 | result: { 31 | min: 1, 32 | max: 12 33 | }, 34 | range: { 35 | min: 0.8, 36 | max: 1 37 | } 38 | }] 39 | }, opts) 40 | 41 | const value = options.value / options.max 42 | 43 | const breakpoint = options.breakpoints 44 | .find(bp => { 45 | if ( 46 | value >= bp.range.min && 47 | value < bp.range.max 48 | ) { 49 | return true 50 | } else if ( 51 | options.breakpoints.indexOf(bp) === 52 | options.breakpoints.length - 1 53 | ) { 54 | return true 55 | } else { 56 | return false 57 | } 58 | }) 59 | 60 | const scale = { 61 | input: (value - breakpoint.range.min) 62 | / (breakpoint.range.max - breakpoint.range.min), 63 | output: (breakpoint.result.max - breakpoint.result.min) 64 | + breakpoint.result.min 65 | } 66 | 67 | const result = { 68 | duration: Math.ceil(scale.input * scale.output), 69 | interval: breakpoint.interval 70 | } 71 | 72 | return { 73 | duration: result.duration < 1 ? 1 : result.duration, 74 | interval: result.interval 75 | } 76 | } 77 | 78 | module.exports = { 79 | intToRest 80 | } 81 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | require('intersection-observer') 2 | require('babel-polyfill') 3 | require('./design') 4 | 5 | var html = require('choo/html') 6 | var choo = require('choo') 7 | 8 | var wrapper = require('./containers/wrapper') 9 | var app = choo() 10 | 11 | // plugins 12 | require('./plugins').forEach(plugin => app.use(plugin)) 13 | app.use(require('enoki/choo')('content', { 14 | autoload: false 15 | })) 16 | 17 | // app 18 | app.route('/', wrapper(require('./templates/home'))) 19 | app.route('/all', wrapper(require('./templates/home'))) 20 | app.route('/suggestions', wrapper(require('./templates/suggestions'))) 21 | 22 | // content 23 | app.route('/about', wrapper(require('./templates/about'))) 24 | app.route('/blog', wrapper(require('./templates/blog'))) 25 | app.route('/blog/:entry', wrapper(require('./templates/blog-entry'))) 26 | app.route('/faq', wrapper(require('./templates/faq'))) 27 | app.route('/intro', wrapper(require('./templates/intro'))) 28 | 29 | // panel 30 | app.route('/panel', wrapper(require('./templates/panel'))) 31 | app.route('/panel/:view', wrapper(require('./templates/panel'))) 32 | app.route('/panel/:view/:id', wrapper(require('./templates/panel'))) 33 | 34 | // data 35 | app.route('/data', wrapper(require('./templates/data'))) 36 | app.route('/data/:command', wrapper(require('./templates/data'))) 37 | app.route('/reset', wrapper(require('./templates/reset'))) 38 | 39 | // dev 40 | if (process.env.NODE_ENV === 'development') { 41 | // app.route('/sandbox', wrapper(require('./sandbox'))) 42 | // app.route('/sandbox/:component', wrapper(require('./sandbox'))) 43 | } 44 | 45 | // start 46 | module.exports = app.mount('body') 47 | -------------------------------------------------------------------------------- /src/lib/blog.js: -------------------------------------------------------------------------------- 1 | var objectKeys = require('object-keys') 2 | var xtend = require('xtend') 3 | 4 | module.exports = { 5 | getSuggestions, 6 | getRandomSuggestions 7 | } 8 | 9 | function getRandomSuggestions (state) { 10 | return getSuggestions(state) 11 | } 12 | 13 | function getSuggestions (state) { 14 | return state.page('/blog') 15 | .pages() 16 | .visible() 17 | .sortBy('date', 'desc') 18 | .toArray() 19 | .filter(function (page) { 20 | return page.category === 'list' 21 | }) 22 | .reduce(function (res, cur) { 23 | objectKeys(cur.links) 24 | .forEach(function (key) { 25 | return res.push(xtend( 26 | cur.links[key], { 27 | author: cur.author, 28 | authorUrl: cur.authorUrl, 29 | interval: key 30 | } 31 | )) 32 | }) 33 | return res 34 | }, [ ]) 35 | } 36 | -------------------------------------------------------------------------------- /src/lib/design.js: -------------------------------------------------------------------------------- 1 | var optionsTypography = require('../plugins/options-typography') 2 | var objectKeys = require('object-keys') 3 | var deepEqual = require('deep-equal') 4 | 5 | var designs = require('./designs') 6 | var designsAll = objectKeys(designs) 7 | var randomized = [ ] 8 | 9 | module.exports = { 10 | isDesignDefault, 11 | getRandomDesign, 12 | getDesignDefaults, 13 | getCssDefaults 14 | } 15 | 16 | function isDesignDefault (state, opts) { 17 | var defaults = getDesignDefaults() 18 | var current = objectKeys(defaults).reduce(function (res, cur) { 19 | res[cur] = state.options.values[cur] 20 | return res 21 | }, { }) 22 | return deepEqual(defaults, current) 23 | } 24 | 25 | function getDesignDefaults () { 26 | return { 27 | invert: false, 28 | colorBg: { a: 1, r: 255, g: 255, b: 255 }, 29 | colorText: { a: 1, r: 0, g: 0, b: 0 }, 30 | font: optionsTypography.system, 31 | uppercase: false, 32 | hyphenate: false, 33 | scale: 40, 34 | spacing: 36 35 | } 36 | } 37 | 38 | function getRandomDesign () { 39 | // reset 40 | if (designsAll.length === 0) { 41 | designsAll = randomized 42 | randomized = [ ] 43 | } 44 | 45 | var randomKey = designsAll[Math.floor(Math.random() * designsAll.length)] 46 | designsAll.splice(designsAll.indexOf(randomKey), 1) 47 | randomized.push(randomKey) 48 | return designs[randomKey] 49 | } 50 | 51 | function getCssDefaults () { 52 | return ` 53 | .design-container { 54 | color: var(--foreground); 55 | font-family: var(--font-family); 56 | font-weight: var(--font-weight); 57 | font-style: var(--font-style); 58 | font-size: var(--font-size); 59 | text-transform: var(--font-uppercase); 60 | hyphens: var(--font-hyphenate); 61 | line-height: 1.2; 62 | 63 | --gutter: 64 | calc(var(--spacing) * 0.8) 65 | var(--spacing); 66 | } 67 | ` 68 | } -------------------------------------------------------------------------------- /src/lib/designs.js: -------------------------------------------------------------------------------- 1 | var type = require('../plugins/options-typography') 2 | 3 | exports.simpleDesign = { 4 | colorBg: { a:1, r: 0, g: 0, b: 255 }, 5 | colorText: { a:1, r: 255, g: 255, b: 255 }, 6 | font: type.reglo, 7 | uppercase: true, 8 | hyphenate: false, 9 | scale: 30, 10 | spacing: 40, 11 | } 12 | 13 | exports.greenOne = { 14 | "colorBg": { "r": 0, "g": 131, "b": 87, "a": 1 }, 15 | "colorText": { "r": 255, "g": 255, "b": 255, "a": 1 }, 16 | "font": type.wremenaLight, 17 | "uppercase": false, 18 | "hyphenate": false, 19 | "scale": 42, 20 | "spacing": 30 21 | } 22 | 23 | exports.purpleExpanded = { 24 | "colorBg": { "r": 186, "g": 82, "b": 195, "a": 1 }, 25 | "colorText": { "r": 255, "g": 255, "b": 255, "a": 1 }, 26 | "font": type.lunchtype24MediumExpanded, 27 | "uppercase": false, 28 | "hyphenate": false, 29 | "scale": 32, 30 | "spacing": 10 31 | } 32 | 33 | exports.paper = { 34 | "colorBg": { "r": 231, "g": 231, "b": 231, "a": 1 }, 35 | "colorText": { "r": 46, "g": 46, "b": 46, "a": 1 }, 36 | "font": type.junicodeBoldCondensed, 37 | "uppercase": false, 38 | "hyphenate": true, 39 | "scale": 63, 40 | "spacing": 18 41 | } 42 | 43 | // red 44 | exports.redone = { 45 | "colorBg": { "r": 255, "g": 205, "b": 205, "a": 1 }, 46 | "colorText": { "r": 255, "g": 0, "b": 0, "a": 1 }, 47 | "font": type.yatraRegular, 48 | "uppercase": false, 49 | "hyphenate": false, 50 | "scale": 32, 51 | "spacing": 41 52 | } 53 | 54 | exports.blueSerif = { 55 | "colorBg": { "r": 210, "g": 252, "b": 255, "a": 1 }, 56 | "colorText": { "r": 0, "g": 8, "b": 255, "a": 1 }, 57 | "font": type.sportingGrotesque, 58 | "uppercase": false, 59 | "hyphenate": false, 60 | "scale": 30, 61 | "spacing": 74 62 | } 63 | 64 | exports.authentic = { 65 | "colorBg": { "r": 170, "g": 170, "b": 170, "a": 1 }, 66 | "colorText": { "r": 255, "g": 255, "b": 255, "a": 1 }, 67 | "font": type.authenticSans, 68 | "uppercase": false, 69 | "hyphenate": false, 70 | "scale": 33, 71 | "spacing": 30 72 | } 73 | 74 | exports.punky = { 75 | "colorBg": { "r": 255, "g": 255, "b": 255, "a": 1 }, 76 | "colorText": { "r": 255, "g": 83, "b": 177, "a": 1 }, 77 | "font": type.jrugPunk, 78 | "uppercase": false, 79 | "hyphenate": false, 80 | "scale": 33, 81 | "spacing": 30 82 | } 83 | 84 | exports.fraktur = { 85 | "colorBg": { "r": 0, "g": 0, "b": 0, "a": 1 }, 86 | "colorText": { "r": 255, "g": 255, "b": 255, "a": 1 }, 87 | "font": type.unifrakturMaguntia, 88 | "uppercase": false, 89 | "hyphenate": false, 90 | "scale": 70, 91 | "spacing": 53 92 | } 93 | 94 | exports.spectral = { 95 | "colorBg": { "r": 255, "g": 218, "b": 218, "a": 1 }, 96 | "colorText": { "r": 86, "g": 91, "b": 131, "a": 1 }, 97 | "font": type.spectralExtraLight, 98 | "uppercase": false, 99 | "hyphenate": false, 100 | "scale": 46, 101 | "spacing": 72 102 | } 103 | 104 | exports.terminal = { 105 | "colorBg": { 106 | "r": 207, 107 | "g": 207, 108 | "b": 207, 109 | "a": 1 110 | }, 111 | "colorText": { 112 | "r": 0, 113 | "g": 28, 114 | "b": 255, 115 | "a": 1 116 | }, 117 | "font": type.terminalGrotesque, 118 | "uppercase": false, 119 | "hyphenate": false, 120 | "scale": 46, 121 | "spacing": 72 122 | } 123 | 124 | exports.curvyPurple = { 125 | "invert": true, 126 | "newTab": true, 127 | "autoDismiss": true, 128 | "colorBg": { 129 | "r": 245, 130 | "g": 245, 131 | "b": 245, 132 | "a": 1 133 | }, 134 | "colorText": { 135 | "r": 100, 136 | "g": 0, 137 | "b": 255, 138 | "a": 1 139 | }, 140 | "font": type.pecita, 141 | "uppercase": false, 142 | "hyphenate": false, 143 | "scale": 54, 144 | "spacing": 68 145 | } 146 | -------------------------------------------------------------------------------- /src/lib/entries.js: -------------------------------------------------------------------------------- 1 | var dayjs = require('dayjs') 2 | 3 | module.exports = { 4 | getDismissedDate 5 | } 6 | 7 | function getDismissedDate (entry) { 8 | return dayjs(entry.dateDismissed) 9 | .add(entry.duration, entry.interval) 10 | .startOf('day') 11 | .toDate() 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/scale.js: -------------------------------------------------------------------------------- 1 | const x = require('xtend') 2 | 3 | const linearConversion = opts => { 4 | const options = x({ 5 | value: 30, 6 | in: { 7 | min: 0, 8 | max: 100 9 | }, 10 | out: { 11 | min: 25, 12 | max: 75 13 | } 14 | }, opts) 15 | 16 | const input = ((options.value - options.in.min) / (options.in.max - options.in.min)) 17 | const output = (options.out.max - options.out.min) 18 | const result = input * output + options.out.min 19 | 20 | return result 21 | } 22 | 23 | module.exports = { 24 | linearConversion 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/time.js: -------------------------------------------------------------------------------- 1 | const x = require('xtend') 2 | 3 | const intToRest = opts => { 4 | const options = x({ 5 | min: 1, 6 | max: 100, 7 | value: 4, 8 | breakpoints: [{ 9 | interval: 'days', 10 | result: { 11 | min: 1, 12 | max: 30 13 | }, 14 | range: { 15 | min: 0, 16 | max: 0.6 17 | } 18 | }, { 19 | interval: 'weeks', 20 | result: { 21 | min: 1, 22 | max: 6 23 | }, 24 | range: { 25 | min: 0.6, 26 | max: 0.8 27 | } 28 | }, { 29 | interval: 'months', 30 | result: { 31 | min: 1, 32 | max: 12 33 | }, 34 | range: { 35 | min: 0.8, 36 | max: 1 37 | } 38 | }] 39 | }, opts) 40 | 41 | const value = options.value / options.max 42 | 43 | const breakpoint = options.breakpoints 44 | .find(bp => { 45 | if ( 46 | value >= bp.range.min && 47 | value < bp.range.max 48 | ) { 49 | return true 50 | } else if ( 51 | options.breakpoints.indexOf(bp) === 52 | options.breakpoints.length - 1 53 | ) { 54 | return true 55 | } else { 56 | return false 57 | } 58 | }) 59 | 60 | const scale = { 61 | input: (value - breakpoint.range.min) / 62 | (breakpoint.range.max - breakpoint.range.min), 63 | output: (breakpoint.result.max - breakpoint.result.min) + 64 | breakpoint.result.min 65 | } 66 | 67 | const result = { 68 | duration: Math.ceil(scale.input * scale.output), 69 | interval: breakpoint.interval 70 | } 71 | 72 | return { 73 | duration: result.duration < 1 ? 1 : result.duration, 74 | interval: result.interval 75 | } 76 | } 77 | 78 | module.exports = { 79 | intToRest 80 | } 81 | -------------------------------------------------------------------------------- /src/plugins/app.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = app 3 | 4 | function app (state, emitter) { 5 | state.app = { 6 | loaded: false 7 | } 8 | 9 | // render 10 | emitter.on('app:render', function (data) { 11 | emitter.emit('entries:render') 12 | emitter.emit('render') 13 | }) 14 | 15 | // check 16 | emitter.on('*', checkLoad) 17 | 18 | // load fallback 19 | emitter.on('DOMContentLoaded', function () { 20 | setTimeout(() => { 21 | if (!state.app.loaded) handleLoad() 22 | }, 3000) 23 | }) 24 | 25 | // have we loaded? 26 | function checkLoad (data) { 27 | if ( 28 | state.entries.loaded && 29 | state.options.loaded.typeCustom && 30 | state.options.loaded.typeLocal && 31 | state.options.loaded.data && 32 | !state.app.loaded 33 | ) { handleLoad() } 34 | } 35 | 36 | // all good 37 | function handleLoad () { 38 | state.app.loaded = true 39 | emitter.emit('app:render') 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/plugins/data-storage.js: -------------------------------------------------------------------------------- 1 | var db = require('../db') 2 | 3 | module.exports = pluginData 4 | 5 | function pluginData (state, emitter) { 6 | state.datastorage = getDefaultState() 7 | 8 | // load the archive if there is one 9 | if (state.datastorage.archiveUrl) setArchive() 10 | 11 | // events 12 | state.events.DATA_DAT_LOAD = 'data:dat:load' 13 | emitter.on(state.events.DATA_DAT_LOAD, handleDatLoad) 14 | 15 | async function handleDatLoad (data) { 16 | emitter.emit(state.events.UI_PANEL, { view: '' }) 17 | var reset = await db.reset() 18 | if (reset !== false) { 19 | state.datastorage = getDefaultState() 20 | if (state.datastorage.archiveUrl) setArchive() 21 | emitter.emit(state.events.ENTRIES_LOAD) 22 | emitter.emit(state.events.OPTIONS_LOAD) 23 | } 24 | } 25 | 26 | async function setArchive () { 27 | try { 28 | var archive = await DatArchive.load(state.datastorage.archiveUrl) 29 | state.datastorage.archive = await archive.getInfo() 30 | emitter.emit(state.events.RENDER) 31 | } catch (err) { } 32 | } 33 | 34 | function getDefaultState() { 35 | return { 36 | isDat: (typeof DatArchive !== 'undefined'), 37 | archiveUrl: window.localStorage.archiveUrl, 38 | archive: { } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/plugins/features.js: -------------------------------------------------------------------------------- 1 | module.exports = features 2 | 3 | var beta = process.env.NODE_ENV === 'development' 4 | 5 | function features (state, emitter) { 6 | state.features = { 7 | tags: true, 8 | search: true 9 | } 10 | 11 | emitter.on('feature:enable', function (data) { 12 | if (data.feature) { 13 | state.features[data.feature] = true 14 | } 15 | 16 | if (data.render !== false) { 17 | emitter.emit('app:render') 18 | } 19 | }) 20 | 21 | emitter.on('feature:disable', function (data) { 22 | if (data.feature) { 23 | state.features[data.feature] = false 24 | } 25 | 26 | if (data.render !== false) { 27 | emitter.emit('app:render') 28 | } 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /src/plugins/index.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | // require('./logger'), 3 | require('./data-storage'), 4 | require('./features'), 5 | require('./entries'), 6 | require('./search'), 7 | require('./options'), 8 | require('./ui'), 9 | require('./staging'), 10 | require('./user'), 11 | require('./app'), 12 | require('./scroll'), 13 | require('./notifications') 14 | ] 15 | -------------------------------------------------------------------------------- /src/plugins/logger.js: -------------------------------------------------------------------------------- 1 | module.exports = logger 2 | 3 | function logger (state, emitter) { 4 | state.debug = process.env.NODE_ENV === 'development' 5 | 6 | if (state.debug) { 7 | emitter.on('*', function (messageName, data) { 8 | console.log('event', messageName, data) 9 | }) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/plugins/notifications.js: -------------------------------------------------------------------------------- 1 | var libDesign = require('../lib/design') 2 | 3 | module.exports = pluginNotifications 4 | 5 | function pluginNotifications (state, emitter) { 6 | state.notifications = { 7 | active: '' 8 | } 9 | 10 | state.events.NOTIFICATION = 'notification' 11 | state.events.NOTIFICATIONS = 'notifications' 12 | 13 | emitter.on(state.events.DOMCONTENTLOADED, handleLoad) 14 | 15 | function handleLoad () { 16 | setTimeout(function () { 17 | // design adjustments 18 | if ( 19 | !state.user.notified['customizeDesign'] && 20 | libDesign.isDesignDefault(state) 21 | ) { 22 | state.notifications.active = 'customizeDesign' 23 | emitter.emit('app:render') 24 | return 25 | } 26 | 27 | if ( 28 | !state.user.notified['p2p'] && 29 | typeof WebArchive === 'undefined' 30 | ) { 31 | state.notifications.active = 'p2p' 32 | emitter.emit('app:render') 33 | } 34 | }, 1000) 35 | } 36 | 37 | function handleNotification (data) { 38 | var data = data || { } 39 | var shouldRender = data.render !== false 40 | if (shouldRender) emitter.emit('app:render') 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/plugins/options.js: -------------------------------------------------------------------------------- 1 | var objectValues = require('object-values') 2 | var clone = require('clone-deep') 3 | var xtend = require('xtend') 4 | 5 | var libDesign = require('../lib/design') 6 | var optionsTypography = require('./options-typography') 7 | var typography = require('../design/typography') 8 | var db = require('../db/options') 9 | 10 | module.exports = Options 11 | 12 | function Options (state, emitter) { 13 | state.options = getDefaultState() 14 | 15 | // events 16 | state.events.OPTIONS_LOAD = 'options:load' 17 | 18 | // listen 19 | emitter.on('DOMContentLoaded', handleLoad) 20 | emitter.on(state.events.OPTIONS_LOAD, handleLoad) 21 | 22 | // values 23 | emitter.on('options:values', function (data) { 24 | var newState = clone(state.options.values) 25 | newState[data.key] = data.value 26 | 27 | if (data.key === 'font') { 28 | typography.load(data.value, function (event, _data) { 29 | emitter.emit(event, _data) 30 | }) 31 | } 32 | 33 | db.update(data, newState) 34 | emitter.emit('options:update', newState) 35 | }) 36 | 37 | emitter.on('options:replace', function (data) { 38 | var newState = xtend(state.options.values, data) 39 | db.update(data, newState) 40 | emitter.emit('options:update', newState) 41 | }) 42 | 43 | // update 44 | emitter.on('options:update', function (data) { 45 | state.options.values = xtend(state.options.values, data) 46 | emitter.emit('app:render') 47 | }) 48 | 49 | // reset 50 | emitter.on('options:reset', function (data) { 51 | var defaults = getDefaultState().values 52 | db.update({ }, defaults) 53 | emitter.emit('options:update', defaults) 54 | }) 55 | 56 | // loaded 57 | emitter.on('options:loaded', function (data) { 58 | state.options.loaded = xtend(state.options.loaded, data) 59 | emitter.emit('app:render') 60 | }) 61 | 62 | emitter.on('options:invert', function (data) { 63 | var newState = clone(state.options.values) 64 | 65 | newState.invert = !state.options.values.invert 66 | newState.colorBg = state.options.values.colorText 67 | newState.colorText = state.options.values.colorBg 68 | 69 | db.update({ }, newState) 70 | emitter.emit('options:update', newState) 71 | }) 72 | 73 | emitter.on('options:typography', function () { 74 | var options = objectValues(state.options.typography) 75 | options.forEach(function (data) { 76 | typography.load(data, () => emitter.emit) 77 | }) 78 | }) 79 | 80 | // type 81 | function handleLoad () { 82 | var defaults = getDefaultState() 83 | 84 | typography.local(function () { 85 | emitter.emit('options:loaded', { typeLocal: true }) 86 | emitter.emit('app:render') 87 | }) 88 | 89 | // init 90 | db.get(function (data) { 91 | data = xtend(defaults.values, data) 92 | 93 | if (data.font) { 94 | typography.load(data.font, function () { 95 | emitter.emit('options:loaded', { typeCustom: true }) 96 | }) 97 | } else { 98 | typography.load(state.options.values.font, function () { 99 | emitter.emit('options:loaded', { typeCustom: true }) 100 | }) 101 | } 102 | 103 | emitter.emit('options:update', data) 104 | emitter.emit('options:loaded', { data: true }) 105 | emitter.emit('app:render') 106 | }) 107 | } 108 | } 109 | 110 | function getDefaultState () { 111 | return { 112 | data: { 113 | name: 'Data', 114 | key: 'data', 115 | type: 'data', 116 | visible: true 117 | }, 118 | design: { 119 | colorBg: { 120 | name: 'Background', 121 | key: 'colorBg', 122 | type: 'color', 123 | visible: true 124 | }, 125 | colorText: { 126 | name: 'Text', 127 | key: 'colorText', 128 | type: 'color', 129 | visible: true 130 | }, 131 | font: { 132 | name: 'Font', 133 | key: 'font', 134 | type: 'typography', 135 | visible: true 136 | }, 137 | uppercase: { 138 | name: 'Uppercase', 139 | key: 'uppercase', 140 | type: 'checkbox', 141 | visible: true 142 | }, 143 | hyphenate: { 144 | name: 'Hyphenate', 145 | key: 'hyphenate', 146 | type: 'checkbox', 147 | visible: true 148 | }, 149 | scale: { 150 | name: 'Scale', 151 | key: 'scale', 152 | type: 'range', 153 | min: 5, 154 | max: 72, 155 | showValue: false, 156 | visible: true 157 | }, 158 | spacing: { 159 | name: 'Space', 160 | key: 'spacing', 161 | type: 'range', 162 | min: 0, 163 | max: 25, 164 | showValue: false, 165 | visible: true 166 | }, 167 | invert: { 168 | name: 'Invert', 169 | key: 'invert', 170 | visible: false 171 | }, 172 | entropy: { 173 | name: 'Randomly offset rest duration', 174 | key: 'entropy', 175 | type: 'range', 176 | min: 0, 177 | max: 7, 178 | unit: 'days', 179 | scaleValue: true, 180 | showValue: true, 181 | visible: true 182 | }, 183 | newTab: { 184 | name: 'Open links in a new window', 185 | key: 'newTab', 186 | type: 'checkbox', 187 | visible: true 188 | }, 189 | autoDismiss: { 190 | name: 'Auto Hide Entries', 191 | key: 'autoDismiss', 192 | type: 'checkbox', 193 | visible: false 194 | }, 195 | css: { 196 | name: 'Edit your custom CSS', 197 | key: 'css', 198 | type: 'textarea', 199 | visible: true 200 | } 201 | }, 202 | values: xtend({ 203 | invert: false, 204 | newTab: true, 205 | autoDismiss: true, 206 | entropy: 0, 207 | css: libDesign.getCssDefaults() 208 | }, libDesign.getDesignDefaults()), 209 | loaded: { 210 | typeLocal: false, 211 | typeCustom: false, 212 | data: false 213 | }, 214 | typography: optionsTypography 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/plugins/scroll.js: -------------------------------------------------------------------------------- 1 | module.exports = pluginScroll 2 | 3 | function pluginScroll (state, emitter) { 4 | emitter.on(state.events.PUSHSTATE, function () { 5 | window.scrollTo(0, 0) 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /src/plugins/search.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = search 3 | 4 | function search (state, emitter) { 5 | state.search = { 6 | term: '', 7 | active: false, 8 | options: { 9 | enabled: true 10 | } 11 | } 12 | 13 | emitter.on('search:update', function (data = { }) { 14 | // check if active 15 | if (!isEnabled()) return 16 | 17 | // search term 18 | if (data.value !== undefined) { 19 | state.search.term = data.value 20 | } 21 | 22 | // show all if not already 23 | if (data.all && !state.ui.entriesViewAll) { 24 | emitter.emit('ui:update', { entriesViewAll: true }) 25 | } 26 | 27 | emitter.emit(state.events.UI_PAGINATE, { 28 | page: 1, 29 | render: false 30 | }) 31 | 32 | // hide the panel 33 | if (data.hidePanel && state.ui.panel.view) { 34 | emitter.emit('ui:panel', { view: '' }) 35 | } 36 | 37 | // rendering 38 | if (data.render) { 39 | emitter.emit('app:render') 40 | } 41 | }) 42 | 43 | function isEnabled () { 44 | return state.features && state.features.search 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/plugins/staging.js: -------------------------------------------------------------------------------- 1 | const xtend = require('xtend') 2 | 3 | module.exports = Staging 4 | 5 | function Staging (state, emitter) { 6 | state.staging = getEmptyState() 7 | 8 | emitter.on('staging:reset', function (data) { 9 | state.staging = getEmptyState() 10 | emitter.emit('app:render') 11 | }) 12 | 13 | emitter.on('staging:entry', function (data) { 14 | state.staging.entry = xtend(state.staging.entry, data) 15 | emitter.emit('app:render') 16 | }) 17 | } 18 | 19 | function getEmptyState () { 20 | return { 21 | id: '', 22 | entry: { 23 | title: '', 24 | tags: [ ], 25 | duration: 7, 26 | interval: 'days', 27 | visited: 0, 28 | timeRange: 20, 29 | url: '' 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/plugins/ui.js: -------------------------------------------------------------------------------- 1 | var dayjs = require('dayjs') 2 | var xtend = require('xtend') 3 | 4 | module.exports = pluginUi 5 | 6 | var resizeFrame 7 | 8 | function pluginUi (state, emitter) { 9 | state.ui = { 10 | date: dayjs().format('MMMM D'), 11 | loaded: false, 12 | stagingActive: false, 13 | introActive: false, 14 | entriesViewAll: false, 15 | mobile: false, 16 | pagination: { 17 | page: 1, 18 | limit: 15 19 | }, 20 | panel: { 21 | active: false, 22 | view: '' 23 | } 24 | } 25 | 26 | state.events.UI_PANEL = 'ui:panel' 27 | state.events.UI_UPDATE = 'ui:update' 28 | state.events.UI_PAGINATE = 'ui:paginate' 29 | 30 | emitter.on(state.events.UI_UPDATE, function (data) { 31 | state.ui = xtend(state.ui, data) 32 | emitter.emit('app:render') 33 | }) 34 | 35 | emitter.on(state.events.UI_PANEL, function (data) { 36 | var render = state.ui.panel.view !== data.view 37 | state.ui.panel = xtend(state.ui.panel, data) 38 | if (render) emitter.emit('app:render', state.events.UI_PANEL) 39 | }) 40 | 41 | emitter.on(state.events.UI_PAGINATE, function (data) { 42 | data = data || { } 43 | var shouldRender = data.render !== false 44 | delete data.render 45 | state.ui.pagination = xtend(state.ui.pagination, data) 46 | if (shouldRender) emitter.emit('app:render') 47 | }) 48 | 49 | emitter.on('DOMContentLoaded', function () { 50 | setMobile() 51 | window.addEventListener('resize', setMobile) 52 | }) 53 | 54 | function setMobile () { 55 | clearTimeout(resizeFrame) 56 | resizeFrame = setTimeout(function () { 57 | state.ui.mobile = window.innerWidth <= 600 58 | emitter.emit('app:render') 59 | }, 100) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/plugins/user.js: -------------------------------------------------------------------------------- 1 | var clone = require('clone-deep') 2 | var xtend = require('xtend') 3 | 4 | var db = require('../db/user') 5 | 6 | module.exports = user 7 | 8 | function user(state, emitter) { 9 | state.user = getState() 10 | 11 | state.events.USER_LOAD = 'user:load' 12 | state.events.USER_RESET = 'user:reset' 13 | state.events.USER_LOADED = 'user:loaded' 14 | state.events.USER_UPDATE = 'user:update' 15 | state.events.USER_FEATURE = 'user:feature' 16 | state.events.USER_NOTIFIED = 'user:notified' 17 | state.events.USER_ANALYTICS = 'user:analytics' 18 | state.events.USER_CYCLES_DISMISS = 'user:cycles:dismiss' 19 | 20 | emitter.on('DOMContentLoaded', function () { 21 | db.get( 22 | function (data) { 23 | emitter.emit(state.events.USER_LOAD, data) 24 | }, 25 | function () { 26 | emitter.emit(state.events.USER_LOADED, data) 27 | } 28 | ) 29 | }) 30 | 31 | emitter.on(state.events.USER_LOADED, function (data) { 32 | // state.user.analytics.visits += 1 33 | // state.user.analytics.lastvisit = new Date().toISOString() 34 | // emitter.emit('user:update') 35 | }) 36 | 37 | emitter.on(state.events.USER_ANALYTICS, function (data) { 38 | state.user.analytics = xtend(state.user.analytics, data) 39 | emitter.emit('user:update') 40 | }) 41 | 42 | emitter.on('pushState', function (data) { 43 | // if ( 44 | // process.env.NODE_ENV === 'production' && 45 | // window.ga && 46 | // typeof window.ga === 'function' 47 | // ) { 48 | // window.ga('set', 'page', window.location.pathname) 49 | // window.ga('send', 'pageview') 50 | // } 51 | }) 52 | 53 | emitter.on(state.events.USER_LOAD, function (data) { 54 | state.user = xtend(state.user, data) 55 | emitter.emit(state.events.USER_LOADED, data) 56 | }) 57 | 58 | emitter.on(state.events.USER_UPDATE, function (data) { 59 | db.update(data, state.user) 60 | emitter.emit('app:render') 61 | }) 62 | 63 | // user prefs for features 64 | emitter.on(state.events.USER_FEATURE, function (data) { 65 | if (typeof data === 'object') { 66 | state.user.features = xtend(state.user.features, data) 67 | } 68 | 69 | if (data.render !== false) { 70 | emitter.emit('app:render') 71 | } 72 | }) 73 | 74 | // cycles dismissed 75 | emitter.on(state.events.USER_CYCLES_DISMISS, function (data) { 76 | console.log('yo') 77 | state.user.cyclesDismissed = true 78 | emitter.emit(state.events.USER_UPDATE) 79 | }) 80 | 81 | // notified 82 | emitter.on(state.events.USER_NOTIFIED, function (data) { 83 | var data = data || {} 84 | if (!data.id) return 85 | state.notifications.active = '' // whoops 86 | state.user.notified[data.id] = true 87 | emitter.emit(state.events.USER_UPDATE) 88 | }) 89 | 90 | emitter.on(state.events.USER_RESET, function (data) { 91 | state.user = getState() 92 | window.localStorage.archiveUrl = '' 93 | emitter.emit(state.events.USER_UPDATE) 94 | }) 95 | } 96 | 97 | function getState() { 98 | return { 99 | credentials: { 100 | email: '', 101 | photoURL: '', 102 | uuid: '', 103 | }, 104 | features: { 105 | search: true, 106 | }, 107 | analytics: { 108 | authenticated: false, 109 | visits: 0, 110 | lastvisit: undefined, 111 | }, 112 | notified: {}, 113 | signedIn: false, 114 | cyclesDismissed: false, 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/sandbox/index.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var ov = require('object-values') 3 | var xd = require('xtend') 4 | 5 | var input = require('./input') 6 | var ui = require('./interface') 7 | 8 | module.exports = Sandbox 9 | 10 | function Sandbox (state, emit) { 11 | var components = [ ...input, ...ui ] 12 | .map(function (component) { 13 | return component({ }, log) 14 | }) 15 | 16 | var navigationComponents = ov(components) 17 | .map(function (component) { 18 | var active = state.params.component === component.key 19 | return html` 20 | ${component.name} 27 | ` 28 | }) 29 | 30 | return html` 31 |
32 | ${sidebar()} 33 | ${content()} 34 |
35 | ` 36 | 37 | function sidebar (props = { }) { 38 | return html` 39 |
40 |
41 | ${navigationComponents} 42 |
43 |
44 | ` 45 | } 46 | 47 | function content (props = { }) { 48 | var examples = components 49 | .filter(function (_component) { 50 | return _component.key === state.params.component 51 | }) 52 | 53 | if (examples.length <= 0) { 54 | return wrapper(html` 55 |
Components not found
56 | `) 57 | } 58 | 59 | return wrapper( 60 | examples.map(function (component) { 61 | if (!isComponentValid(component)) { 62 | return html` 63 |
Component can not mount
64 | ` 65 | } 66 | return component.variations 67 | .map(function (variation) { 68 | return example( 69 | variation, 70 | h(component.template, variation.props) 71 | ) 72 | }) 73 | }) 74 | ) 75 | } 76 | 77 | function log (data) { 78 | console.log('sandbox', data) 79 | } 80 | } 81 | 82 | function wrapper (children) { 83 | return html` 84 |
85 | ${children} 86 |
87 | ` 88 | } 89 | 90 | function example (props, children) { 91 | return html` 92 |
93 |
94 |
95 |
${JSON.stringify(props.props)}
96 |
97 | ${children} 98 |
99 |
100 | ` 101 | } 102 | 103 | function isComponentValid (props) { 104 | return props && 105 | props.template && 106 | props.variations 107 | } 108 | -------------------------------------------------------------------------------- /src/sandbox/input.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = [ 3 | checkbox, 4 | range, 5 | text, 6 | tags 7 | ] 8 | 9 | function checkbox (state, emit) { 10 | return { 11 | key: 'checkbox', 12 | name: 'Checkbox', 13 | template: require('../components/input/checkbox'), 14 | variations: [{ 15 | name: 'Default', 16 | props: { 17 | key: 'one', 18 | name: 'Test', 19 | value: true, 20 | onChange: function (data) { 21 | emit({ 22 | component: 'Checkbox', 23 | data: data 24 | }) 25 | } 26 | } 27 | }, { 28 | name: 'Inactive', 29 | props: { 30 | key: 'two', 31 | value: false 32 | } 33 | }, { 34 | name: 'Custom icon', 35 | props: { 36 | key: 'three', 37 | name: 'Custom icon', 38 | icon: '🙃', 39 | value: true 40 | } 41 | }] 42 | } 43 | } 44 | 45 | function range (state, emit) { 46 | return { 47 | key: 'range', 48 | name: 'Range', 49 | template: require('../components/input/range'), 50 | variations: [{ 51 | name: 'Default', 52 | props: { 53 | key: 'one', 54 | name: 'Test', 55 | value: 50, 56 | onInput: function (data) { 57 | emit({ 58 | component: 'Range', 59 | data: data 60 | }) 61 | } 62 | } 63 | }, { 64 | name: 'Value', 65 | props: { 66 | key: 'one', 67 | name: 'Test', 68 | showValue: true, 69 | value: 10 70 | } 71 | }] 72 | } 73 | } 74 | 75 | function text (state, emit) { 76 | return { 77 | key: 'text', 78 | name: 'Text', 79 | template: require('../components/input/text'), 80 | variations: [{ 81 | name: 'Default', 82 | props: { 83 | key: 'one', 84 | name: 'Test', 85 | onInput: function (data) { 86 | emit({ 87 | component: 'Text', 88 | data: data 89 | }) 90 | } 91 | } 92 | }, { 93 | name: 'Value', 94 | props: { 95 | key: 'one', 96 | name: 'Test', 97 | value: 'This one has a value' 98 | } 99 | }, { 100 | name: 'Autofocus', 101 | props: { 102 | key: 'one', 103 | name: 'Autofocus example', 104 | autofocus: true 105 | } 106 | }] 107 | } 108 | } 109 | 110 | function tags (state, emit) { 111 | return { 112 | key: 'tags', 113 | name: 'Tags', 114 | template: require('../components/input/tags'), 115 | variations: [{ 116 | name: 'Default', 117 | props: { 118 | key: 'one', 119 | name: 'Test', 120 | value: [ ], 121 | onChange: function (data) { 122 | emit({ 123 | component: 'Tags', 124 | data: data 125 | }) 126 | } 127 | } 128 | }, { 129 | name: 'Tags', 130 | props: { 131 | key: 'two', 132 | value: ['one', 'two', 'three'], 133 | onChange: function (data) { 134 | emit({ 135 | component: 'Tags', 136 | data: data 137 | }) 138 | } 139 | } 140 | }] 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/sandbox/interface.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = [ 3 | search 4 | ] 5 | 6 | function search (state, emit) { 7 | return { 8 | key: 'search', 9 | name: 'Search', 10 | template: require('../components/search'), 11 | variations: [{ 12 | name: 'Default', 13 | props: { 14 | value: true, 15 | onChange: function (data) { 16 | emit({ 17 | component: 'Search', 18 | data: data 19 | }) 20 | } 21 | } 22 | }] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/templates/about.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var containerContent = require('../containers/content') 4 | var format = require('../components/format') 5 | 6 | module.exports = view 7 | 8 | function view (state, emit) { 9 | return containerContent(state, emit, content(state, emit)) 10 | } 11 | 12 | function content (state, emit) { 13 | return html` 14 |
15 |
16 | ${format(state.page().v('text'))} 17 |
18 |
19 | ` 20 | } 21 | -------------------------------------------------------------------------------- /src/templates/blog-entry.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var containerContent = require('../containers/content') 4 | var entryBlog = require('../components/entry-blog') 5 | var format = require('../components/format') 6 | 7 | module.exports = view 8 | 9 | function view (state, emit) { 10 | return containerContent(state, emit, content(state, emit)) 11 | } 12 | 13 | function content (state, emit) { 14 | var page = state.page().v() 15 | 16 | return html` 17 |
18 | ${entryBlog(state, emit, page)} 19 |
20 | ` 21 | } 22 | -------------------------------------------------------------------------------- /src/templates/blog.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var Content = require('../containers/content') 4 | var Blog = require('../containers/blog') 5 | 6 | module.exports = view 7 | 8 | function view (state, emit) { 9 | return Content(state, emit, content(state, emit)) 10 | } 11 | 12 | function content (state, emit) { 13 | var entries = state.page() 14 | .children() 15 | .visible() 16 | .sortBy('date', 'desc') 17 | .toArray() 18 | 19 | return state.cache(Blog, 'blog').render({ 20 | entries: entries 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /src/templates/data.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var ov = require('object-values') 3 | 4 | var css = require('../components/css') 5 | 6 | var navigationOpts = { 7 | export: { 8 | key: 'export', 9 | text: 'Export' 10 | }, 11 | import: { 12 | key: 'import', 13 | text: 'Import' 14 | }, 15 | design: { 16 | key: 'design', 17 | text: 'Design' 18 | } 19 | } 20 | 21 | var getCommand = command => command || 'export' 22 | 23 | module.exports = view 24 | 25 | function handleImportClick (event, emit) { 26 | var input = event.target.parentNode.querySelector('textarea') 27 | var value = input.value 28 | 29 | try { 30 | var result = JSON.parse(value) 31 | emit('entries:reset', result) 32 | alert('imported!') 33 | } catch (err) { 34 | alert('Please enter valid JSON') 35 | console.warn(err) 36 | } 37 | } 38 | 39 | function elNavigation (state, emit) { 40 | var command = getCommand(state.params.command) 41 | var opts = ov(navigationOpts) 42 | 43 | var elsOpts = opts.map((opt, i) => html` 44 | 48 | 49 | ${opt.text} 50 | 51 | 52 | `) 53 | 54 | return html`
58 | ${elsOpts} 59 | × 64 |
` 65 | } 66 | 67 | function elImport (state, emit) { 68 | return html`
69 | 74 |
handleImportClick(event, emit)} 77 | >Submit
78 |
` 79 | } 80 | 81 | function elExport (state, emit) { 82 | var entries = state.entries.all 83 | return html` 84 |
85 | 90 |
91 | ` 92 | } 93 | 94 | function elDesign (state, emit) { 95 | var options = state.options.values 96 | return html` 97 |
98 | 103 |
104 | ` 105 | } 106 | 107 | function view (state, emit) { 108 | var command = getCommand(state.params.command) 109 | var elContent = getContent() 110 | 111 | return html`
112 | ${elNavigation(state, emit)} 113 | ${elContent(state, emit)} 114 | ${css(state, emit)} 115 |
` 116 | 117 | function getContent () { 118 | switch (state.params.command) { 119 | case 'import': 120 | return elImport 121 | case 'design': 122 | return elDesign 123 | default: 124 | return elExport 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/templates/faq.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var containerContent = require('../containers/content') 4 | var format = require('../components/format') 5 | 6 | module.exports = view 7 | 8 | function view (state, emit) { 9 | return containerContent(state, emit, content(state, emit)) 10 | } 11 | 12 | function content (state, emit) { 13 | var text = state.page().v('text') || '' 14 | var answers = text 15 | .split('##') 16 | .filter(str => str) 17 | .map(str => '##' + str) 18 | 19 | return html` 20 |
21 |
22 | ${answers.map(createAnswer)} 23 |
24 |
25 | ` 26 | 27 | function createAnswer (props) { 28 | return html` 29 |
30 | ${format(props)} 31 |
32 | ` 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/templates/home.js: -------------------------------------------------------------------------------- 1 | var EntryNavigation = require('../containers/entry-navigation') 2 | var Notification = require('../containers/notification') 3 | var Panel = require('../containers/panel-container') 4 | var Intro = require('../containers/intro') 5 | var EntryList = require('../containers/entry-list') 6 | 7 | module.exports = view 8 | 9 | function view (state, emit) { 10 | var panelProps = { 11 | isHoverActive: true && !state.ui.mobile, 12 | view: state.ui.panel.view 13 | } 14 | 15 | // hide if nothing to load 16 | if (!state.app.loaded) return '' 17 | 18 | // all 19 | if (state.route === 'all' && !state.ui.entriesViewAll) { 20 | emit('ui:update', { entriesViewAll: true }) 21 | } 22 | 23 | // non all 24 | if ( 25 | state.route !== 'all' && 26 | state.ui.entriesViewAll && 27 | !state.search.term 28 | ) { 29 | emit('ui:update', { entriesViewAll: false }) 30 | } 31 | 32 | return [ 33 | Panel(state, panelProps, emit), 34 | EntryNavigation(state, emit), 35 | createContent() 36 | ] 37 | 38 | function createNotification () { 39 | if (state.notifications.active) { 40 | return Notification(state, emit) 41 | } 42 | } 43 | 44 | function createContent () { 45 | return (state.entries.amount === 0) 46 | ? createIntro(state, emit) 47 | : [EntryList(state, emit), createNotification()] 48 | } 49 | 50 | function createIntro () { 51 | // show if we have’t 52 | if (!state.ui.mobile && !state.ui.panel.loaded) { 53 | setTimeout(function () { 54 | emit('ui:panel', { view: 'entry', loaded: true }) 55 | }, 1) 56 | } 57 | return Intro(state, emit) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/templates/intro.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var containerContent = require('../containers/content') 4 | var IntroVideo = require('../components/intro-video') 5 | 6 | module.exports = view 7 | 8 | function view (state, emit) { 9 | return containerContent(state, emit, content(state, emit)) 10 | } 11 | 12 | function content (state, emit) { 13 | return html` 14 |
15 |
Coming soon
16 | ${state.cache(IntroVideo, 'intro-video').render()} 17 |
18 | ` 19 | } 20 | -------------------------------------------------------------------------------- /src/templates/panel.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var EntryNavigation = require('../containers/entry-navigation') 4 | var Panel = require('../containers/panel-container') 5 | var EntryList = require('../containers/entry-list') 6 | 7 | module.exports = view 8 | 9 | function view (state, emit) { 10 | var panelProps = { 11 | isHoverActive: false, 12 | view: state.params.view 13 | } 14 | 15 | return [ 16 | Panel(state, panelProps, emit), 17 | !state.ui.mobile ? EntryList(state, emit) : '', 18 | EntryNavigation(state, emit), 19 | !state.ui.mobile ? createOverlay() : html`
` 20 | ] 21 | 22 | function createOverlay () { 23 | return html` 24 |
29 | ` 30 | } 31 | 32 | function handleOverlayClick () { 33 | emit('pushState', '/') 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/templates/reset.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var css = require('../components/css') 3 | 4 | var resetAll = (emit) => { 5 | emit('entries:reset') 6 | emit('options:reset') 7 | emit('user:reset') 8 | } 9 | 10 | var resetEntries = (emit) => emit('entries:reset') 11 | var resetOptions = (emit) => emit('options:reset') 12 | var resetUser = (emit) => emit('user:reset') 13 | 14 | module.exports = (state, emit) => { 15 | var elContainer = content => html`
${content}
` 18 | 19 | var elReset = html`
20 |
21 |
resetAll(emit)} 24 | > 25 | Reset Everything 26 |
27 |
28 | 29 |
30 |
resetOptions(emit)} 33 | > 34 | Reset Options 35 |
36 |
37 | 38 |
39 |
resetEntries(emit)} 42 | > 43 | Reset Entries 44 |
45 |
46 |
` 47 | 48 | var elConfirmation = html`
49 | Your local data has been reset 50 |
` 51 | 52 | return html`
53 | ${elContainer(elReset)} 54 | ${css(state, emit)} 55 |
` 56 | } 57 | -------------------------------------------------------------------------------- /src/templates/suggestions.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | 3 | var EntryNavigation = require('../containers/entry-navigation') 4 | var Suggestions = require('../containers/suggestions') 5 | var Panel = require('../containers/panel-container') 6 | var EntryList = require('../containers/entry-list') 7 | var loading = require('../components/loading') 8 | 9 | module.exports = viewSuggestions 10 | 11 | function viewSuggestions (state, emit) { 12 | // hide the nav 13 | if (!state.ui.panel.view !== '' && !state.ui.panel.loadedAbout) { 14 | emit('ui:panel', { view: '', loadedAbout: true }) 15 | } 16 | 17 | var panelProps = { 18 | isHoverActive: true && !state.ui.mobile, 19 | view: state.ui.panel.view 20 | } 21 | 22 | if (!state.site.loaded) { 23 | emit(state.events.CONTENT_LOAD) 24 | return loading() 25 | } 26 | 27 | return [ 28 | Panel(state, panelProps, emit), 29 | EntryNavigation(state, emit), 30 | EntryList(state, emit), 31 | createContent() 32 | ] 33 | 34 | function createContent () { 35 | return html` 36 |
41 | ${state.cache(Suggestions, 'suggestions').render()} 42 |
43 | ` 44 | } 45 | 46 | function handleContainerClick (event) { 47 | var isContainer = event.target.hasAttribute('data-suggestions') 48 | if (isContainer && state.entries.amount) emit('pushState', '/') 49 | } 50 | } 51 | --------------------------------------------------------------------------------