├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── ci.yml │ └── update-patterns.yml ├── .gitignore ├── .gitmodules ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── 11ty ├── eleventy.config.js ├── filters │ ├── dates.js │ └── timestamp.js └── shortcodes │ ├── patternListing.js │ ├── patternPreview.js │ └── renderRelatedPatterns.js ├── LICENSE ├── README.md ├── images ├── favicon.ico ├── icons │ ├── arrow-right.svg │ ├── back.svg │ ├── check.svg │ ├── edit.svg │ ├── forward.svg │ ├── icon-library.svg │ ├── rectangle_o.svg │ ├── rectangle_w.svg │ └── star.svg ├── illustrations │ ├── Architecture_Sprint.png │ ├── Design_Sprint.png │ ├── Informational_Interview.png │ ├── placeholder.svg │ └── qr_code.svg ├── logo │ ├── simply-secure-assets_Logo - White - Vertical (1).svg │ ├── simply-secure-assets_Logo - White - Vertical.svg │ ├── simply-secure-assets_Logo - White Horizontal.svg │ └── simplysecure-logo--white@2.png └── meta │ ├── og.jpg │ └── twitter.jpg ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── Barriers to Adoption for Web Monetization (April 2021).pdf ├── DOTS-webmon-report.txt ├── DOTS_Report_7Maxims.pdf ├── report.txt ├── robots.txt └── zines │ └── web-monetization │ ├── decent-large.png │ ├── decent-small.png │ ├── icons.svg │ ├── index.html │ └── zine.js ├── scripts ├── main.js ├── modules │ ├── filterlist │ │ └── index.js │ ├── lazyload │ │ └── index.js │ └── mobile-nav │ │ └── index.js └── utilities │ ├── helpers │ └── index.js │ └── selectors │ └── index.js ├── site ├── 404.njk ├── _globals │ ├── helpers.js │ ├── library.json │ ├── navigation.js │ └── site.json ├── _includes │ ├── components │ │ ├── featured-pattern.njk │ │ ├── footer.njk │ │ ├── header.njk │ │ ├── loading.njk │ │ ├── logo.njk │ │ ├── mobile-nav.njk │ │ ├── nav.njk │ │ ├── social-icons.njk │ │ └── social-meta.njk │ ├── layouts │ │ ├── article.njk │ │ ├── default.njk │ │ ├── pattern.njk │ │ └── topic.njk │ └── library.njk ├── _patterns-meta │ ├── library.md │ ├── patterns-list-alphabetical.njk │ └── patterns-list-lastUpdated.njk ├── about.njk ├── assembly.md ├── contribute.njk ├── glossary.md ├── governance.md ├── includes │ └── components │ │ └── loading.njk ├── index.njk ├── library ├── projects │ └── web-monetization │ │ ├── gftw-hero.png │ │ ├── image_1.png │ │ ├── image_2.png │ │ ├── image_3.png │ │ ├── image_4.png │ │ ├── image_5.png │ │ ├── image_6.png │ │ ├── image_7.png │ │ └── index.md ├── report.md ├── sitemap.njk ├── support-us.njk ├── topics ├── virtual-workshop-amarillo.md ├── virtual-workshop-cyan.md ├── vision.md └── work-with-us.njk ├── styles ├── base │ ├── _all.scss │ ├── _fonts.scss │ ├── _global.scss │ ├── _links.scss │ ├── _typography.scss │ └── _utilities.scss ├── components │ ├── _all.scss │ ├── _buttons.scss │ ├── _footer.scss │ ├── _form.scss │ ├── _header.scss │ ├── _main.scss │ ├── _mobile-nav.scss │ ├── donate.scss │ ├── examples.scss │ ├── featured-pattern.scss │ ├── links.scss │ ├── offers.scss │ ├── pattern-listing.scss │ ├── pattern-main.scss │ ├── pattern-preview.scss │ ├── pattern.scss │ ├── projects.scss │ ├── report.scss │ └── timeline.scss ├── fonts │ ├── Inter-Black.woff │ ├── Inter-Black.woff2 │ ├── Inter-BlackItalic.woff │ ├── Inter-BlackItalic.woff2 │ ├── Inter-Bold.woff │ ├── Inter-Bold.woff2 │ ├── Inter-BoldItalic.woff │ ├── Inter-BoldItalic.woff2 │ ├── Inter-ExtraBold.woff │ ├── Inter-ExtraBold.woff2 │ ├── Inter-ExtraBoldItalic.woff │ ├── Inter-ExtraBoldItalic.woff2 │ ├── Inter-ExtraLight.woff │ ├── Inter-ExtraLight.woff2 │ ├── Inter-ExtraLightItalic.woff │ ├── Inter-ExtraLightItalic.woff2 │ ├── Inter-Italic.woff │ ├── Inter-Italic.woff2 │ ├── Inter-Light.woff │ ├── Inter-Light.woff2 │ ├── Inter-LightItalic.woff │ ├── Inter-LightItalic.woff2 │ ├── Inter-Medium.woff │ ├── Inter-Medium.woff2 │ ├── Inter-MediumItalic.woff │ ├── Inter-MediumItalic.woff2 │ ├── Inter-Regular.woff │ ├── Inter-Regular.woff2 │ ├── Inter-SemiBold.woff │ ├── Inter-SemiBold.woff2 │ ├── Inter-SemiBoldItalic.woff │ ├── Inter-SemiBoldItalic.woff2 │ ├── Inter-Thin.woff │ ├── Inter-Thin.woff2 │ ├── Inter-ThinItalic.woff │ ├── Inter-ThinItalic.woff2 │ ├── Inter-italic.var.woff2 │ ├── Inter-roman.var.woff2 │ ├── Inter.var.woff2 │ ├── SpaceGrotesk-Bold.woff │ ├── SpaceGrotesk-Bold.woff2 │ ├── SpaceGrotesk-Light.woff │ ├── SpaceGrotesk-Light.woff2 │ ├── SpaceGrotesk-Medium.woff │ ├── SpaceGrotesk-Medium.woff2 │ ├── SpaceGrotesk-Regular.woff │ ├── SpaceGrotesk-Regular.woff2 │ ├── SpaceGrotesk-SemiBold.woff │ ├── SpaceGrotesk-SemiBold.woff2 │ ├── grotesk.css │ └── inter.css └── main.scss ├── tailwind.config.js ├── update_patterns.sh └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /mix-manifest.json 3 | 4 | /js/main*.js 5 | 6 | /dots-patterns 7 | /site/library 8 | /site/topics 9 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | env: { 5 | browser: true, 6 | es2021: true, 7 | }, 8 | extends: [ 9 | "airbnb-base", 10 | "prettier", // keep last 11 | ], 12 | parserOptions: { 13 | ecmaVersion: 12, 14 | sourceType: "module", 15 | }, 16 | plugins: ["prettier"], 17 | ignorePatterns: ["public/zines/*/zine.js"], 18 | rules: { 19 | "prettier/prettier": "warn", 20 | }, 21 | settings: { 22 | "import/resolver": { 23 | alias: { 24 | map: [ 25 | ["@utilities", path.resolve(__dirname, "scripts/utilities")], 26 | ["@modules", path.resolve(__dirname, "scripts/modules")], 27 | ["~", path.resolve(__dirname, "scripts")], 28 | ], 29 | }, 30 | }, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: ["master", "develop"] 7 | 8 | jobs: 9 | run-linters: 10 | name: Run linters 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Check out Git repository 15 | uses: actions/checkout@v2 16 | 17 | - name: Read node version from .nvmrc 18 | id: nvmrc 19 | uses: browniebroke/read-nvmrc-action@v1 20 | 21 | - uses: actions/setup-node@v1 22 | with: 23 | node-version: "${{ steps.nvmrc.outputs.node_version }}" 24 | 25 | - uses: actions/cache@v2 26 | env: 27 | cache-name: cache-node-modules 28 | with: 29 | path: ~/.npm 30 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 31 | restore-keys: | 32 | ${{ runner.os }}-build-${{ env.cache-name }}- 33 | ${{ runner.os }}-build- 34 | ${{ runner.os }}- 35 | - run: npm ci 36 | 37 | - name: Generate ESLint report 38 | run: npm run lint -- --output-file eslint_report.json --format json 39 | continue-on-error: true 40 | - name: Annotate report 41 | uses: ataylorme/eslint-annotate-action@1.1.2 42 | with: 43 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 44 | report-json: "eslint_report.json" 45 | continue-on-error: true 46 | - name: Upload ESLint report 47 | uses: actions/upload-artifact@v1 48 | with: 49 | name: eslint_report.json 50 | path: eslint_report.json 51 | -------------------------------------------------------------------------------- /.github/workflows/update-patterns.yml: -------------------------------------------------------------------------------- 1 | name: Update pattern library 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | update-patterns: 8 | name: Update pattern library 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Check out Git repository 13 | uses: actions/checkout@v2 14 | with: 15 | ref: master 16 | submodules: true 17 | 18 | - name: Read node version from .nvmrc 19 | id: nvmrc 20 | uses: browniebroke/read-nvmrc-action@v1 21 | 22 | - uses: actions/setup-node@v1 23 | with: 24 | node-version: "${{ steps.nvmrc.outputs.node_version }}" 25 | 26 | - uses: actions/cache@v2 27 | env: 28 | cache-name: cache-node-modules 29 | with: 30 | path: ~/.npm 31 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 32 | restore-keys: | 33 | ${{ runner.os }}-build-${{ env.cache-name }}- 34 | ${{ runner.os }}-build- 35 | ${{ runner.os }}- 36 | - run: npm ci 37 | 38 | - name: Update pattern submodule 39 | run: git submodule update --init --remote 40 | 41 | - name: Run linter 42 | run: npm run lint 43 | continue-on-error: false 44 | 45 | - name: Run prettier 46 | run: npm run prettier 47 | 48 | - name: Add and commit any changes 49 | uses: EndBug/add-and-commit@v5 50 | with: 51 | # The arguments for the `git add` command (see the paragraph below for more info) 52 | # Default: '.' 53 | add: "dots-patterns" 54 | 55 | # The name of the user that will be displayed as the author of the commit 56 | # Default: author of the commit that triggered the run 57 | author_name: DOTS Community 58 | 59 | # The email of the user that will be displayed as the author of the commit 60 | # Default: author of the commit that triggered the run 61 | author_email: no-reply@decentpatterns.xyz 62 | 63 | # Name of the branch to use, if different from the one that triggered the workflow 64 | # Default: the branch that triggered the run 65 | branch: master 66 | 67 | # The message for the commit 68 | # Default: 'Commit from GitHub Actions (name of the workflow)' 69 | message: "Update pattern library" 70 | 71 | # Whether to use the --signoff option on `git commit` (only `true` and `false` are accepted) 72 | # Default: false 73 | signoff: true 74 | 75 | env: 76 | # This is necessary in order to push a commit to the repo 77 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Leave this line unchanged 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | 4 | /dist/ 5 | /css/ 6 | /js/ 7 | 8 | .vscode 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dots-patterns"] 2 | path = dots-patterns 3 | url = https://github.com/simplysecure/dots-patterns.git 4 | [submodule "site/zine"] 5 | path = site/zine 6 | url = https://github.com/substack/zine.git 7 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v12.18.4 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | 3 | dots-patterns/ 4 | site/library/ 5 | site/topics/ 6 | 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Start dev server", 9 | "request": "launch", 10 | "runtimeArgs": ["run", "start"], 11 | "runtimeExecutable": "npm", 12 | "skipFiles": ["/**"], 13 | "type": "pwa-node" 14 | }, 15 | { 16 | "name": "Build and serve", 17 | "request": "launch", 18 | "runtimeArgs": ["serve", "dist"], 19 | "runtimeExecutable": "npx", 20 | "skipFiles": ["/**"], 21 | "type": "pwa-node", 22 | "preLaunchTask": "build" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "files.associations": { 4 | "*.njk": "nunjucks" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "build", 7 | "group": { 8 | "kind": "build", 9 | "isDefault": true 10 | }, 11 | "problemMatcher": [], 12 | "label": "build", 13 | "detail": "cross-env NODE_ENV=production npm-run-all -l clean build:*" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /11ty/eleventy.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | const htmlmin = require("html-minifier"); 3 | const markdownIt = require("markdown-it"); 4 | const markdownItAnchor = require("markdown-it-anchor"); 5 | const markdownItContainer = require("markdown-it-container"); 6 | const markdownItFootnote = require("markdown-it-footnote"); 7 | const markdownItWikilinks = require("@f3rno/markdown-it-wikilinks"); 8 | const slugify = require("slugify"); 9 | 10 | const dateFilters = require("./filters/dates.js"); 11 | const timestampFilters = require("./filters/timestamp.js"); 12 | const patternPreview = require("./shortcodes/patternPreview.js"); 13 | const renderRelatedPatterns = require("./shortcodes/renderRelatedPatterns.js"); 14 | const patternListing = require("./shortcodes/patternListing.js"); 15 | 16 | module.exports = (eleventyConfig) => { 17 | // Add a readable date formatter filter to Nunjucks 18 | eleventyConfig.addFilter("dateDisplay", dateFilters); 19 | 20 | // Add a HTML timestamp formatter filter to Nunjucks 21 | eleventyConfig.addFilter("htmlDateDisplay", timestampFilters); 22 | 23 | // Minify our HTML 24 | eleventyConfig.addTransform("htmlmin", (content, outputPath) => { 25 | if (outputPath.endsWith(".html")) { 26 | const minified = htmlmin.minify(content, { 27 | useShortDoctype: true, 28 | removeComments: true, 29 | collapseWhitespace: true, 30 | }); 31 | return minified; 32 | } 33 | return content; 34 | }); 35 | 36 | // Collections 37 | 38 | // Configure 11ty to merge directory-level data with item-level data (e.g tags) 39 | eleventyConfig.setDataDeepMerge(true); 40 | 41 | const byTitle = (a, b) => { 42 | if (a.data.title == null) return -1; 43 | if (b.data.title == null) return 1; 44 | return a.data.title.localeCompare(b.data.title, "en"); 45 | }; 46 | 47 | const byLastUpdated = (a, b) => { 48 | if (a.data.created == null) return -1; 49 | if (b.data.created == null) return 1; 50 | return a.data.created > b.data.created; 51 | }; 52 | 53 | const insertPatterns = (getPatternsByTopic) => (topic) => { 54 | // eslint-disable-next-line 55 | topic.data.patterns = getPatternsByTopic(topic.data.slug).sort( 56 | byLastUpdated 57 | ); 58 | return topic; 59 | }; 60 | 61 | eleventyConfig.addCollection("patternsByTitle", (collection) => 62 | collection.getFilteredByTag("pattern").sort(byTitle) 63 | ); 64 | eleventyConfig.addCollection("patternsByLastUpdated", (collection) => 65 | collection.getFilteredByTag("pattern").sort(byLastUpdated) 66 | ); 67 | eleventyConfig.addCollection("topicsByTitle", (collection) => 68 | collection 69 | .getFilteredByTag("topic") 70 | .map( 71 | insertPatterns((topicSlug) => 72 | collection 73 | .getFilteredByTags("pattern") 74 | .filter((pattern) => pattern.data.topic === topicSlug) 75 | ) 76 | ) 77 | .sort(byTitle) 78 | ); 79 | 80 | // Shortcodes 81 | eleventyConfig.addShortcode("patternPreview", patternPreview); 82 | eleventyConfig.addShortcode("renderRelatedPatterns", renderRelatedPatterns); 83 | eleventyConfig.addShortcode("patternListing", patternListing); 84 | 85 | // Layout aliases 86 | eleventyConfig.addLayoutAlias("default", "layouts/default.njk"); 87 | eleventyConfig.addLayoutAlias("article", "layouts/article.njk"); 88 | eleventyConfig.addLayoutAlias("timeline", "layouts/timeline.njk"); 89 | eleventyConfig.addLayoutAlias("pattern", "layouts/pattern.njk"); 90 | eleventyConfig.addLayoutAlias("topic", "layouts/topic.njk"); 91 | 92 | // Include our static assets 93 | eleventyConfig.addPassthroughCopy({ "styles/fonts": "fonts" }); 94 | eleventyConfig.addPassthroughCopy("images"); 95 | eleventyConfig.addPassthroughCopy({ public: "files" }); 96 | eleventyConfig.addPassthroughCopy({ "public/robots.txt": "robots.txt" }); 97 | eleventyConfig.addPassthroughCopy({ "public/zines": "zines" }); 98 | 99 | // Add assets for individual patterns 100 | eleventyConfig.addPassthroughCopy("site/library/**/*.{svg,png,jpg,jpeg}"); 101 | 102 | eleventyConfig.addPassthroughCopy("site/projects/**/*.{svg,png,jpg,jpeg}"); 103 | 104 | const options = { 105 | html: true, 106 | breaks: false, 107 | linkify: false, 108 | typographer: true, 109 | }; 110 | 111 | // Configure wikilinks to transfrom in the right way, i.e.: 112 | // [[some link]] => href="/library/some-link" 113 | const wikilinksOptions = { 114 | generatePageNameFromLabel: (label) => slugify(label, { lower: true }), 115 | relativeBaseURL: "/library/", 116 | uriSuffix: "", 117 | }; 118 | 119 | const markdownLib = markdownIt(options) 120 | .use(markdownItWikilinks(wikilinksOptions)) 121 | .use(markdownItFootnote) 122 | .use(markdownItAnchor, { permalink: true, level: 1 }) 123 | .use(markdownItContainer, "examples"); 124 | 125 | eleventyConfig.setLibrary("md", markdownLib); 126 | 127 | return { 128 | templateFormats: ["md", "njk"], 129 | markdownTemplateEngine: "njk", 130 | htmlTemplateEngine: "njk", 131 | passthroughFileCopy: true, 132 | 133 | dir: { 134 | input: "site", 135 | output: "dist", 136 | includes: "_includes", 137 | data: "_globals", 138 | }, 139 | }; 140 | }; 141 | -------------------------------------------------------------------------------- /11ty/filters/dates.js: -------------------------------------------------------------------------------- 1 | /* 2 | A date formatter filter for Nunjucks 3 | */ 4 | function dateFilters(date, part) { 5 | const d = new Date(date); 6 | if (part === "year") { 7 | return d.getUTCFullYear(); 8 | } 9 | const month = [ 10 | "January", 11 | "February", 12 | "March", 13 | "April", 14 | "May", 15 | "June", 16 | "July", 17 | "August", 18 | "September", 19 | "October", 20 | "November", 21 | "December", 22 | ]; 23 | const ordinal = { 24 | 1: "st", 25 | 2: "nd", 26 | 3: "rd", 27 | 21: "st", 28 | 22: "nd", 29 | 23: "rd", 30 | 31: "st", 31 | }; 32 | 33 | return `${d.getDate() + (ordinal[d.getDate()] || "th")} ${ 34 | month[d.getMonth()] 35 | }, ${d.getUTCFullYear()}`; 36 | } 37 | 38 | module.exports = dateFilters; 39 | -------------------------------------------------------------------------------- /11ty/filters/timestamp.js: -------------------------------------------------------------------------------- 1 | /* 2 | A simple ISO timestamp for Nunjucks 3 | */ 4 | function timestampFilter() { 5 | const timestamp = new Date(); 6 | return `${timestamp.getFullYear()}-${ 7 | timestamp.getMonth() + 1 8 | }-${timestamp.getDate()}`; 9 | } 10 | 11 | module.exports = timestampFilter; 12 | -------------------------------------------------------------------------------- /11ty/shortcodes/patternListing.js: -------------------------------------------------------------------------------- 1 | module.exports = (collection, sort) => { 2 | const hasSorting = sort != null; 3 | const isAlphabetical = sort === "alphabetical"; 4 | const linkAlphabetical = isAlphabetical 5 | ? "./#pattern-listing" 6 | : "../#pattern-listing"; 7 | const linkLastUpdated = !isAlphabetical 8 | ? "./#pattern-listing" 9 | : "./last-updated#pattern-listing"; 10 | 11 | const sortButtons = hasSorting 12 | ? `
13 | Alphabetical 16 | Last Updated 19 |
` 20 | : ""; 21 | 22 | return `
23 |
24 | 25 | ${sortButtons} 26 |
27 |
`; 28 | }; 29 | -------------------------------------------------------------------------------- /11ty/shortcodes/patternPreview.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | 3 | /** 4 | * Render a thumbnail display of a given pattern object 5 | */ 6 | module.exports = (pattern) => ` 7 | 16 | `; 17 | -------------------------------------------------------------------------------- /11ty/shortcodes/renderRelatedPatterns.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | const slugify = require("slugify"); 3 | 4 | /** 5 | * Render links for a list of pattern names 6 | * 7 | * Used in the pattern detail page sidebar 8 | */ 9 | module.exports = (patterns, collection) => { 10 | const patternExists = (patternName) => 11 | collection.filter( 12 | (p) => 13 | slugify(p.data.title, { lower: true }) === 14 | slugify(patternName, { lower: true }) 15 | ).length !== 0; 16 | 17 | const patternList = patterns 18 | .sort() 19 | .map((p) => 20 | patternExists(p) 21 | ? ` 22 | ` 28 | : ` 29 | ` 35 | ) 36 | .reduce((prev, cur) => prev + cur, ""); 37 | return ``; 38 | }; 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Decentral Patterns Website 2 | 3 | This repository holds the sources for the [decentpatterns.xyz](https://decentpatterns.xyz) website. It's built using the static site generator Eleventy, the tailwindcss framework and Javascript. 4 | 5 | ## Installation and development 6 | 7 | First, make sure that you have initialized and updated the `dots-patterns` submodule. 8 | 9 | ``` 10 | git submodule update --init 11 | ``` 12 | 13 | The site is developed for Node v12, you can use `nvm use` to load the specific version from `.nvmrc` or install it yourselves. Now you can pull the dependencies. 14 | 15 | ``` 16 | npm install 17 | ``` 18 | 19 | To start the development server, run the `npm start` command in terminal and open [`localhost:3000`](http://localhost:3000/). The development server is configured to automatically reload when you make changes. 20 | 21 | We use prettier and eslint to maintain a consistent and maintainable code style. Use the npm commands `npm run lint` to validate sources and `npm run prettier` to reformat sources on disk. 22 | 23 | ## Folder Structure 24 | 25 | ### Content 26 | 27 | The `site` folder contains all the templates, partials and content - which Eleventy will parse into HTML for us. Within our `site` folder, lives a `globals` folder. Here you'll find a `site.json` file - for general config stuff e.g site name, author, email, social media links etc. You'll also find a `navigation.json` file, which we use to loop over in our nav partial to generate our navigation. It's possible to hide navigation entries from the production deployment by setting `"draft": true` on them. There's also a `helpers.js` file, which just contains a simple environment helper. 28 | 29 | The repository [dots-patterns](https://github.com/simplysecure/dots-patterns) contains markdown-formatted patterns that are included in the site. The repository contents are symlinked into the folders `site/library` and `site/topics`. 30 | 31 | ### Assets 32 | 33 | Some of the assets are bundled using Webpack. This includes client-side Javascript, which you can find in the `scripts` folder and SCSS stylesheets, which are in the `styles` folder. 34 | 35 | Other assets are copied as-is for deployment. This includes fonts in `styles/fonts`, images in `images` and downloadable files in the `public` folder. 36 | 37 | ### Tooling 38 | 39 | The repository root contains configuration files for the various tools we use. In addition, you will find the more elaborate config for 11ty in the `11ty` folder. 40 | 41 | ## Ready to deploy? 42 | 43 | Type the `npm run build` command to minify scripts, styles and run Purgecss. 44 | 45 | Purge will cross reference your templates/HTML with all those Tailwind classes and will remove any classes you haven't used - pretty cool huh? 46 | -------------------------------------------------------------------------------- /images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/images/favicon.ico -------------------------------------------------------------------------------- /images/icons/arrow-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Icon / Web / Orange / Arrow Right 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /images/icons/back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /images/icons/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /images/icons/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Svg Vector Icons : http://www.onlinewebfonts.com/icon 6 | 7 | 8 | -------------------------------------------------------------------------------- /images/icons/forward.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /images/icons/icon-library.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /images/icons/rectangle_o.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rectangle 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /images/icons/rectangle_w.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rectangle 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /images/icons/star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /images/illustrations/Architecture_Sprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/images/illustrations/Architecture_Sprint.png -------------------------------------------------------------------------------- /images/illustrations/Design_Sprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/images/illustrations/Design_Sprint.png -------------------------------------------------------------------------------- /images/illustrations/Informational_Interview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/images/illustrations/Informational_Interview.png -------------------------------------------------------------------------------- /images/illustrations/placeholder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /images/logo/simply-secure-assets_Logo - White - Vertical (1).svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/logo/simply-secure-assets_Logo - White - Vertical.svg: -------------------------------------------------------------------------------- 1 | simply-secure-assets -------------------------------------------------------------------------------- /images/logo/simply-secure-assets_Logo - White Horizontal.svg: -------------------------------------------------------------------------------- 1 | simply-secure-assets -------------------------------------------------------------------------------- /images/logo/simplysecure-logo--white@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/images/logo/simplysecure-logo--white@2.png -------------------------------------------------------------------------------- /images/meta/og.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/images/meta/og.jpg -------------------------------------------------------------------------------- /images/meta/twitter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/images/meta/twitter.jpg -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dots-website", 3 | "version": "1.0.0", 4 | "description": "Decentral Patterns Website", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/simplysecure/dots-website" 8 | }, 9 | "author": "Simply Secure", 10 | "license": "CC0-1.0", 11 | "private": true, 12 | "scripts": { 13 | "production": "npm run build", 14 | "build": "cross-env NODE_ENV=production npm-run-all -l clean build:*", 15 | "build:eleventy": "eleventy --config=11ty/eleventy.config.js", 16 | "build:webpack": "webpack", 17 | "clean": "rimraf dist", 18 | "lint": "eslint .", 19 | "prettier": "prettier --write .", 20 | "start": "cross-env NODE_ENV=development npm-run-all --silent clean --parallel start:*", 21 | "start:eleventy": "ELEVENTY_ENV=development eleventy --watch --quiet --config=11ty/eleventy.config.js", 22 | "start:webpack": "webpack serve", 23 | "start:browser-sync": "browser-sync start --proxy 'localhost:8081' --files dist --browser chromium --logLevel silent" 24 | }, 25 | "dependencies": { 26 | "@11ty/eleventy": "^0.11.1", 27 | "tailwindcss": "^1.9.5" 28 | }, 29 | "devDependencies": { 30 | "@fullhuman/postcss-purgecss": "^3.1.3", 31 | "@f3rno/markdown-it-wikilinks": "^1.0.3", 32 | "autoprefixer": "^10.2.4", 33 | "browser-sync": "^2.26.14", 34 | "clean-webpack-plugin": "^3.0.0", 35 | "cross-env": "^7.0.3", 36 | "css-loader": "^5.0.2", 37 | "eslint": "^7.19.0", 38 | "eslint-config-airbnb-base": "^14.2.1", 39 | "eslint-config-prettier": "^6.15.0", 40 | "eslint-import-resolver-alias": "^1.1.2", 41 | "eslint-plugin-import": "^2.22.1", 42 | "eslint-plugin-prettier": "^3.3.1", 43 | "html-minifier": "^4.0.0", 44 | "markdown-it": "^12.0.4", 45 | "markdown-it-anchor": "^7.0.2", 46 | "markdown-it-container": "^3.0.0", 47 | "markdown-it-footnote": "^3.0.2", 48 | "mini-css-extract-plugin": "^1.3.6", 49 | "npm-run-all": "^4.1.5", 50 | "postcss": "^8.2.10", 51 | "postcss-loader": "^4.2.0", 52 | "prettier": "^2.2.1", 53 | "rimraf": "^3.0.2", 54 | "sass": "^1.32.7", 55 | "sass-loader": "^10.1.1", 56 | "style-loader": "^2.0.0", 57 | "webpack": "^5.21.2", 58 | "webpack-cli": "^4.5.0", 59 | "webpack-dev-server": "^3.11.2" 60 | }, 61 | "engines": { 62 | "node": ">=12.0.0" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | const autoprefixer = require("autoprefixer"); 3 | const tailwindcss = require("tailwindcss"); 4 | 5 | module.exports = { 6 | plugins: [tailwindcss("./tailwind.config.js"), autoprefixer], 7 | }; 8 | -------------------------------------------------------------------------------- /public/Barriers to Adoption for Web Monetization (April 2021).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/public/Barriers to Adoption for Web Monetization (April 2021).pdf -------------------------------------------------------------------------------- /public/DOTS_Report_7Maxims.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/public/DOTS_Report_7Maxims.pdf -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | 4 | Sitemap: https://decentpatterns.xyz/sitemap.xml 5 | -------------------------------------------------------------------------------- /public/zines/web-monetization/decent-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/public/zines/web-monetization/decent-large.png -------------------------------------------------------------------------------- /public/zines/web-monetization/decent-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/public/zines/web-monetization/decent-small.png -------------------------------------------------------------------------------- /public/zines/web-monetization/icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 24 | 28 | 29 | 30 | 48 | 50 | 51 | 53 | image/svg+xml 54 | 56 | 57 | 58 | 59 | 60 | 64 | 68 | 75 | 81 | 86 | 91 | 96 | 97 | 104 | 107 | 114 | 119 | 124 | 129 | 134 | 139 | 144 | 149 | 154 | 159 | 164 | 169 | 174 | 175 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /public/zines/web-monetization/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /scripts/main.js: -------------------------------------------------------------------------------- 1 | // Import local modules 2 | import "@modules/mobile-nav"; 3 | import "@modules/lazyload"; 4 | import "@modules/filterlist"; 5 | -------------------------------------------------------------------------------- /scripts/modules/filterlist/index.js: -------------------------------------------------------------------------------- 1 | const FilterBar = (function setupFilterbar() { 2 | const filterbarInput = document.getElementById("filterbar-input"); 3 | const container = document.getElementById("pattern-listing-entries"); 4 | const noResults = document.getElementById("pattern-listing-no-results"); 5 | 6 | if (container == null) { 7 | console.log("no filterlist container"); 8 | return; 9 | } 10 | 11 | function updateSearchResults() { 12 | const searchPhrase = filterbarInput.value.toLowerCase(); 13 | const items = container.getElementsByTagName("a"); 14 | 15 | let val; 16 | let numResults = 0; 17 | for (let i = 0; i < items.length; i += 1) { 18 | val = items[i].text.toLowerCase(); 19 | if (val.includes(searchPhrase)) { 20 | items[i].style.display = "initial"; 21 | numResults += 1; 22 | } else { 23 | items[i].style.display = "none"; 24 | } 25 | } 26 | 27 | if (numResults === 0) { 28 | noResults.style.display = "block"; 29 | } else { 30 | noResults.style.display = "none"; 31 | } 32 | } 33 | 34 | updateSearchResults(); 35 | filterbarInput.addEventListener("keyup", updateSearchResults); 36 | })(); 37 | 38 | export default FilterBar; 39 | -------------------------------------------------------------------------------- /scripts/modules/lazyload/index.js: -------------------------------------------------------------------------------- 1 | import $$ from "@utilities/selectors"; 2 | import { exists } from "@utilities/helpers"; 3 | 4 | const Lazyload = (function Lazyload() { 5 | // lazyload our images 6 | const images = $$.wrapper.querySelectorAll("[data-lazy]"); 7 | 8 | if (exists(images)) { 9 | // options 10 | const options = { 11 | threshold: 0.5, 12 | }; 13 | 14 | const preloadImage = function preloadImage(img) { 15 | // find and store the image's data-lazy attribute 16 | // commented out for now, but if you want to go the extra mile, then you can do all the srcset attribute stuff on the images ;) 17 | // const srcset = img.dataset.srcset 18 | const src = img.dataset.lazy; 19 | 20 | // TODO: Refactor to not assign to function parameter 21 | // I think this shouldn't stay but I am not sure whether we keep this 22 | // functionality so I don't want to spend the time refactoring it for 23 | // nothing 24 | // eslint-disable-next-line no-param-reassign 25 | img.src = src; 26 | // img.srcset = srcset 27 | 28 | // add a class of loaded 29 | // we can then use this as a hook for fade-in animations etc 30 | img.classList.add("loaded"); 31 | }; 32 | 33 | const lazyObserver = new IntersectionObserver((entries, lazyLoad) => { 34 | entries.forEach((entry) => { 35 | if (entry.isIntersecting) { 36 | preloadImage(entry.target); 37 | lazyLoad.unobserve(entry.target); 38 | } 39 | }); 40 | }, options); 41 | 42 | images.forEach((image) => { 43 | lazyObserver.observe(image); 44 | }); 45 | } 46 | })(); 47 | 48 | export default Lazyload; 49 | -------------------------------------------------------------------------------- /scripts/modules/mobile-nav/index.js: -------------------------------------------------------------------------------- 1 | import $$ from "@utilities/selectors"; 2 | 3 | function toggleMobileMenu() { 4 | this.classList.toggle("menu-toggle-active"); 5 | $$.mobileNav.classList.toggle("menu-visible"); 6 | $$.wrapper.classList.toggle("menu-visible"); 7 | 8 | // set aria-expanded attribute on menu toggle button 9 | if (this.getAttribute("aria-expanded") === "false") { 10 | this.setAttribute("aria-expanded", "true"); 11 | } else { 12 | this.setAttribute("aria-expanded", "false"); 13 | } 14 | } 15 | 16 | const MobileNav = (function MobileNav() { 17 | $$.mobileNavToggle.addEventListener("click", toggleMobileMenu); 18 | })(); 19 | 20 | export default MobileNav; 21 | -------------------------------------------------------------------------------- /scripts/utilities/helpers/index.js: -------------------------------------------------------------------------------- 1 | const $$ = require("@utilities/selectors"); 2 | 3 | /** 4 | * @description Test if the body id is something 5 | * @param {string} 6 | * @return {bool} 7 | * 8 | */ 9 | 10 | const page = (name) => { 11 | if (!name) { 12 | return $$.body.getAttribute("id"); 13 | } 14 | 15 | return $$.body.getAttribute("id") === name; 16 | }; 17 | 18 | /** 19 | * @description Check if element exists the page 20 | * @param {string} Element selector 21 | * @param {string} Minimum number of elements 22 | * @return {bool} 23 | */ 24 | 25 | const exists = (el) => { 26 | return el.length > 0; 27 | }; 28 | 29 | module.exports = { page, exists }; 30 | -------------------------------------------------------------------------------- /scripts/utilities/selectors/index.js: -------------------------------------------------------------------------------- 1 | const $$ = { 2 | body: document.querySelector("body"), 3 | 4 | wrapper: document.getElementById("wrapper"), 5 | 6 | header: document.getElementById("header"), 7 | 8 | nav: document.getElementById("nav"), 9 | 10 | hero: document.getElementById("hero"), 11 | 12 | main: document.getElementById("main"), 13 | 14 | containerCentre: document.getElementById("container-centre"), 15 | 16 | containerRight: document.getElementById("container-right"), 17 | 18 | preFooter: document.getElementById("pre-footer"), 19 | 20 | footer: document.getElementById("footer"), 21 | 22 | mobileNav: document.getElementById("mobile-nav"), 23 | 24 | mobileNavToggle: document.getElementById("mobile-nav-toggle"), 25 | }; 26 | 27 | module.exports = $$; 28 | -------------------------------------------------------------------------------- /site/404.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | permalink: 404.html 4 | hidden: true 5 | meta_title: 404 6 | body_class: 404 7 | title: Oops! 8 | --- 9 | 10 |
11 | 12 | 24 | 25 |
26 | -------------------------------------------------------------------------------- /site/_globals/helpers.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | /** 4 | * Assemble related patterns by loading the page source from disk 5 | * and scanning for [[wikilinks]]. 6 | */ 7 | const getRelatedPatterns = (data) => { 8 | // this is the same regex pattern as used by the wikilinks markdownit 9 | // extension (taken from documentation on npm) 10 | const regex = /\[\[([\w\s/]+)(\|([\w\s/]+))?\]\]/g; 11 | const content = fs.readFileSync(data.page.inputPath, { 12 | encoding: "utf8", 13 | flag: "r", 14 | }); 15 | try { 16 | return [...content.matchAll(regex)].map((m) => m[1]); 17 | } catch (err) { 18 | console.error( 19 | `Error extracting related patterns: malformed wikilink (${err})` 20 | ); 21 | return []; 22 | } 23 | }; 24 | 25 | const categoryName = (data) => { 26 | const category = data.collections.topic.find( 27 | (t) => t.data.slug === data.topic 28 | ); 29 | if (category == null) { 30 | // console.error( 31 | // `Category ${data.topic} for pattern ${data.title} not found.` 32 | // ); 33 | return `Category ${data.topic} not found`; 34 | } 35 | return category.data.title; 36 | }; 37 | 38 | module.exports = { 39 | // environment helper 40 | environment: process.env.ELEVENTY_ENV, 41 | 42 | // Netlify sets this in their build environment 43 | is_netlify_production: process.env.CONTEXT === "production", 44 | 45 | relatedPatterns: getRelatedPatterns, 46 | 47 | categoryName, 48 | }; 49 | -------------------------------------------------------------------------------- /site/_globals/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "featured": "conditional-file-sharing" 3 | } 4 | -------------------------------------------------------------------------------- /site/_globals/navigation.js: -------------------------------------------------------------------------------- 1 | // Base navigation configuration to which filters are applied below. 2 | const navitems = { 3 | main: [ 4 | { 5 | label: "Home", 6 | url: "/", 7 | }, 8 | { 9 | label: "Pattern Library", 10 | url: "/library/", 11 | }, 12 | { 13 | label: "Contribute", 14 | url: "/contribute/", 15 | }, 16 | { 17 | label: "About", 18 | url: "/about/", 19 | }, 20 | ], 21 | }; 22 | 23 | /** 24 | * True when executed in a Netfliy production build context 25 | */ 26 | const isNetlifyProduction = process.env.CONTEXT === "production"; 27 | 28 | /** 29 | * Filter draft items when in production context 30 | * 31 | * @param {Object} input navigation configuration 32 | */ 33 | const draftFilter = ({ main, ...rest }) => ({ 34 | main: main.filter((item) => !item.draft || !isNetlifyProduction), 35 | ...rest, 36 | }); 37 | 38 | const filteredNavitems = draftFilter(navitems); 39 | module.exports = filteredNavitems; 40 | -------------------------------------------------------------------------------- /site/_globals/site.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Decentralization Off The Shelf", 3 | "url": "https://decentpatterns.xyz", 4 | "author": { 5 | "name": "Simply Secure", 6 | "email": "team@simplysecure.org", 7 | "handle": "@simplysecureorg", 8 | "avatar": "/images/blog/author.jpg" 9 | }, 10 | "images": { 11 | "logo": "/images/logo/logo.svg", 12 | "favicon": "/images/favicon.ico", 13 | "twitter": "/images/meta/twitter.jpg", 14 | "og": "/images/meta/og.jpg" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /site/_includes/components/featured-pattern.njk: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

Featured Pattern

5 |
6 | 7 | 27 |
28 | -------------------------------------------------------------------------------- /site/_includes/components/footer.njk: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /site/_includes/components/header.njk: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /site/_includes/components/loading.njk: -------------------------------------------------------------------------------- 1 |
2 | 4 | 5 | 8 | 9 | 10 | 13 | 14 | 15 | 18 | 19 | 20 |
21 | -------------------------------------------------------------------------------- /site/_includes/components/logo.njk: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /site/_includes/components/mobile-nav.njk: -------------------------------------------------------------------------------- 1 | 27 | 28 | 38 | -------------------------------------------------------------------------------- /site/_includes/components/nav.njk: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /site/_includes/components/social-icons.njk: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /site/_includes/components/social-meta.njk: -------------------------------------------------------------------------------- 1 | {# Google Schema #} 2 | 3 | 4 | 5 | {# Twitter #} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {# Open Graph #} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /site/_includes/layouts/article.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |
6 |
7 | {{ content | safe }} 8 |
9 |
10 | -------------------------------------------------------------------------------- /site/_includes/layouts/default.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% if meta_title %}{{ meta_title }}{% else %}{{ title }}{% endif %} | 8 | {{ site.name }} 9 | 10 | 16 | {% if page.fileSlug === 'blog' %} 17 | 18 | {% else %} 19 | 20 | {% endif %} {# include analytics #} {% if helpers.environment !== 21 | "development" %} 22 | 28 | {% endif %} {# if your site's entire CSS comes in under 14kb, you may want 29 | to inline in the head #} {# include main.css if in development mode #} {% if 30 | helpers.environment === "development" %} 31 | {# css is injected with style-loader in dev mode, these style rules 32 | help to avoid a short flash of unstyled content while navigating #} 33 | 34 | {% else %} {# else, use the minified css file for production #} 35 | 36 | {% endif %} {# include scripts #} {% if helpers.environment === 37 | "development" %} 38 | 39 | {% else %} 40 | 41 | {% endif %} {# include social meta tags #} {% include 42 | "components/social-meta.njk" %} {# lastly include favicon, fonts, etc #} 43 | 44 | 45 | {# canonical #} 46 | 47 | 48 | 49 | 60 | Skip to content 61 | 62 |
66 | {# include header #} 67 | 68 | {% include "components/header.njk" %} 69 | 70 | {# include content #} 71 | {{ content | safe }} 72 | 73 | {# include footer #} {% include "components/footer.njk" %} 74 |
75 | 76 | {# include mobile nav #} {% include "components/mobile-nav.njk" %} 77 | 78 | 79 | -------------------------------------------------------------------------------- /site/_includes/layouts/pattern.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |
6 | 12 | 13 |

{{ title }}

14 | 15 |
16 |
17 | 18 |
19 | 20 |
21 |
22 | Last Updated 23 |
{{ published }}
24 |
25 | 26 |
27 | Category 28 | 29 |
{{ categoryName }}
30 |
31 |
32 | 33 | {% if relatedPatterns | length > 0 %} 34 | 40 | {% endif %} 41 | 42 |
43 | Propose a change 44 | 51 |
52 | 53 |
54 |
55 | 56 |
57 |
66 | 67 | 68 | 69 |
70 | {# {% if tags | length > 1 %} 71 |
72 | Tags 73 |
    74 | {% for tag in tags %} 75 | {% if tag !== 'pattern' %} 76 |
  • 77 | {{ tag | capitalize }} 78 |
  • 79 | {% endif %} 80 | {% endfor %} 81 |
82 |
83 | {% endif %} #} 84 |
85 | 86 |
87 | -------------------------------------------------------------------------------- /site/_includes/layouts/topic.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | 6 | 12 | 13 |

{{ title }}

14 | 15 |
16 | {{ content | safe }} 17 |
18 | 19 | {% patternListing patterns %} 20 | 21 |

No patterns found for this search term.

22 | 23 |
24 | {% for pattern in patterns %} 25 | {% patternPreview pattern %} 26 | {% endfor %} 27 |
28 | 29 |
30 | -------------------------------------------------------------------------------- /site/_includes/library.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |
6 |

Pattern Library

7 | 8 |
9 |
{{ content | safe }}
10 | 11 | 12 | 13 | Browse all patterns 14 | 15 | 16 |
17 | 18 | {% include "components/featured-pattern.njk" %} 19 | 20 |

Pattern Categories

21 | 22 |
    23 | {%- for topic in collections.topicsByTitle -%} 24 |
  • 25 |

    {{ topic.data.title }}

    26 | 27 |
    28 |
    {{ topic.templateContent | safe }}
    29 | 30 | See all 31 | {{topic.data.title}} 32 | 33 |
    34 | 35 |
    36 | {% for pattern in topic.data.patterns %} 37 | {% if loop.index0 < 3 %} 38 | {% patternPreview pattern %} 39 | {% endif %} 40 | {% endfor %} 41 |
    42 |
  • 43 | {%- endfor -%} 44 |
45 | 46 |

47 | View pattern index 48 |

49 |
50 | -------------------------------------------------------------------------------- /site/_patterns-meta/library.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Patterns 3 | layout: library.njk 4 | permalink: "library/" 5 | --- 6 | 7 | Every piece of software needs some degree of interface, content, and service design. This is no different in decentralization. What is different, however, is that decentralized design introduces concepts and scenarios that diverge from today’s dominant, centralized paradigms. These differences have the potential to make incorporating and solving decentralized design problems more challenging for experienced and novice developers alike. That’s why in an effort to help us all better understand how to build decentralized applications, we’ve created the design patterns in this library to be generalizable to protocols, applications, and the user interfaces of decentralized applications. The patterns themselves have been divided below into categories to further increase accessibility and comprehension. 8 | 9 | See something missing? [Propose a new pattern](https://github.com/simplysecure/dots-patterns/issues/new?assignees=&labels=pattern-submission&template=pattern-proposal-template.md&title=%5Bsubmission%5D) 10 | -------------------------------------------------------------------------------- /site/_patterns-meta/patterns-list-alphabetical.njk: -------------------------------------------------------------------------------- 1 | --- 2 | title: All Patterns 3 | layout: default 4 | permalink: "library/list/index.html" 5 | --- 6 | 7 |
8 | 9 | 15 | 16 |

All Patterns

17 | 18 |
19 |

20 | Every piece of software needs some amount of interface, content, and service design. This is no different in decentralization. What is different, however, is that decentralization introduces concepts and scenarios that are diverging from today’s dominant, centralized paradigms. These design patterns are generalizable to protocols, applications, and the user interfaces of decentralized applications.

21 | 22 |

See something missing? Please propose a new pattern.

23 |
24 | 25 | {% patternListing collections.patternsByTitle, 26 | 'alphabetical' %} 27 | 28 |

No patterns found for this search term.

29 | 38 | 39 |
40 | -------------------------------------------------------------------------------- /site/_patterns-meta/patterns-list-lastUpdated.njk: -------------------------------------------------------------------------------- 1 | --- 2 | title: All Patterns 3 | layout: default 4 | permalink: "library/list/last-updated/index.html" 5 | --- 6 | 7 |
8 | 9 | 15 | 16 |

All Patterns

17 | 18 |
19 |

20 | Every piece of software needs some amount of interface, content, and service design. This is no different in decentralization. What is different, however, is that decentralization introduces concepts and scenarios that are diverging from today’s dominant, centralized paradigms. These design patterns are generalizable to protocols, applications, and the user interfaces of decentralized applications.

21 | 22 |

See something missing? Please propose a new pattern.

23 |
24 | 25 | {% patternListing collections.patternsByLastUpdated, 26 | 'lastUpdated' %} 27 | 28 | 37 |

No patterns found for this search term.

38 | 39 |
40 | -------------------------------------------------------------------------------- /site/about.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | meta_title: About 4 | body_class: about 5 | title: About 6 | timeline: 7 | - description: Project scope and research design 8 | date: Summer 2019 9 | state: done 10 | - description: Workshops and interviews 11 | date: Winter 2019 12 | state: done 13 | - description: Publish research report 14 | date: Spring 2020 15 | state: done 16 | - description: Design pattern research 17 | date: Summer 2020 18 | state: done 19 | - description: Pattern library launch 20 | date: Winter 2020 21 | state: done 22 | - description: Shared decentralization glossary 23 | date: Spring 2021 24 | state: progress 25 | - description: Explanatory resources about decentralization 26 | date: Summer 2021 27 | state: progress 28 | - description: Comparative map of decentralization projects 29 | date: Fall 2021 30 | state: idle 31 | --- 32 | 33 |
34 |

About the project

35 |
36 |
37 | 38 |

39 | DOTS, short for Decentralization Off The Shelf, is a design project supporting practitioners in decentralization through interface, content, and service design. Our main resource is a library of tried-and-tested design patterns, along with a glossary of terms and a research report detailing the needs and gaps we see in the current ecosystem. 40 |

41 | 42 |

43 | DOTS is hosted by Simply Secure, a US-based 501(c)3 nonprofit supporting the usability of safety and privacy tools. We are actively seeking funding to assist in the development of additional critical resources in the decentralization space. 44 |

45 |

46 | 47 | Donate to keep this work going 48 | 49 |

50 | 51 |

Our Vision

52 | 53 |

54 | Our mission is to develop UX components and tools that developers and designers can use to build better user-facing applications backed by decentralized architectures. To achieve this goal, the DOTS team – with the input and assistance of the larger community – is working to create a library of decentralization resources, assets, and design patterns. 55 |

56 |

57 | Our pattern library is inspired by the architect and design theorist Christopher Alexander, co-author of “A Pattern Language.” Much like the way Alexander developed his patterns, our design patterns follow a structural template for clarity and convenience. Each pattern provides a design solution to a recurring design problem which we have observed and discovered in our hands-on research work. The library also includes examples, best practices, learning resources, and potential problems that may be encountered when using a given pattern in real-life development work. Ultimately, our design pattern library seeks to provide a roadmap to repeatable solutions and serve as a reminder of the countless capabilities of design. 58 |

59 |
60 | 61 |

About the team

62 | 63 |
64 |

65 | Eileen Wagner 66 |

67 |
    68 |
  • 69 | Designer 70 |
  • 71 |
  • Eileen advises teams and organizations on UX design and research. Her focus is on information architecture, content strategy, and interaction design -- or anything that helps people make sense of complex technologies. She works with numerous projects in decentralization and security, and enjoys facilitating relationships between the builders and users of technology. Her background is in analytic philosophy and mathematical logic, and she won’t stop talking about demoing barbershop music.
  • 72 |
73 |
74 | 75 |
76 |

77 | Karissa McKelvey 78 |

79 |
    80 |
  • 81 | Researcher 82 |
  • 83 |
  • Karissa researches technical architecture design and its impact on usability, safety, and resilience. Her contributions to decentralized applications are relied on by at-risk users across the world. Previously, she led user experience for dat and hypercore, a decentralized data sharing tool and peer-to-peer protocol. Her background is in political sociology and data science, and she loves making weird musical art that touches your funny bone.
  • 84 |
85 |
86 | 87 |
88 |

89 | Vincent Ahrend 90 |

91 |
    92 |
  • 93 | Web Engineer 94 |
  • 95 |
  • Vincent builds elegant and performant data-driven web experiences and the tooling required to maintain them. With a long-time passion for decentralized software, he has contributed to several related open source projects and is currently working on a brand-new peer-to-peer framework for the web. When in Berlin you can meet him at the bi-monthly p2p-berlin meeting. He has a background in cognitive science and a soft spot for discordianism.
  • 96 |
97 |
98 | 99 |
100 |

Ngọc Triệu

101 |
    102 |
  • 103 | Designer 104 |
  • 105 |
  • Ngọc sees design as an intervention to asymmetrical power relations. As a design researcher at Simply Secure, she imagines the futures of the world through lenses such as decoloniality and decentralization. Ngọc is passionate about user advocacy, co-creation, and equal access to knowledge(s). Her background is in design management, history, and cultures; and she loves doing kendo and taking a walk in the woods.
  • 106 |
107 |
108 | 109 |
110 |

Contributors

111 | 122 |
123 | 124 |
125 |

Advisors

126 | 138 |
139 | 140 |
141 |

Keep in touch

142 |

143 | We give talks and facilitate invite-only workshops, focus groups, and conference gatherings about decentralization! To get notified when we release new resources and get invited to events, sign up for our newsletter. 144 |

145 |

146 | 147 | Sign up for updates 148 | 149 |

150 |
151 | 152 | 153 |
154 |

Roadmap

155 |
156 | {% for item in timeline %} 157 |
158 | {% if item.state === 'progress' %} 159 |
160 | {% include "components/loading.njk" %} 161 |
162 | {% elif item.state === 'done' %} 163 |
164 | 165 |
166 | {% else %} 167 |
168 | {% endif %} 169 |
170 | {{item.description | safe }} 171 |
172 |
{{item.date}}
173 |
174 | {% endfor %} 175 |
176 |
177 | 178 |
179 |

Grants

180 | 190 |
191 |
192 | 193 |
194 | -------------------------------------------------------------------------------- /site/assembly.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: article 3 | meta_title: DOTS Monthly Assembly 4 | body_class: workshop 5 | title: DOTS Assembly 6 | --- 7 | 8 | # Join our monthly community assembly! 9 | 10 | We invite comments, questions, and new ideas regarding design patterns 11 | in decentralization and related technologies. 12 | 13 | Every second Wednesday of the month at 17:00 UTC / 19:00 Berlin / 10am California. 14 | 15 | 16 | Join us on Discord! 17 | 18 |
19 | 20 | ICS 21 | 22 |
23 | 24 | Google Calendar 25 | 26 | 27 | ## What to expect 28 | 29 | Our Assemblies are hour-long, participatory events where we set the agenda depending on the people in the room. Our focus will be on design aspects in decentralization, but we explicitly welcome non-designers and non-developers to join the conversation as well! 30 | 31 | - Hello & welcome! 32 | - Agenda hacking 33 | - Presentation and/or breakout sessions 34 | - Last 10 min: new pattern requests & proposals 35 | 36 | We will be hosting the event on [Discord](https://discord.gg/4uDSbWNPec), a platform that allows community members to communicate over chat, voice, and video. We also use [Miro](https://miro.com/) for collaborative whiteboarding. 37 | 38 | Design sprint illustration 42 | -------------------------------------------------------------------------------- /site/contribute.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | meta_title: Contribute 4 | body_class: contribute 5 | title: Contribute 6 | --- 7 |
12 |

13 | Join the conversation 14 |

15 | 16 |
17 |
18 |

19 | Decentralization Off The Shelf is a commons project that helps create tooling and resources by the community, for the community. We actively invite your participation in sharing your specific problems and challenges, as well as offering possible solutions for specific topics. 20 |

21 |
22 |
23 | 24 |
25 |
    26 |
  • 27 | Open Source Design Patterns 28 |
  • 29 |
  • Our design patterns live in a Github repository where you can join our discussion or propose a new pattern.
  • 30 |
  • 31 | Discuss and propose patterns 33 |
  • 34 |
35 | 36 |
    37 |
  • 38 | Community Chat 39 |
  • 40 |
  • We’d love to hear from you! Options to participate in community chat for day-to-day communications and tea time include:
  • 41 |
  • 42 | Matrix community 44 |
  • 45 |
  • 46 | Discord server 48 |
  • 49 |
50 | 51 |
    52 |
  • 53 | Monthly Community Assembly 54 |
  • 55 |
  • In our monthly assembly we invite comments, questions, and new ideas regarding design patterns 56 | in decentralization and related technologies. 57 |
  • 58 |
  • 59 | See details on monthly community assembly 60 |
  • 61 |
62 | 63 |
    64 |
  • 65 | Design Help for your Project 66 |
  • 67 |
  • We also give talks and facilitate invite-only workshops, focus groups, and conference gatherings about decentralization! For speaking engagements, workshops, grants, and partnerships, inquire through our email. To get notified when we release new resources and get invited to events, sign up for our newsletter. 68 |
  • 69 |
  • 70 | E-mail newsletter 72 |
  • 73 |
74 |
75 | 76 |
77 | 78 |
79 |
80 |
81 |

Donate

82 |

DOTS is a collective initiative working to identify needs, synthesize priorities, provide resources, and coordinate efforts to further the development and deployment of decentralized technologies. By addressing common obstacles to effective decentralization design, use, and adoption, we can increase the overall quantity and quality of decentralized applications. Given the size and importance of this project, we are actively seeking funding to help fuel the development of high-quality resources on a fast and efficient time frame. 83 |

84 | Donate to keep this work going 85 |
86 | 87 |
88 |

Governance

89 |

Our core values are mutual respect, open-mindedness, human-centric approaches, and inclusion. All design assets created are licensed under CC-BY. All code created is open source. The legal entity sponsoring DOTS is Simply Secure, a US 501(c)3. 90 |

91 | Learn about our governance structure 92 |
93 |
94 |
95 | -------------------------------------------------------------------------------- /site/glossary.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: article 3 | title: Glossary 4 | --- 5 | 6 | Decentralization introduces a wealth of new concepts, many of which are named and described in different ways across many projects. This causes confusion among early adopters as well as barriers in onboarding new users. We've attempted to capture many of decentralization concepts in this glossary. If you see a term missing or incorrect, please propose a change. 7 | -------------------------------------------------------------------------------- /site/governance.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: article 3 | meta_title: Governance 4 | body_class: governance 5 | title: Governance 6 | --- 7 | 8 | # Our Governance Structure 9 | 10 | ### Basics 11 | 12 | The project's Maintainers hold decision-making power while seeking to represent a balance of the views and the best interests of the community as a whole. 13 | 14 | DOTS creates resources and toolkits that help with usability and adoption of decentralized applications. 15 | 16 | Our core values are: mutual respect, open-mindedness, human-centric approaches, inclusion. 17 | 18 | All design assets created are licensed under CC-BY. All code created is open source. The legal entity sponsoring DOTS is Simply Secure, a US 501\(c\)3. 19 | 20 | ### Participants 21 | 22 | Participation is open to anyone who wants to join. 23 | 24 | The Maintainers can remove misbehaving participants at will for the sake of the common good. We follow Simply Secure's [Code of Conduct](https://simplysecure.org/coc/). 25 | 26 | Participants involved in the development of open source resources are Contributors, participants involved in strategy and fundraising are Advisors. 27 | 28 | In the event that one of the Maintainers is unable or unwilling to continue leadership, they may appoint a new Maintainer or choose to alter the governance structure entirely. 29 | 30 | ### Policy 31 | 32 | The Maintainers set the community's policies and make decisions for the community, taking reasonable account of input from other community participants. 33 | 34 | The Maintainers are responsible for implementing—or delegating implementation of—policies and other decisions. 35 | 36 | If Contributors are not happy with the Maintainers' leadership, they are free to voice their concerns directly. An open community forum will be held at least once a year, (but likely more often), where input will be solicited. 37 | 38 | ### Process 39 | 40 | Access to accounts sit with the Maintainers, and can be shared with Contributors and Advisors as needed. 41 | 42 | The Maintainers manage all funds; distribution of funds is made transparent on Github and Open Collective. 43 | 44 | Anyone is free to discuss and debate community policies, practices, and culture. 45 | 46 | ### Evolution 47 | 48 | The Maintainers can change the governance structure at will. 49 | -------------------------------------------------------------------------------- /site/includes/components/loading.njk: -------------------------------------------------------------------------------- 1 |
2 | 4 | 5 | 8 | 9 | 10 | 13 | 14 | 15 | 18 | 19 | 20 |
21 | -------------------------------------------------------------------------------- /site/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | meta_description: ... 4 | body_class: home 5 | title: Decentralization, off the shelf. 6 | --- 7 | 8 | 9 | 10 |
11 |

Decen­trali­zation, off the shelf.

12 | 13 |
14 | 15 |
16 |

17 | Decentralization allows for the existence of different voices in a world of increasingly asymmetric power relations. Among other things, it enables alternative technologies to challenge traditional models: where governments and corporate control are causing harm, decentralized technologies have the potential to bring about autonomy, resilience, and equity. 18 |

19 | 20 |

21 | Unfortunately, a significant gap exists between the protocols that currently define the decentralization space and the applications that most users want to adopt. That’s why the mission of Decentralization Off The Shelf (or “DOTS”) is to develop UX components and tools that developers and designers can use to build better user-facing applications backed by decentralized architectures, off the shelf. To achieve this goal, the DOTS team – with the invaluable input and assistance of the larger community – is working to create a library of decentralization resources, assets, and design patterns. 22 |

23 | 24 | 29 |
30 | 31 | 36 | 37 |
38 | 39 |
40 | {% include "components/featured-pattern.njk" %} 41 |
42 | 43 |
44 | 45 |
46 |

Research Report

47 | 48 |

49 | Through a series of interviews and focus groups with technology designers and builders, we have identified seven key areas where decentralized projects can improve their own practice, where further targeted research is needed, and where funders can help foster shared innovation. These areas, and the rest of our initial research findings, are discussed in our 2020 report, Decentralization Off The Shelf: 7 Maxims. 50 |

51 |
52 | 53 | 58 | 59 |
60 | 61 |
62 | 63 |
64 |

Monthly Community Assembly

65 | 66 |

67 | Our Assemblies are hour-long, participatory events where we set the agenda depending on the people in the room. Our focus will be on design aspects in decentralization, but we explicitly welcome non-designers and non-developers to join the conversation as well! 68 |

69 |
70 | 71 | 76 | 77 |
78 | 79 |
80 |
81 | 82 |

Need design help?

83 | 84 |

85 | At DOTS, we’re looking for partners and collaborators to bring their design challenges to us so that we can workshop new user experience and architecture patterns. By addressing the specific needs and challenges of your project, we can also learn valuable lessons that can be applied to the community as a whole. As a result, the design work we do together will ultimately feed into the production of our pattern library. 86 |

87 |
88 | 89 |
90 | Work with us 91 |
92 | 93 |
94 | 95 |
96 | -------------------------------------------------------------------------------- /site/library: -------------------------------------------------------------------------------- 1 | ../dots-patterns/patterns -------------------------------------------------------------------------------- /site/projects/web-monetization/gftw-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/gftw-hero.png -------------------------------------------------------------------------------- /site/projects/web-monetization/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/image_1.png -------------------------------------------------------------------------------- /site/projects/web-monetization/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/image_2.png -------------------------------------------------------------------------------- /site/projects/web-monetization/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/image_3.png -------------------------------------------------------------------------------- /site/projects/web-monetization/image_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/image_4.png -------------------------------------------------------------------------------- /site/projects/web-monetization/image_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/image_5.png -------------------------------------------------------------------------------- /site/projects/web-monetization/image_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/image_6.png -------------------------------------------------------------------------------- /site/projects/web-monetization/image_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/site/projects/web-monetization/image_7.png -------------------------------------------------------------------------------- /site/sitemap.njk: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: sitemap.xml 3 | hidden: true 4 | --- 5 | 6 | 7 | {%- for page in collections.all %} 8 | {%- if not page.data.hidden %} 9 | 10 | {{ site.url }}{{ page.url | url }} 11 | {{ page.date | htmlDateDisplay }} 12 | 13 | {%- endif %} 14 | {%- endfor %} 15 | 16 | -------------------------------------------------------------------------------- /site/support-us.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | meta_title: Donate 4 | body_class: donate 5 | title: Support us 6 | --- 7 | 8 | 9 |
10 |
11 |

Support us

12 | 13 |

Decentralization Off The Shelf is hosted by Simply Secure, a US-based 501(c)3 supporting the usability of safety and privacy tools. Donations are tax-deductible in the United States.

14 | 15 |

Your donation will help our ongoing work in creating tooling and resources for the decentralization community. See our roadmap and Github issues.

16 | 17 |

We currently accept donations by Coinbase, PayPal, Transferwise, OpenCollective and via checks drawn on US dollars.

18 | 19 |
20 | Coinbase 21 | OpenCollective 22 | PayPal 23 |
24 | 25 |

26 | If you use Coinbase or PayPal, please reference “DOTS” to make sure your donation goes towards this project. 27 |

28 |
29 | 30 |
31 | -------------------------------------------------------------------------------- /site/topics: -------------------------------------------------------------------------------- 1 | ../dots-patterns/topics -------------------------------------------------------------------------------- /site/virtual-workshop-amarillo.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: article 3 | meta_title: DOTS Designers Workshop 4 | body_class: workshop 5 | title: Designer Workshop (Amarillo) 6 | --- 7 | 8 | # Invitation 9 | 10 | ## Join our virtual design workshop this spring! 11 | 12 | This spring, we invite you to collaborate with other designers experienced in decentralized technologies. 13 | 14 | This time, we will have a smaller group (maximum 8) designers. We will focus on 15 | how identity (me/us) works in decentralized contexts, and how we can envision 16 | a new way to relate to each other and ourselves in these new digital spaces. 17 | 18 | If you are interested in attending, please send an email to 19 | [mailto:team@decentpatterns.xyz](team@decentpatterns.xyz) with your name, email address, and how you found out 20 | about this workshop. 21 | 22 | Feel free to prepare to share any work in progress or old designs that never made it to the implementation phase. 23 | 24 | ### Topics we will cover 25 | 26 |
27 | 28 | - Onboarding 29 | - What are the largest pain points for your users? 30 | - What are the problems for onboarding to decentralized identity tech? 31 | - What are the primary trust issues and how is that reflected in our messaging? 32 | - Agency & identity 33 | - Who else knows who I am? Can I be anonymous? 34 | - What happens when I lose my password? 35 | - Can I use multiple devices? Can I share a device with others? 36 | - Security & authentication 37 | - Who can see what, and for how long? 38 | - Why can't certain data be deleted? 39 | - What happens if a device is lost? 40 | - Who can I call if I run into a problem? 41 | 42 |
43 | 44 | By participating in this workshop series, you get to: 45 | 46 | - Meet other designers in the decentralization space 47 | - Have your current work highlighted or cited as part of a research summary and the pattern library 48 | - \$100 compensation for each person who attends, either directly to you or donated to the non-profit organization of your choice 49 | 50 | Design sprint illustration 54 | 55 | Our workshop will take place on the internet on the following date: 56 | 57 | - Wednesday, Feb 24 9am PT / 6pm CET for 2 hours 58 | 59 | This workshop series will be facilitated by Ngọc Triệu and Karissa McKelvey. 60 | 61 | If you are interested in attending, please send an email to team@decentpatterns.xyz with your name, email address, and how you found out about this workshop. 62 | 63 | Thank you! 64 | -------------------------------------------------------------------------------- /site/virtual-workshop-cyan.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: article 3 | meta_title: DOTS Workshop Invitation 4 | body_class: workshop 5 | title: Virtual Workshop (Cyan) 6 | --- 7 | 8 | # Invitation 9 | 10 | ## Join our virtual design workshop this fall! 11 | 12 | Decentralization is full of hard UX problems waiting for talented designers to tackle. This fall, we invite you to collaborate with a community of designers interested in building a library of design patterns for decentralization. 13 | 14 | 15 | Register to attend our design workshop! 16 | 17 | 18 | ### Topics we will cover 19 | 20 |
21 | 22 | - Mental models of decentralization and networking in general 23 | - What data is stored where? 24 | - Where are the boundaries between apps, archives, mounts? 25 | - Relationship between protocols and clients 26 | - What is a protocol, what is a client? 27 | - What does it mean for a protocol to have multiple clients? (and vice versa) 28 | - Agency & identity 29 | - Who else knows who I am? Can I be anonymous? 30 | - What happens when I lose my password? 31 | - Can I use multiple devices? Can I share a device with others? 32 | - Security & authentication 33 | - Who can see what, and for how long? 34 | - Why can't certain data be deleted? 35 | - What happens if a device is lost? 36 | - Online status & synchronization & availability 37 | - Does this network require the Internet to work? 38 | - What does it mean to optionally use the Internet? 39 | - Will my content be available at all times? How reliable is this service? 40 | - Licensing & intellectual property 41 | - What does it mean to have other people's data on my machine? 42 | - Governance & content moderation 43 | - Who has control over shared content and infrastructure? 44 | - How can I block someone? 45 | - Who can I call if I run into a problem? 46 | 47 |
48 | 49 | There will be two parts to this workshop series. The first one introduces the existing design patterns and use cases. The second one takes the existing design patterns further and provides more structure for the corresponding use cases. View our first set of design patterns [here on GitHub](https://github.com/simplysecure/dots-patterns/). 50 | 51 | By participating in this workshop series, you get to: 52 | 53 | - learn more about decentralization technologies; 54 | - contribute to a field driven by empowerment, resilience, and sovereignty; 55 | - develop completely new and ground-breaking designs; 56 | - meet other like-minded folks in this area. 57 | 58 | Design sprint illustration 62 | 63 | Our workshops will take place on the internet on the following dates: 64 | 65 | - Part 1: Wednesday, Sep 23 12pm ET / 6pm CET / 9am PT for 2.5 hours and 66 | - Part 2: Wednesday, Sep 30 12pm ET / 6pm CET / 9am PT for 2.5 hours 67 | 68 | Not a designer? We'd still like to invite you to participate. Sign up and we will be in touch! 69 | 70 | 71 | Register to attend our design workshop! 72 | 73 | 74 | Participation is free-of-charge. 75 | 76 | This workshop series will be facilitated by Lola Oyelayo-Pearson, Eileen Wagner, and Karissa McKelvey. 77 | -------------------------------------------------------------------------------- /site/vision.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: article 3 | title: Vision & Mission 4 | --- 5 | 6 | # Vision & Mission 7 | 8 | Our mission is to develop UX components and tools that developers and designers can use to build better user-facing applications backed by decentralized architectures. We do this by producing a library of resources, assets, and design patterns with the help and input of the larger community. 9 | 10 | Our pattern library is inspired by the renowned architect and design theorist Alexander Christopher, author of “A Pattern Language”. Much like the way Christopher developed his patterns, our design patterns follow a structural template for clarity and convenience. Each pattern addresses a recurring design problem which we have observed and discovered in our hands-on research work, then comes the design solution to that problem. In addition, we also include examples, best practices, potential problems when using each pattern in real-life development work, take-aways and learning resources. Ultimately, our design pattern library aims to serve not only as the general repeatable solutions but also a reminder of what design is capable of. 11 | 12 | ## Why decentralization? 13 | 14 | Decentralization allows the coexistence of different opinions and voices in a world of asymmetric power relations. Decentralized technologies, in particular, enable alternative applications that challenge the traditional models: where government and corporate control are causing harm, decentralized technologies have the potential to bring about autonomy, resilience, and equity. 15 | 16 | ## Why Design? 17 | 18 | We believe that a human-centered design approach to decentralized technologies will ensure accessibility and usability for a better world where technologies bring about positive change to humans and their environments. 19 | 20 | One of the main challenges for decentralized technologies is the lack of adaptation. There are far too many unfamiliar and technical concepts which often lead to confusion. Design allows for the simplification of these terms and helps make sense of things in a user-friendly manner. By combining a variety of design research methodologies and design principles, including iterative testing and feedback, we are able to obtain an understanding of users, their existing social practices, habits, and mental models. In any given step, users’ perspectives are always prioritized and emphasized. This empowers new ideas and allows us to compile best practices for decentralization design. 21 | 22 | ## Why collaborative? 23 | 24 | The cornerstone of Decentralization Off The Shelf lies in collaboration. Our vision for a co-design process is driven by our experience in coaching and working alongside more than 60 open-source projects for the past five years. We learnt that for ever-evolving technologies to stay relevant, it takes a lot of iterations and inputs from designers and developers alike. Going forward, we hope to build a common space for all those who are fascinated by the possibility of decentralized technologies to come together and co-create. 25 | 26 | Join the conversation and start contributing [here](/contribute). 27 | -------------------------------------------------------------------------------- /site/work-with-us.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | meta_title: Work with us 4 | meta_description: Work with us page description 5 | body_class: work-with-us 6 | title: Work with us 7 | --- 8 | 9 |
14 |

15 | We support projects working in decentralization with UX/UI and architecture 16 | design. 17 |

18 | 19 |
20 |
21 | Design sprint illustration 25 |

Design Sprints

26 |

27 | We offer remote design support, ranging from 3-hour workshops to 28 | week-long sprints. Topics may include (but are not limited to): 29 |

30 |
    31 |
  • Developing a UX/UI pattern for a particular workflow
  • 32 |
  • 33 | Workshopping terminology, explanation, or illustrations for onboarding 34 |
  • 35 |
  • Designing a feature from the ground up
  • 36 |
  • Beginning user research and testing
  • 37 |
  • Reviewing of current designs based on best practices
  • 38 |
39 |
40 |
41 | Architecture sprint illustration 45 |

Architecture Sprints

46 |
    47 |
  • 48 | Architecture review, resulting in a report on usability implications 49 |
  • 50 |
  • Developer-facing documentation
  • 51 |
  • Is your architecture ready for a particular design?
  • 52 |
  • 53 | What architecture adjustments could help reach your design goals? 54 |
  • 55 |
  • 56 | We build an example application with your protocol or developer-facing 57 | library, and give feedback to your team. 58 |
  • 59 |
60 |
61 |
62 | Informational interview illustration 66 |

Informational Interview

67 |

68 | Are you working on a decentralized protocol or application, and would 69 | like to share your thoughts? We are putting together practical 70 | guidelines for decentralized applications, and are interested in hearing 71 | your perspective. Our research focuses on: 72 |

73 |
    74 |
  • What use cases are decentralized applications being applied to?
  • 75 |
  • 76 | What user experience pattern does your application use for X, Y, Z 77 | feature? 78 |
  • 79 |
  • 80 | What protocol or library do you use for an application with some given 81 | constraints? 82 |
  • 83 |
  • 84 | What are the trade-offs in approaches for key user interactions such 85 | as multi-device, backup, and discoverability? 86 |
  • 87 |
  • Who is currently working on X, Y, Z topic?
  • 88 |
89 |
90 |
91 | 92 |
93 | Get in touch 94 |
95 | 96 |
97 |

Projects we've worked with

98 | 99 | 105 | 111 | 112 |
113 |
114 | -------------------------------------------------------------------------------- /styles/base/_all.scss: -------------------------------------------------------------------------------- 1 | //========== Import all base partials ==========// 2 | 3 | @import "utilities"; 4 | @import "global"; 5 | @import "links"; 6 | @import "typography"; 7 | @import "fonts"; 8 | -------------------------------------------------------------------------------- /styles/base/_fonts.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Inter"; 3 | font-style: normal; 4 | font-weight: 100; 5 | font-display: swap; 6 | src: url(/fonts/Inter-Thin.woff2?v=3.12) format("woff2"), 7 | url(/fonts/Inter-Thin.woff?v=3.12) format("woff"); 8 | } 9 | @font-face { 10 | font-family: "Inter"; 11 | font-style: italic; 12 | font-weight: 100; 13 | font-display: swap; 14 | src: url(/fonts/Inter-ThinItalic.woff2?v=3.12) format("woff2"), 15 | url(/fonts/Inter-ThinItalic.woff?v=3.12) format("woff"); 16 | } 17 | 18 | @font-face { 19 | font-family: "Inter"; 20 | font-style: normal; 21 | font-weight: 200; 22 | font-display: swap; 23 | src: url(/fonts/Inter-ExtraLight.woff2?v=3.12) format("woff2"), 24 | url(/fonts/Inter-ExtraLight.woff?v=3.12) format("woff"); 25 | } 26 | @font-face { 27 | font-family: "Inter"; 28 | font-style: italic; 29 | font-weight: 200; 30 | font-display: swap; 31 | src: url(/fonts/Inter-ExtraLightItalic.woff2?v=3.12) format("woff2"), 32 | url(/fonts/Inter-ExtraLightItalic.woff?v=3.12) format("woff"); 33 | } 34 | 35 | @font-face { 36 | font-family: "Inter"; 37 | font-style: normal; 38 | font-weight: 300; 39 | font-display: swap; 40 | src: url(/fonts/Inter-Light.woff2?v=3.12) format("woff2"), 41 | url(/fonts/Inter-Light.woff?v=3.12) format("woff"); 42 | } 43 | @font-face { 44 | font-family: "Inter"; 45 | font-style: italic; 46 | font-weight: 300; 47 | font-display: swap; 48 | src: url(/fonts/Inter-LightItalic.woff2?v=3.12) format("woff2"), 49 | url(/fonts/Inter-LightItalic.woff?v=3.12) format("woff"); 50 | } 51 | 52 | @font-face { 53 | font-family: "Inter"; 54 | font-style: normal; 55 | font-weight: 400; 56 | font-display: swap; 57 | src: url(/fonts/Inter-Regular.woff2?v=3.12) format("woff2"), 58 | url(/fonts/Inter-Regular.woff?v=3.12) format("woff"); 59 | } 60 | @font-face { 61 | font-family: "Inter"; 62 | font-style: italic; 63 | font-weight: 400; 64 | font-display: swap; 65 | src: url(/fonts/Inter-Italic.woff2?v=3.12) format("woff2"), 66 | url(/fonts/Inter-Italic.woff?v=3.12) format("woff"); 67 | } 68 | 69 | @font-face { 70 | font-family: "Inter"; 71 | font-style: normal; 72 | font-weight: 500; 73 | font-display: swap; 74 | src: url(/fonts/Inter-Medium.woff2?v=3.12) format("woff2"), 75 | url(/fonts/Inter-Medium.woff?v=3.12) format("woff"); 76 | } 77 | @font-face { 78 | font-family: "Inter"; 79 | font-style: italic; 80 | font-weight: 500; 81 | font-display: swap; 82 | src: url(/fonts/Inter-MediumItalic.woff2?v=3.12) format("woff2"), 83 | url(/fonts/Inter-MediumItalic.woff?v=3.12) format("woff"); 84 | } 85 | 86 | @font-face { 87 | font-family: "Inter"; 88 | font-style: normal; 89 | font-weight: 600; 90 | font-display: swap; 91 | src: url(/fonts/Inter-SemiBold.woff2?v=3.12) format("woff2"), 92 | url(/fonts/Inter-SemiBold.woff?v=3.12) format("woff"); 93 | } 94 | @font-face { 95 | font-family: "Inter"; 96 | font-style: italic; 97 | font-weight: 600; 98 | font-display: swap; 99 | src: url(/fonts/Inter-SemiBoldItalic.woff2?v=3.12) format("woff2"), 100 | url(/fonts/Inter-SemiBoldItalic.woff?v=3.12) format("woff"); 101 | } 102 | 103 | @font-face { 104 | font-family: "Inter"; 105 | font-style: normal; 106 | font-weight: 700; 107 | font-display: swap; 108 | src: url(/fonts/Inter-Bold.woff2?v=3.12) format("woff2"), 109 | url(/fonts/Inter-Bold.woff?v=3.12) format("woff"); 110 | } 111 | @font-face { 112 | font-family: "Inter"; 113 | font-style: italic; 114 | font-weight: 700; 115 | font-display: swap; 116 | src: url(/fonts/Inter-BoldItalic.woff2?v=3.12) format("woff2"), 117 | url(/fonts/Inter-BoldItalic.woff?v=3.12) format("woff"); 118 | } 119 | 120 | @font-face { 121 | font-family: "Inter"; 122 | font-style: normal; 123 | font-weight: 800; 124 | font-display: swap; 125 | src: url(/fonts/Inter-ExtraBold.woff2?v=3.12) format("woff2"), 126 | url(/fonts/Inter-ExtraBold.woff?v=3.12) format("woff"); 127 | } 128 | @font-face { 129 | font-family: "Inter"; 130 | font-style: italic; 131 | font-weight: 800; 132 | font-display: swap; 133 | src: url(/fonts/Inter-ExtraBoldItalic.woff2?v=3.12) format("woff2"), 134 | url(/fonts/Inter-ExtraBoldItalic.woff?v=3.12) format("woff"); 135 | } 136 | 137 | @font-face { 138 | font-family: "Inter"; 139 | font-style: normal; 140 | font-weight: 900; 141 | font-display: swap; 142 | src: url(/fonts/Inter-Black.woff2?v=3.12) format("woff2"), 143 | url(/fonts/Inter-Black.woff?v=3.12) format("woff"); 144 | } 145 | @font-face { 146 | font-family: "Inter"; 147 | font-style: italic; 148 | font-weight: 900; 149 | font-display: swap; 150 | src: url(/fonts/Inter-BlackItalic.woff2?v=3.12) format("woff2"), 151 | url(/fonts/Inter-BlackItalic.woff?v=3.12) format("woff"); 152 | } 153 | 154 | @font-face { 155 | font-family: "Space Grotesk"; 156 | font-style: normal; 157 | font-weight: 300; 158 | font-display: swap; 159 | src: url(/fonts/SpaceGrotesk-Light.woff2) format("woff2"), 160 | url(/fonts/SpaceGrotesk-Light.woff) format("woff"); 161 | } 162 | 163 | @font-face { 164 | font-family: "Space Grotesk"; 165 | font-style: normal; 166 | font-weight: 400; 167 | font-display: swap; 168 | src: url(/fonts/SpaceGrotesk-Regular.woff2) format("woff2"), 169 | url(/fonts/SpaceGrotesk-Regular.woff) format("woff"); 170 | } 171 | 172 | @font-face { 173 | font-family: "Space Grotesk"; 174 | font-style: normal; 175 | font-weight: 500; 176 | font-display: swap; 177 | src: url(/fonts/SpaceGrotesk-Medium.woff2) format("woff2"), 178 | url(/fonts/SpaceGrotesk-Medium.woff) format("woff"); 179 | } 180 | 181 | @font-face { 182 | font-family: "Space Grotesk"; 183 | font-style: normal; 184 | font-weight: 600; 185 | font-display: swap; 186 | src: url(/fonts/SpaceGrotesk-SemiBold.woff2) format("woff2"), 187 | url(/fonts/SpaceGrotesk-SemiBold.woff) format("woff"); 188 | } 189 | 190 | @font-face { 191 | font-family: "Space Grotesk"; 192 | font-style: normal; 193 | font-weight: 700; 194 | font-display: swap; 195 | src: url(/fonts/SpaceGrotesk-Bold.woff2) format("woff2"), 196 | url(/fonts/SpaceGrotesk-Bold.woff) format("woff"); 197 | } 198 | -------------------------------------------------------------------------------- /styles/base/_global.scss: -------------------------------------------------------------------------------- 1 | //========== Globals ==========// 2 | html { 3 | background-color: theme("colors.background"); 4 | font-size: 18px; 5 | } 6 | 7 | body { 8 | line-height: 1.78; // 18px * 1.78 = 32px (vertical spacing) 9 | } 10 | -------------------------------------------------------------------------------- /styles/base/_links.scss: -------------------------------------------------------------------------------- 1 | //========== Links ==========// 2 | 3 | a { 4 | @apply no-underline transition-all duration-300 ease-out; 5 | 6 | &:not([class]) { 7 | border-bottom-width: 1px; 8 | border-color: #ecf0f8; 9 | 10 | &:hover { 11 | @apply text-highlight border-black; 12 | } 13 | } 14 | } 15 | 16 | .markdown { 17 | .header-anchor { 18 | @apply text-dark transition-all duration-300 ease-out; 19 | } 20 | 21 | h1, 22 | h2, 23 | h3, 24 | h4 { 25 | &:hover .header-anchor { 26 | @apply text-white; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /styles/base/_typography.scss: -------------------------------------------------------------------------------- 1 | // //========== Typography ==========// 2 | 3 | // headings 4 | h1, 5 | h2, 6 | h3, 7 | h4 { 8 | @apply font-serif break-words; 9 | -moz-hyphens: auto; 10 | hyphens: auto; 11 | margin: 3rem 0 1.38rem; 12 | } 13 | 14 | h2, 15 | h3, 16 | h4 { 17 | @apply text-white; 18 | } 19 | 20 | h1 { 21 | @apply text-xl text-highlight mt-0; 22 | 23 | @screen sm { 24 | @apply text-2xl my-16; 25 | } 26 | } 27 | 28 | h2 { 29 | @apply text-lg font-light my-6; 30 | 31 | @screen sm { 32 | @apply text-xl my-12; 33 | } 34 | } 35 | 36 | h3 { 37 | @apply text-lg font-light my-8; 38 | 39 | @screen md { 40 | @apply text-lg my-10; 41 | } 42 | } 43 | 44 | h4 { 45 | @apply text-base my-8; 46 | } 47 | 48 | h5 { 49 | @apply text-base text-medium my-8; 50 | } 51 | 52 | p, 53 | ul, 54 | ol { 55 | @apply text-base text-white; 56 | } 57 | 58 | // Apply spacing between consecutive content blocks 59 | p + p, 60 | p + ul, 61 | p + ol, 62 | ul + p, 63 | ol + p { 64 | @apply mt-6; 65 | 66 | @screen lg { 67 | @apply mt-12; 68 | } 69 | } 70 | 71 | .content { 72 | p, 73 | ul, 74 | ol { 75 | @apply max-w-xl; 76 | } 77 | 78 | ul, 79 | ol { 80 | @apply text-body text-base pl-6; 81 | 82 | @screen md { 83 | @apply pl-0; 84 | } 85 | 86 | li + li, 87 | ul + li, 88 | ol + li { 89 | @apply mt-4; 90 | } 91 | 92 | ul, 93 | ol { 94 | @apply mt-4 pl-8 mb-0; 95 | } 96 | } 97 | } 98 | 99 | ol { 100 | @apply list-decimal; 101 | } 102 | 103 | // the .markdown-class is applied to content, which is rendered from a markdown 104 | // source file 105 | 106 | .content.markdown { 107 | @apply max-w-4xl; 108 | 109 | p, 110 | ul, 111 | ol { 112 | // increases readbility 113 | @apply text-base; 114 | } 115 | 116 | // larger font-size needs more space around the paragraphs 117 | p + p { 118 | @apply mt-8; 119 | } 120 | 121 | // markdown header styles 122 | 123 | h1 { 124 | // hiding the header-anchor on h1 elements specifically because they are 125 | // quite obtrusive at that font-size 126 | 127 | .header-anchor { 128 | display: none; 129 | } 130 | } 131 | 132 | // markdown list styles 133 | 134 | ul, 135 | ol { 136 | @apply list-outside; 137 | 138 | @screen md { 139 | @apply pl-16; 140 | } 141 | } 142 | 143 | ul { 144 | @apply list-disc; 145 | } 146 | 147 | // quote styles 148 | 149 | blockquote { 150 | @apply my-12; 151 | 152 | // @screen md { 153 | // @apply my-16; 154 | // } 155 | 156 | p { 157 | @apply text-base pl-8 border-l-2 border-dark; 158 | } 159 | } 160 | 161 | // this horizontal ruler is inserted before the footnotes, which are extracted 162 | // from the main markdown document 163 | 164 | hr.footnotes-sep { 165 | @apply mb-16; 166 | @screen lg { 167 | margin-top: -2rem; 168 | } 169 | } 170 | 171 | .footnote-item { 172 | // make sure that links in footnotes do have line breaks 173 | word-break: break-all; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /styles/base/_utilities.scss: -------------------------------------------------------------------------------- 1 | //========== Utility classes ==========// 2 | 3 | // subtle 'fade in' to the lazyloaded image 4 | [data-lazy] { 5 | @apply opacity-0 w-full; 6 | transition: opacity 0.25s ease-in; 7 | min-height: 120px; 8 | } 9 | 10 | .loaded { 11 | @apply opacity-100; 12 | } 13 | 14 | // Reset body visibility changed in default.njk style tag, which is loaded 15 | // for dev environment to avoid flash of unstyled content on navigation 16 | body { 17 | visibility: initial; 18 | } 19 | -------------------------------------------------------------------------------- /styles/components/_all.scss: -------------------------------------------------------------------------------- 1 | //========== Import all component partials ==========// 2 | 3 | @import "mobile-nav"; 4 | @import "buttons"; 5 | @import "form"; 6 | @import "links"; 7 | @import "_header"; 8 | @import "_footer"; 9 | @import "_main"; 10 | 11 | @import "donate"; 12 | @import "examples"; 13 | @import "featured-pattern"; 14 | @import "offers"; 15 | @import "pattern-listing"; 16 | @import "pattern-main"; 17 | @import "pattern-preview"; 18 | @import "pattern"; 19 | @import "report"; 20 | @import "timeline"; 21 | @import "projects"; 22 | -------------------------------------------------------------------------------- /styles/components/_buttons.scss: -------------------------------------------------------------------------------- 1 | //========== Buttons ==========// 2 | // a.button, 3 | // .buttons a { 4 | // display: inline-block; 5 | // @apply border-2 border-white py-1 px-2 rounded-lg text-highlight; 6 | // font-weight: bold; 7 | // border-width: 1px; 8 | 9 | // @screen md { 10 | // @apply py-2 px-4; 11 | // } 12 | // } 13 | 14 | // .buttons { 15 | // @apply my-6; 16 | 17 | // a { 18 | // @apply mr-1; 19 | 20 | // @screen md { 21 | // @apply mr-2; 22 | // } 23 | // } 24 | // } 25 | 26 | .button-group { 27 | @apply flex flex-row; 28 | 29 | .btn { 30 | @apply rounded-none border-r-0 mr-0; 31 | margin-right: 0; 32 | } 33 | 34 | .btn:first-child { 35 | border-top-left-radius: 0.25rem; 36 | border-bottom-left-radius: 0.25rem; 37 | } 38 | 39 | .btn:last-child { 40 | @apply border; 41 | border-top-right-radius: 0.25rem; 42 | border-bottom-right-radius: 0.25rem; 43 | } 44 | } 45 | 46 | a.btn { 47 | @apply rounded font-bold p-4 text-center; 48 | font-size: 14px; 49 | line-height: 16px; 50 | min-width: 10rem; 51 | display: inline-table; 52 | margin: 10px 1rem 10px 0; 53 | 54 | @apply border border-light text-light bg-transparent; 55 | 56 | &:hover { 57 | @apply bg-dark; 58 | } 59 | 60 | &.btn-active { 61 | @apply bg-light text-dark border-light; 62 | } 63 | 64 | &.btn-primary { 65 | @apply border-0 bg-secondary text-dark; 66 | 67 | &:hover { 68 | background-color: #65fbe5; 69 | } 70 | } 71 | 72 | &.btn-highlight { 73 | @apply border-0 bg-highlight text-dark; 74 | 75 | } 76 | 77 | 78 | &.btn-secondary { 79 | @apply border-0 bg-light text-dark; 80 | 81 | &:hover { 82 | @apply bg-white; 83 | } 84 | } 85 | 86 | &.btn-sm { 87 | @apply p-2; 88 | font-size: 12px; 89 | min-width: 7rem; 90 | 91 | &.btn-pill { 92 | @apply py-1 px-2; 93 | } 94 | } 95 | 96 | &.btn-lg { 97 | min-width: 12rem; 98 | @apply p-6; 99 | } 100 | 101 | &.btn-pill { 102 | @apply rounded-full py-3 px-6; 103 | 104 | min-width: 4rem; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /styles/components/_footer.scss: -------------------------------------------------------------------------------- 1 | footer { 2 | @apply max-w-3xl; 3 | 4 | > hr { 5 | @apply w-24 mb-16 border-highlight; 6 | } 7 | 8 | a { 9 | @apply border-medium; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /styles/components/_form.scss: -------------------------------------------------------------------------------- 1 | //========== Form ==========// 2 | 3 | .form { 4 | .row { 5 | @apply mb-6; 6 | 7 | label { 8 | @apply block mb-1 text-gray-800; 9 | 10 | &:after { 11 | @apply text-caption text-gray-600; 12 | } 13 | } 14 | 15 | &.required { 16 | label:after { 17 | content: "\00a0(required)"; 18 | } 19 | } 20 | 21 | &:not(.required) { 22 | label:after { 23 | content: "\00a0(optional)"; 24 | } 25 | } 26 | } 27 | 28 | .input, 29 | .textarea { 30 | @apply border border-gray-200 rounded p-3 w-full transition-all duration-300 ease-out; 31 | 32 | &:focus { 33 | @apply border-pink-500 outline-none; 34 | } 35 | } 36 | 37 | .input { 38 | @apply h-12; 39 | } 40 | 41 | .textarea { 42 | @apply h-24; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /styles/components/_header.scss: -------------------------------------------------------------------------------- 1 | .company-logo-link { 2 | @apply text-white hidden w-8; 3 | 4 | @screen lg { 5 | @apply block mr-24; 6 | } 7 | 8 | @screen xl { 9 | @apply w-16; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /styles/components/_main.scss: -------------------------------------------------------------------------------- 1 | // 'container' helper class 2 | header, 3 | main, 4 | footer { 5 | @apply px-4; 6 | 7 | @screen sm { 8 | @apply px-6; 9 | } 10 | 11 | @screen md { 12 | @apply px-6 mx-12; 13 | } 14 | 15 | @screen xl { 16 | @apply mx-32; 17 | } 18 | } 19 | 20 | main { 21 | @apply py-8 mt-8; 22 | 23 | @screen md { 24 | @apply mt-0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /styles/components/_mobile-nav.scss: -------------------------------------------------------------------------------- 1 | //========== Mobile Navigation ==========// 2 | 3 | $transition-easing: cubic-bezier(0.77, 0, 0.175, 1); 4 | $transition-length: 0.25s; 5 | 6 | // menu toggle button 7 | .mobile-nav-toggle { 8 | @apply block fixed h-12 w-full bottom-0 flex items-center justify-center font-bold border-none bg-highlight text-white z-50; 9 | 10 | @screen xs { 11 | @apply h-12; 12 | } 13 | 14 | @screen md { 15 | @apply hidden; 16 | } 17 | 18 | .mobile-nav-icon-line { 19 | height: 2px; 20 | } 21 | 22 | // when menu toggle is clicked 23 | &.menu-toggle-active { 24 | @apply bg-transparent; 25 | .mobile-nav-icon-bg { 26 | @apply bg-highlight rounded-full; 27 | width: 40px; 28 | height: 40px; 29 | position: absolute; 30 | margin-left: -2px; 31 | } 32 | 33 | .mobile-nav-icon-line { 34 | @apply m-0 bg-white; 35 | 36 | &:nth-child(1) { 37 | transform: rotate(45deg) translateY(3px); 38 | } 39 | 40 | &:nth-child(2) { 41 | @apply opacity-0; 42 | } 43 | 44 | &:nth-child(3) { 45 | transform: rotate(-45deg) translateY(-3px); 46 | } 47 | } 48 | 49 | .mobile-nav-label { 50 | position: absolute; 51 | left: -100%; 52 | } 53 | } 54 | } 55 | 56 | .wrapper.menu-visible { 57 | display: none; 58 | @screen md { 59 | display: flex; 60 | } 61 | } 62 | 63 | // mobile menu 64 | .mobile-nav { 65 | @apply fixed left-0 top-0 h-screen w-full overflow-y-auto pt-12 bg-dark z-50; 66 | height: -webkit-fill-available; 67 | transform: translate3d(-100%, 0, 0); 68 | transition: transform $transition-length $transition-easing; 69 | transition-delay: 0.1s; 70 | will-change: transform; 71 | 72 | @screen md { 73 | @apply hidden; 74 | } 75 | 76 | // when menu is visible 77 | &.menu-visible { 78 | transform: translate3d(0, 0, 0); 79 | 80 | .item { 81 | @apply opacity-100; 82 | transform: translate3d(0, 0, 0); 83 | } 84 | 85 | .footer { 86 | @apply opacity-100 duration-300; 87 | transition-delay: 1s; 88 | } 89 | } 90 | 91 | .item { 92 | transition: opacity 0.4s ease, 93 | transform $transition-length $transition-easing; 94 | transform: translate3d(-50%, 0, 0); 95 | transition-delay: $transition-length; 96 | 97 | // incrementally delay our animations 98 | @for $i from 0 through 100 { 99 | &:nth-child(#{$i}) { 100 | transition-delay: $transition-length * $i / 8 + 0.5; 101 | } 102 | } 103 | } 104 | 105 | .footer { 106 | @apply pt-3 px-5 fixed left-0 w-full z-50 overflow-y-auto; 107 | 108 | // bottom = height of .mobile-nav-toggle 109 | bottom: 3rem; 110 | @screen xs { 111 | bottom: 4rem; 112 | } 113 | 114 | @screen sm { 115 | @apply px-5 py-6; 116 | } 117 | 118 | @screen md { 119 | @apply hidden; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /styles/components/donate.scss: -------------------------------------------------------------------------------- 1 | .content .donation-options { 2 | @apply flex flex-col my-10; 3 | 4 | @screen sm { 5 | @apply flex-row flex-wrap max-w-3xl; 6 | 7 | a { 8 | @apply mr-4; 9 | } 10 | } 11 | 12 | @screen lg { 13 | @apply my-16; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /styles/components/examples.scss: -------------------------------------------------------------------------------- 1 | // This component can be included in markdown templates by using this syntax: 2 | // 3 | // ::: examples 4 | // markdown content 5 | // ::: 6 | // 7 | // turns into: 8 | // 9 | //
10 | // markdown content 11 | //
12 | // 13 | 14 | .markdown.content .examples { 15 | ul { 16 | @apply list-none p-0 m-0 grid grid-cols-2 gap-4; 17 | 18 | @screen md { 19 | @apply grid-cols-3; 20 | } 21 | 22 | li + li { 23 | @apply mt-0; 24 | } 25 | } 26 | 27 | img { 28 | @apply w-full mb-2 object-cover rounded-lg border border-white; 29 | -webkit-filter: grayscale(100%); 30 | filter: grayscale(100%); 31 | height: 10em; 32 | mix-blend-mode: overlay; 33 | transition: filter 0.25s ease-out; 34 | } 35 | 36 | img:hover { 37 | filter: grayscale(0%); 38 | mix-blend-mode: normal; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /styles/components/featured-pattern.scss: -------------------------------------------------------------------------------- 1 | .featured-pattern { 2 | @apply flex flex-col my-8; 3 | 4 | @screen xl { 5 | @apply flex-row max-w-5xl mb-32; 6 | } 7 | 8 | // illustration 9 | div:first-child { 10 | @apply flex-none; 11 | 12 | @screen lg { 13 | @apply mr-12; 14 | } 15 | 16 | img { 17 | max-width: 100%; 18 | } 19 | } 20 | 21 | // text 22 | div:last-child { 23 | @apply flex flex-col max-w-xl; 24 | min-width: 300px; 25 | 26 | h2 { 27 | @apply mt-4 mb-2; 28 | 29 | @screen sm { 30 | @apply mt-8; 31 | } 32 | 33 | em { 34 | @apply block text-lg; 35 | } 36 | } 37 | 38 | p + p { 39 | @apply mt-2; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /styles/components/links.scss: -------------------------------------------------------------------------------- 1 | .link-reference { 2 | @apply text-base text-highlight; 3 | 4 | &.sm { 5 | font-size: .75rem; 6 | } 7 | 8 | &::after { 9 | content: url("/images/icons/arrow-right.svg"); 10 | vertical-align: middle; 11 | margin-left: 2rem; 12 | transition-property: margin-left; 13 | transition-duration: 0.3s; 14 | } 15 | 16 | &:hover { 17 | &::after { 18 | margin-left: 3rem; 19 | } 20 | } 21 | } 22 | 23 | .markdown .link-reference { 24 | @apply text-base; 25 | } 26 | 27 | .link-next, 28 | .link-prev { 29 | @apply flex flex-row h-12 max-w-2xl pr-4 items-center; 30 | @apply text-base text-highlight; 31 | 32 | @screen md { 33 | @apply h-16; 34 | } 35 | 36 | @screen lg { 37 | max-width: 20rem; 38 | } 39 | } 40 | 41 | .link-next { 42 | div:first-child { 43 | @apply pr-16 inline; 44 | } 45 | 46 | div:last-child { 47 | @apply flex-shrink-0 ml-auto flex justify-center content-center; 48 | @apply w-12 h-12 rounded-full; 49 | @apply bg-highlight text-white text-xl; 50 | line-height: 1; 51 | 52 | // @screen md { 53 | // @apply w-16 h-16; 54 | // line-height: 1.5; 55 | // } 56 | 57 | transition-property: padding-left; 58 | transition-duration: 0.3s; 59 | } 60 | 61 | &.link-small { 62 | div:last-child { 63 | @apply w-8 h-8; 64 | } 65 | } 66 | 67 | // icon button hover animation 68 | &:hover { 69 | div:last-child { 70 | @apply pl-2; 71 | } 72 | } 73 | } 74 | 75 | .link-prev { 76 | div:last-child { 77 | @apply pl-16 inline; 78 | } 79 | 80 | img { 81 | transition: transform 0.3s ease-in; 82 | } 83 | 84 | &.link-small { 85 | div:first-child { 86 | @apply w-8 h-8; 87 | } 88 | } 89 | 90 | // icon button hover animation 91 | &:hover { 92 | img { 93 | transform: translateX(-4px); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /styles/components/offers.scss: -------------------------------------------------------------------------------- 1 | // Styles for the grid listing at /work-with-us 2 | 3 | .offers { 4 | @apply flex flex-col; 5 | 6 | @screen md { 7 | @apply flex-row flex-wrap; 8 | } 9 | 10 | @screen lg { 11 | @apply ml-0 mr-0 mt-16; 12 | } 13 | 14 | section { 15 | @apply max-w-sm mb-16; 16 | 17 | @screen md { 18 | @apply mb-32 mr-16; 19 | } 20 | 21 | @screen lg { 22 | @apply mr-32 max-w-md; 23 | } 24 | 25 | @screen xl { 26 | @apply mr-48; 27 | } 28 | 29 | ul { 30 | @apply list-disc; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /styles/components/pattern-listing.scss: -------------------------------------------------------------------------------- 1 | #pattern-listing { 2 | @apply max-w-4xl; 3 | 4 | .filterbar { 5 | @apply flex flex-col mb-4; 6 | 7 | @screen sm { 8 | @apply flex-row; 9 | } 10 | 11 | @screen md { 12 | @apply mb-8; 13 | } 14 | 15 | input { 16 | @apply w-full mb-4 bg-transparent border-b-2 border-light p-2; 17 | 18 | @screen sm { 19 | @apply mr-4 mb-0; 20 | } 21 | 22 | &:focus { 23 | @apply bg-dark; 24 | outline: none; 25 | } 26 | } 27 | 28 | .button-group { 29 | @apply items-center; 30 | } 31 | 32 | .button-group .btn { 33 | @apply my-0; 34 | } 35 | } 36 | } 37 | 38 | #pattern-listing-entries { 39 | a { 40 | @apply border-none; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /styles/components/pattern-main.scss: -------------------------------------------------------------------------------- 1 | .library-main { 2 | ul.library-main-topics { 3 | li { 4 | @apply max-w-6xl; 5 | } 6 | 7 | li + li { 8 | @apply mt-24; 9 | 10 | @screen sm { 11 | @apply mt-32; 12 | } 13 | } 14 | 15 | // topic description 16 | .library-main-topics-description { 17 | @apply max-w-2xl; 18 | 19 | @screen xl { 20 | @apply my-16; 21 | } 22 | } 23 | 24 | .library-main-topics-patterns { 25 | @apply flex flex-row justify-between my-8; 26 | 27 | @screen sm { 28 | @apply my-12; 29 | } 30 | 31 | @screen xl { 32 | @apply my-16; 33 | } 34 | 35 | div { 36 | // Equal spacing for pattern previews 37 | @apply flex-1; 38 | } 39 | 40 | // gap between pattern previews 41 | div + div { 42 | @apply ml-4; 43 | 44 | @screen sm { 45 | @apply ml-12; 46 | } 47 | 48 | @screen md { 49 | @apply ml-8; 50 | } 51 | 52 | @screen xl { 53 | @apply ml-12; 54 | } 55 | } 56 | 57 | // Show more previews for larger screens 58 | 59 | div:nth-child(3) { 60 | @apply hidden; 61 | } 62 | 63 | @screen md { 64 | div:nth-child(3) { 65 | @apply block; 66 | } 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /styles/components/pattern-preview.scss: -------------------------------------------------------------------------------- 1 | // Component for rendering a pattern preview that includes an image and 2 | // a short text blurb below 3 | .pattern-preview { 4 | @apply max-w-xs; 5 | 6 | img { 7 | @apply mb-4; 8 | width: 322px; 9 | height: 204px; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /styles/components/pattern.scss: -------------------------------------------------------------------------------- 1 | .inner.pattern { 2 | // 3 | // Rules for desktop content columns 4 | // 5 | .pattern-content { 6 | @screen lg { 7 | @apply w-2/3; 8 | } 9 | } 10 | 11 | .pattern-sidebar { 12 | @screen lg { 13 | @apply w-1/3 pl-16; 14 | } 15 | } 16 | 17 | // 18 | // Head of page contains illustration and metadata (except tags) 19 | // 20 | 21 | .pattern-head { 22 | @apply flex flex-col; 23 | 24 | @screen lg { 25 | @apply flex-row mt-16; 26 | } 27 | 28 | .pattern-illustration { 29 | img { 30 | @apply w-full; 31 | } 32 | } 33 | 34 | .pattern-meta { 35 | @apply flex flex-col mt-4; 36 | 37 | @screen lg { 38 | @apply mt-0; 39 | } 40 | 41 | & > div { 42 | @apply my-3; 43 | 44 | em:first-child { 45 | @apply text-medium; 46 | } 47 | } 48 | } 49 | 50 | .pattern-related-patterns { 51 | a { 52 | @apply block text-caption; 53 | } 54 | 55 | li span { 56 | text-transform: capitalize; 57 | } 58 | 59 | li + li { 60 | @apply mt-3; 61 | } 62 | } 63 | } 64 | 65 | // 66 | // Main section of page contains text content and sidebar with tags 67 | // 68 | 69 | .pattern-main { 70 | @apply flex flex-col-reverse; 71 | 72 | @screen md { 73 | @apply flex-row; 74 | } 75 | 76 | .content.markdown { 77 | p, 78 | ul, 79 | ol { 80 | @apply max-w-full; 81 | } 82 | } 83 | 84 | .pattern-sidebar { 85 | .pattern-tags { 86 | @apply my-3; 87 | 88 | @screen md { 89 | @apply my-12; 90 | } 91 | 92 | em:first-child { 93 | @apply text-medium mb-1; 94 | } 95 | } 96 | } 97 | 98 | h3 { 99 | margin-top: 5.5rem; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /styles/components/projects.scss: -------------------------------------------------------------------------------- 1 | 2 | .hero-section { 3 | margin-top: 0px; 4 | padding-top: 68px; 5 | padding-right: 24px; 6 | background-image: url(/projects/web-monetization/gftw-hero.png); 7 | background-color: transparent; 8 | background-position: 100% 50%, 0px 0px; 9 | background-size: auto 460px, auto; 10 | background-repeat: no-repeat, repeat; 11 | background-attachment: scroll, scroll; 12 | } 13 | 14 | 15 | .hero-section-header { 16 | max-width: 531px; 17 | padding-top: 96px; 18 | padding-bottom: 96px; 19 | } 20 | 21 | @media screen and (max-width: 767px) { 22 | .hero-section { 23 | padding-top: 32px; 24 | } 25 | } 26 | 27 | @media screen and (max-width: 991px) { 28 | .hero-section { 29 | padding-right: 0px; 30 | } 31 | .hero-section-header { 32 | max-width: inherit; 33 | background-color: rgb(26 32 44 / 70%); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /styles/components/report.scss: -------------------------------------------------------------------------------- 1 | // These style rules are written specifically for the dots report, however they 2 | // are not scoped to that page 3 | 4 | #report .content.markdown { 5 | // the take-aways component sits below a heading and contains the main take- 6 | // aways of the following paragraph 7 | 8 | p, 9 | ul, 10 | ol { 11 | @apply max-w-xl; 12 | } 13 | 14 | .take-aways { 15 | @apply mb-16; 16 | 17 | @screen md { 18 | @apply mb-24; 19 | } 20 | 21 | p { 22 | @apply text-base my-8; 23 | 24 | @screen md { 25 | @apply text-lg my-16; 26 | } 27 | } 28 | 29 | ul, 30 | ol { 31 | @apply pl-0 list-none; 32 | 33 | @screen md { 34 | @apply pl-8 list-none; 35 | 36 | li { 37 | @apply mb-8; 38 | } 39 | } 40 | } 41 | } 42 | 43 | // The table of contents is written as a regular markdown lists, this class 44 | // allows customizing the markdown list-styling to something that works for 45 | // a table of contents 46 | 47 | .markdown-toc { 48 | ul, 49 | ol { 50 | @apply my-4; 51 | li { 52 | @apply mt-4; 53 | } 54 | } 55 | } 56 | 57 | // the aside is a special element used in the dots report. it is implemented 58 | // here as an element with a dotted colored border and contains content that 59 | // sits "aside" to the main content of the report 60 | 61 | .aside { 62 | @apply py-8 px-6 my-16 border-dotted border-2 border-secondary; 63 | 64 | @screen md { 65 | @apply py-16 px-12; 66 | 67 | p { 68 | @apply mb-16; 69 | } 70 | } 71 | 72 | ul { 73 | @apply mb-0 pl-0; 74 | 75 | @screen md { 76 | @apply pl-8; 77 | } 78 | } 79 | 80 | ul li { 81 | @apply list-none font-bold mb-8; 82 | 83 | &:last-child { 84 | @apply mb-0; 85 | } 86 | 87 | ul { 88 | @apply list-outside pl-6; 89 | 90 | @screen md { 91 | @apply pl-0; 92 | } 93 | } 94 | 95 | ul li { 96 | @apply list-disc font-normal pl-2 mt-0 mb-0; 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /styles/components/timeline.scss: -------------------------------------------------------------------------------- 1 | .timeline { 2 | position: relative; 3 | &__item { 4 | @apply flex flex-wrap; 5 | 6 | &.progress { 7 | svg path, 8 | svg rect { 9 | fill: theme("colors.highlight"); 10 | } 11 | height: 200%; 12 | width: 30px; 13 | content: ""; 14 | } 15 | 16 | &.done { 17 | height: 30px; 18 | width: 30px; 19 | } 20 | 21 | &.idle { 22 | height: 200%; 23 | width: 30px; 24 | content: ""; 25 | } 26 | 27 | &__description { 28 | @apply text-highlight text-base flex-1; 29 | margin-left: 9px; 30 | &.done { 31 | @apply text-secondary; 32 | } 33 | &.idle { 34 | @apply text-gray-400; 35 | } 36 | } 37 | 38 | &__date { 39 | @apply mb-6 text-caption; 40 | flex-basis: 100%; // date wraps on its own line 41 | color: text-gray-600; 42 | margin-left: 39px; // keep space for icon 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /styles/fonts/Inter-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Black.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Black.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-BlackItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-BlackItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-BlackItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-BlackItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Bold.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Bold.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-BoldItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-BoldItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraBold.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraBold.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraBoldItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraLight.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraLight.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraLight.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraLightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraLightItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-ExtraLightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ExtraLightItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Italic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Italic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Light.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Light.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-LightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-LightItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-LightItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Medium.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Medium.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-MediumItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-MediumItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-MediumItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-MediumItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Regular.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Regular.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-SemiBold.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-SemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-SemiBoldItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Thin.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-Thin.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-ThinItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ThinItalic.woff -------------------------------------------------------------------------------- /styles/fonts/Inter-ThinItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-ThinItalic.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-italic.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-italic.var.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter-roman.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter-roman.var.woff2 -------------------------------------------------------------------------------- /styles/fonts/Inter.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/Inter.var.woff2 -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Bold.woff -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Bold.woff2 -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Light.woff -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Light.woff2 -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Medium.woff -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Medium.woff2 -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Regular.woff -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-Regular.woff2 -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-SemiBold.woff -------------------------------------------------------------------------------- /styles/fonts/SpaceGrotesk-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sprblm/dots-website/9564fed4c8e927fb70eb7f2f4d0e72b71f584f72/styles/fonts/SpaceGrotesk-SemiBold.woff2 -------------------------------------------------------------------------------- /styles/fonts/grotesk.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Space Grotesk"; 3 | font-style: normal; 4 | font-weight: 300; 5 | font-display: swap; 6 | src: url("SpaceGrotesk-Light.woff2") format("woff2"), 7 | url("SpaceGrotesk-Light.woff") format("woff"); 8 | } 9 | 10 | @font-face { 11 | font-family: "Space Grotesk"; 12 | font-style: normal; 13 | font-weight: 400; 14 | font-display: swap; 15 | src: url("SpaceGrotesk-Regular.woff2") format("woff2"), 16 | url("SpaceGrotesk-Regular.woff") format("woff"); 17 | } 18 | 19 | @font-face { 20 | font-family: "Space Grotesk"; 21 | font-style: normal; 22 | font-weight: 500; 23 | font-display: swap; 24 | src: url("SpaceGrotesk-Medium.woff2") format("woff2"), 25 | url("SpaceGrotesk-Medium.woff") format("woff"); 26 | } 27 | 28 | @font-face { 29 | font-family: "Space Grotesk"; 30 | font-style: normal; 31 | font-weight: 600; 32 | font-display: swap; 33 | src: url("SpaceGrotesk-SemiBold.woff2") format("woff2"), 34 | url("SpaceGrotesk-SemiBold.woff") format("woff"); 35 | } 36 | 37 | @font-face { 38 | font-family: "Space Grotesk"; 39 | font-style: normal; 40 | font-weight: 700; 41 | font-display: swap; 42 | src: url("SpaceGrotesk-Bold.woff2") format("woff2"), 43 | url("SpaceGrotesk-Bold.woff") format("woff"); 44 | } 45 | -------------------------------------------------------------------------------- /styles/fonts/inter.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Inter"; 3 | font-style: normal; 4 | font-weight: 100; 5 | font-display: swap; 6 | src: url("Inter-Thin.woff2?v=3.12") format("woff2"), 7 | url("Inter-Thin.woff?v=3.12") format("woff"); 8 | } 9 | @font-face { 10 | font-family: "Inter"; 11 | font-style: italic; 12 | font-weight: 100; 13 | font-display: swap; 14 | src: url("Inter-ThinItalic.woff2?v=3.12") format("woff2"), 15 | url("Inter-ThinItalic.woff?v=3.12") format("woff"); 16 | } 17 | 18 | @font-face { 19 | font-family: "Inter"; 20 | font-style: normal; 21 | font-weight: 200; 22 | font-display: swap; 23 | src: url("Inter-ExtraLight.woff2?v=3.12") format("woff2"), 24 | url("Inter-ExtraLight.woff?v=3.12") format("woff"); 25 | } 26 | @font-face { 27 | font-family: "Inter"; 28 | font-style: italic; 29 | font-weight: 200; 30 | font-display: swap; 31 | src: url("Inter-ExtraLightItalic.woff2?v=3.12") format("woff2"), 32 | url("Inter-ExtraLightItalic.woff?v=3.12") format("woff"); 33 | } 34 | 35 | @font-face { 36 | font-family: "Inter"; 37 | font-style: normal; 38 | font-weight: 300; 39 | font-display: swap; 40 | src: url("Inter-Light.woff2?v=3.12") format("woff2"), 41 | url("Inter-Light.woff?v=3.12") format("woff"); 42 | } 43 | @font-face { 44 | font-family: "Inter"; 45 | font-style: italic; 46 | font-weight: 300; 47 | font-display: swap; 48 | src: url("Inter-LightItalic.woff2?v=3.12") format("woff2"), 49 | url("Inter-LightItalic.woff?v=3.12") format("woff"); 50 | } 51 | 52 | @font-face { 53 | font-family: "Inter"; 54 | font-style: normal; 55 | font-weight: 400; 56 | font-display: swap; 57 | src: url("Inter-Regular.woff2?v=3.12") format("woff2"), 58 | url("Inter-Regular.woff?v=3.12") format("woff"); 59 | } 60 | @font-face { 61 | font-family: "Inter"; 62 | font-style: italic; 63 | font-weight: 400; 64 | font-display: swap; 65 | src: url("Inter-Italic.woff2?v=3.12") format("woff2"), 66 | url("Inter-Italic.woff?v=3.12") format("woff"); 67 | } 68 | 69 | @font-face { 70 | font-family: "Inter"; 71 | font-style: normal; 72 | font-weight: 500; 73 | font-display: swap; 74 | src: url("Inter-Medium.woff2?v=3.12") format("woff2"), 75 | url("Inter-Medium.woff?v=3.12") format("woff"); 76 | } 77 | @font-face { 78 | font-family: "Inter"; 79 | font-style: italic; 80 | font-weight: 500; 81 | font-display: swap; 82 | src: url("Inter-MediumItalic.woff2?v=3.12") format("woff2"), 83 | url("Inter-MediumItalic.woff?v=3.12") format("woff"); 84 | } 85 | 86 | @font-face { 87 | font-family: "Inter"; 88 | font-style: normal; 89 | font-weight: 600; 90 | font-display: swap; 91 | src: url("Inter-SemiBold.woff2?v=3.12") format("woff2"), 92 | url("Inter-SemiBold.woff?v=3.12") format("woff"); 93 | } 94 | @font-face { 95 | font-family: "Inter"; 96 | font-style: italic; 97 | font-weight: 600; 98 | font-display: swap; 99 | src: url("Inter-SemiBoldItalic.woff2?v=3.12") format("woff2"), 100 | url("Inter-SemiBoldItalic.woff?v=3.12") format("woff"); 101 | } 102 | 103 | @font-face { 104 | font-family: "Inter"; 105 | font-style: normal; 106 | font-weight: 700; 107 | font-display: swap; 108 | src: url("Inter-Bold.woff2?v=3.12") format("woff2"), 109 | url("Inter-Bold.woff?v=3.12") format("woff"); 110 | } 111 | @font-face { 112 | font-family: "Inter"; 113 | font-style: italic; 114 | font-weight: 700; 115 | font-display: swap; 116 | src: url("Inter-BoldItalic.woff2?v=3.12") format("woff2"), 117 | url("Inter-BoldItalic.woff?v=3.12") format("woff"); 118 | } 119 | 120 | @font-face { 121 | font-family: "Inter"; 122 | font-style: normal; 123 | font-weight: 800; 124 | font-display: swap; 125 | src: url("Inter-ExtraBold.woff2?v=3.12") format("woff2"), 126 | url("Inter-ExtraBold.woff?v=3.12") format("woff"); 127 | } 128 | @font-face { 129 | font-family: "Inter"; 130 | font-style: italic; 131 | font-weight: 800; 132 | font-display: swap; 133 | src: url("Inter-ExtraBoldItalic.woff2?v=3.12") format("woff2"), 134 | url("Inter-ExtraBoldItalic.woff?v=3.12") format("woff"); 135 | } 136 | 137 | @font-face { 138 | font-family: "Inter"; 139 | font-style: normal; 140 | font-weight: 900; 141 | font-display: swap; 142 | src: url("Inter-Black.woff2?v=3.12") format("woff2"), 143 | url("Inter-Black.woff?v=3.12") format("woff"); 144 | } 145 | @font-face { 146 | font-family: "Inter"; 147 | font-style: italic; 148 | font-weight: 900; 149 | font-display: swap; 150 | src: url("Inter-BlackItalic.woff2?v=3.12") format("woff2"), 151 | url("Inter-BlackItalic.woff?v=3.12") format("woff"); 152 | } 153 | 154 | /* ------------------------------------------------------- 155 | Variable font. 156 | Usage: 157 | 158 | html { font-family: 'Inter', sans-serif; } 159 | @supports (font-variation-settings: normal) { 160 | html { font-family: 'Inter var', sans-serif; } 161 | } 162 | */ 163 | @font-face { 164 | font-family: "Inter var"; 165 | font-weight: 100 900; 166 | font-display: swap; 167 | font-style: normal; 168 | font-named-instance: "Regular"; 169 | src: url("Inter-roman.var.woff2?v=3.12") format("woff2"); 170 | } 171 | @font-face { 172 | font-family: "Inter var"; 173 | font-weight: 100 900; 174 | font-display: swap; 175 | font-style: italic; 176 | font-named-instance: "Italic"; 177 | src: url("Inter-italic.var.woff2?v=3.12") format("woff2"); 178 | } 179 | 180 | /* -------------------------------------------------------------------------- 181 | [EXPERIMENTAL] Multi-axis, single variable font. 182 | 183 | Slant axis is not yet widely supported (as of February 2019) and thus this 184 | multi-axis single variable font is opt-in rather than the default. 185 | 186 | When using this, you will probably need to set font-variation-settings 187 | explicitly, e.g. 188 | 189 | * { font-variation-settings: "slnt" 0deg } 190 | .italic { font-variation-settings: "slnt" 10deg } 191 | 192 | */ 193 | @font-face { 194 | font-family: "Inter var experimental"; 195 | font-weight: 100 900; 196 | font-display: swap; 197 | font-style: oblique 0deg 10deg; 198 | src: url("Inter.var.woff2?v=3.12") format("woff2"); 199 | } 200 | -------------------------------------------------------------------------------- /styles/main.scss: -------------------------------------------------------------------------------- 1 | //========== Imports ==========// 2 | 3 | // Import Tailwind preflight 4 | @tailwind base; 5 | 6 | // Import our custom base styles 7 | @import "base/all"; 8 | 9 | // Import Tailwind components 10 | @tailwind components; 11 | 12 | // Import our custom component styles 13 | @import "components/all"; 14 | 15 | // Import Tailwind utilities 16 | // TailwindCSS recommends leaving utilities till last to ensure they aren't overwritten. 17 | @tailwind utilities; 18 | -------------------------------------------------------------------------------- /update_patterns.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | git submodule update --init 3 | cd dots-patterns 4 | git pull --ff-only 5 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 3 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 4 | 5 | const isDev = process.env.NODE_ENV !== "production"; 6 | 7 | module.exports = { 8 | devServer: { 9 | clientLogLevel: "silent", 10 | contentBase: path.join(__dirname, "dist"), 11 | host: "localhost", 12 | hot: true, 13 | port: 8081, 14 | progress: true, 15 | stats: "minimal", 16 | sockPort: 8081, 17 | writeToDisk: true, 18 | }, 19 | devtool: isDev ? "cheap-module-source-map" : "source-map", 20 | entry: [ 21 | path.resolve(__dirname, "./scripts/main.js"), 22 | path.resolve(__dirname, "./styles/main.scss"), 23 | ], 24 | mode: isDev ? "development" : "production", 25 | module: { 26 | rules: [ 27 | { 28 | test: /\.s[ac]ss$/i, 29 | use: [ 30 | isDev ? "style-loader" : MiniCssExtractPlugin.loader, 31 | { loader: "css-loader", options: { url: false } }, 32 | "postcss-loader", 33 | "sass-loader", 34 | ], 35 | }, 36 | ], 37 | }, 38 | output: { 39 | filename: "main.js", 40 | path: path.resolve(__dirname, "dist", "js"), 41 | }, 42 | plugins: [ 43 | new CleanWebpackPlugin(), 44 | new MiniCssExtractPlugin({ 45 | filename: "../css/[name].css", 46 | }), 47 | ], 48 | resolve: { 49 | alias: { 50 | "@utilities": path.resolve(__dirname, "scripts/utilities"), 51 | "@modules": path.resolve(__dirname, "scripts/modules"), 52 | }, 53 | }, 54 | }; 55 | --------------------------------------------------------------------------------