├── .browserslistrc ├── .cc-metadata.yml ├── .dockerignore ├── .editorconfig ├── .env ├── .eslintrc.js ├── .github ├── dependabot.yml └── workflows │ ├── cd.yml │ ├── ci.yml │ └── project-automation.yml ├── .gitignore ├── .huskyrc ├── .storybook ├── main.js ├── manager-head.html ├── manager.js ├── meta │ ├── contribution.stories.mdx │ ├── usage.stories.mdx │ └── welcome.stories.mdx ├── order.js ├── preview-head.html ├── preview.js ├── theme.js └── viewport.js ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── INSTRUCTIONS.md ├── LICENSE ├── README.md ├── babel.config.js ├── deploy.sh ├── docker-compose.yml ├── jest.config.js ├── library ├── build.js ├── components.json ├── index-stencil.txt └── variables.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── readme_assets ├── cc_logo.png └── vocabulary_logo.svg ├── src ├── assets │ ├── icons │ │ └── favicon.png │ └── titlecard.png ├── i18n.js ├── index.js ├── knobs │ ├── attribute.js │ ├── branded.js │ ├── circleable.js │ ├── colored.js │ ├── direction.js │ ├── iconified.js │ ├── indicating.js │ ├── invertible.js │ ├── joined.js │ ├── raisable.js │ ├── rounded.js │ ├── scaled.js │ ├── simplified.js │ ├── text.js │ ├── toned.js │ └── unactionable.js ├── layouts │ ├── README.md │ ├── Table │ │ ├── Table.vue │ │ └── TableCell.vue │ └── Tabs │ │ ├── Tab.vue │ │ ├── Tabs.stories.mdx │ │ └── Tabs.vue ├── locales │ ├── en.json │ └── hi.json ├── mixins │ ├── branded.js │ ├── circleable.js │ ├── colored.js │ ├── indicating.js │ ├── invertible.js │ ├── joined.js │ ├── raisable.js │ ├── rounded.js │ ├── scaled.js │ ├── simplified.js │ ├── toned.js │ └── unactionable.js ├── patterns │ ├── Footer │ │ └── Footer.vue │ ├── Header │ │ └── Header.vue │ └── Locale │ │ └── Locale.vue └── utils │ ├── SlotRenderer │ ├── SlotRenderer.md │ └── SlotRenderer.vue │ └── helpers.js ├── tests ├── .eslintrc.js └── unit │ └── Dummy.spec.js └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.cc-metadata.yml: -------------------------------------------------------------------------------- 1 | # Whether this GitHub repo is engineering related 2 | engineering_project: true 3 | # Name of the repository/project in English 4 | english_name: CC Vocabulary 5 | # All technologies used 6 | technologies: JavaScript, Vue, Webpack, Babel, Stylus, Styleguidist, Theo 7 | # Whether this repository should be featured on the CC Open Source site 8 | featured: false # In the future, maybe 9 | # Slack channel name 10 | slack: 'cc-dev-vocabulary' 11 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /docs 5 | /build 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js, jsx, ts, tsx, vue, styl, md}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | 7 | [*.md] 8 | trim_trailing_whitespace = false 9 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | VUE_APP_I18N_LOCALE=en 2 | VUE_APP_I18N_FALLBACK_LOCALE=en 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | '@vue/standard' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 13 | 'vue/script-indent': ['error', 2, { 14 | switchCase: 1, 15 | baseIndent: 1 16 | }] // Supersedes the normal indent rule 17 | }, 18 | overrides: [ 19 | { 20 | files: ['*.vue'], 21 | rules: { 22 | indent: 'off' // Replaced by vue/script-indent 23 | } 24 | } 25 | ], 26 | parserOptions: { 27 | parser: 'babel-eslint' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | 8 | - package-ecosystem: "docker" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: vue-vocabulary-cd 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | env: 9 | PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true 10 | 11 | jobs: 12 | deploy_npm: 13 | name: Deploy to npm 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: Setup Node.js 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: 12 22 | registry-url: https://registry.npmjs.org 23 | 24 | - name: Install dependencies 25 | run: npm install --no-audit 26 | 27 | - name: Publish package 28 | run: bash deploy.sh 29 | env: 30 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 31 | 32 | deploy_gh: 33 | name: Deploy to GitHub Packages 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v2 37 | 38 | - name: Setup Node.js 39 | uses: actions/setup-node@v1 40 | with: 41 | node-version: 12 42 | registry-url: https://npm.pkg.github.com/ 43 | 44 | - name: Install dependencies 45 | run: npm install --no-audit 46 | 47 | - name: Publish package 48 | run: bash deploy.sh 49 | env: 50 | NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: vue-vocabulary-ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | env: 12 | CI: true 13 | PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true 14 | 15 | jobs: 16 | setup: 17 | name: Setup 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - name: Setup Node.js 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: '12.16.1' 27 | 28 | - id: cache-node-modules 29 | name: Cache Node.js modules 30 | uses: actions/cache@v1 31 | with: 32 | path: ~/.npm # npm caches files in ~/.npm 33 | key: node-${{ hashFiles('**/package-lock.json') }} 34 | 35 | - name: Install dependencies 36 | run: npm install --no-audit 37 | 38 | lint: 39 | name: Lint 40 | runs-on: ubuntu-latest 41 | needs: setup 42 | 43 | steps: 44 | - uses: actions/checkout@v2 45 | 46 | - name: Setup Node.js 47 | uses: actions/setup-node@v1 48 | with: 49 | node-version: '12.16.1' 50 | 51 | - id: cache-node-modules 52 | name: Cache Node.js modules 53 | uses: actions/cache@v1 54 | with: 55 | path: ~/.npm # npm caches files in ~/.npm 56 | key: node-${{ hashFiles('**/package-lock.json') }} 57 | 58 | - name: Install dependencies 59 | run: npm install --prefer-offline --no-audit 60 | 61 | - name: Run lint 62 | run: npm run lint 63 | 64 | unit: 65 | name: Unit tests 66 | runs-on: ubuntu-latest 67 | needs: setup 68 | 69 | steps: 70 | - uses: actions/checkout@v2 71 | 72 | - name: Setup Node.js 73 | uses: actions/setup-node@v1 74 | with: 75 | node-version: '12.16.1' 76 | 77 | - id: cache-node-modules 78 | name: Cache Node.js modules 79 | uses: actions/cache@v1 80 | with: 81 | path: ~/.npm # npm caches files in ~/.npm 82 | key: node-${{ hashFiles('**/package-lock.json') }} 83 | 84 | - name: Install dependencies 85 | run: npm install --prefer-offline --no-audit 86 | 87 | - name: Run tests 88 | run: npm run test:unit 89 | 90 | build: 91 | name: Build 92 | runs-on: ubuntu-latest 93 | needs: setup 94 | 95 | steps: 96 | - uses: actions/checkout@v2 97 | 98 | - name: Setup Node.js 99 | uses: actions/setup-node@v1 100 | with: 101 | node-version: '12.16.1' 102 | 103 | - id: cache-node-modules 104 | name: Cache Node.js modules 105 | uses: actions/cache@v1 106 | with: 107 | path: ~/.npm # npm caches files in ~/.npm 108 | key: node-${{ hashFiles('**/package-lock.json') }} 109 | 110 | - name: Install dependencies 111 | run: npm install --prefer-offline --no-audit 112 | 113 | - name: Run build 114 | run: npm run build 115 | -------------------------------------------------------------------------------- /.github/workflows/project-automation.yml: -------------------------------------------------------------------------------- 1 | name: "Project Automation" 2 | on: 3 | issues: 4 | types: [opened] 5 | pull_request: 6 | types: [opened] 7 | jobs: 8 | join_issue_pr_to_project: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: "Automate adding issues" 12 | uses: docker://takanabe/github-actions-automate-projects:v0.0.1 13 | if: github.event_name == 'issues' 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }} 16 | GITHUB_PROJECT_URL: https://github.com/orgs/creativecommons/projects/13 17 | GITHUB_PROJECT_COLUMN_NAME: "To Triage" 18 | - name: "Automate adding PRs" 19 | uses: docker://takanabe/github-actions-automate-projects:v0.0.1 20 | if: github.event_name == 'pull_request' 21 | continue-on-error: true 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }} 24 | GITHUB_PROJECT_URL: https://github.com/orgs/creativecommons/projects/13 25 | GITHUB_PROJECT_COLUMN_NAME: "In Progress" 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /build 5 | /docs 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "npm run lint" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [ 3 | './meta/*.stories.mdx', 4 | '../src/**/*.stories.mdx' 5 | ], 6 | addons: [ 7 | 'storybook-addon-designs', 8 | '@storybook/addon-knobs', 9 | '@storybook/addon-backgrounds', 10 | '@storybook/addon-viewport', 11 | '@storybook/addon-docs' 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.storybook/manager-head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/addons' 2 | 3 | import theme from './theme' 4 | 5 | addons.setConfig({ 6 | theme 7 | }) 8 | -------------------------------------------------------------------------------- /.storybook/meta/contribution.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs/blocks' 2 | 3 | 4 | 5 | # Contribution 6 | 7 | We're always looking for contributors to help us find and fix bugs, build new 8 | features, help us improve the project documentation or translate the project to 9 | another language. 10 | 11 | Vue Vocabulary is continuously evolving and improving. You can contribute to the 12 | project in a number of ways. 13 | 14 | | What | How | 15 | |-|-| 16 | | **Code** | If you are a developer, feel free to resolve open issues, proof PRs, add new features to existing components or add new components altogether. | 17 | | **Design** | If you are a designer, your inputs on making every component more intuitive, aesthetic and joyful will reverberate through the entire ecosystem. | 18 | | **Test** | If you are a user of these components, your feedback, bug reports and feature requests will drive the project forward so that we can meet your needs. | 19 | | **Write** | If you have a knack for writing technical articles, you could be the voice of the library's documentation, making it easy to use and understand. | 20 | | **Share** | If you can't contribute in these ways, you can refer the project to a friend who might be able to. Spreading the word is the easiest way to help out. | 21 | 22 | Interested? 23 | 24 | The following instructions are in addition to the processes in our general [Contribution][contribution] and 25 | [Pull Request][pull_request] guidelines on the Creative Common Open Source website, and [those] in Vocabulary. If you 26 | haven't read them already, read them first. 27 | 28 | [contribution]:https://creativecommons.github.io/contributing-code/ 29 | [pull_request]:https://opensource.creativecommons.org/contributing-code/pr-guidelines/ 30 | [those]:https://cc-vocabulary.netlify.com/?path=/docs/vocabulary-contribution--page 31 | 32 | These instructions are a port of the general guidelines, tailored specifically for Vue Vocabulary. 33 | 34 | ## Setting up 35 | 36 | Clone the repository. If you intend to contribute, which you should, fork the repo from GitHub's GUI and clone your fork 37 | instead. See GitHub Help pages for [instructions on how to do that](https://help.github.com/en/github/getting-started-with-github/fork-a-repo). 38 | 39 | To setup you can either use Docker and Docker Compose or manually set up the project. Both have their advantages and 40 | disadvantages. 41 | 42 | Docker makes sure every developer has a consistent and identical development setup. It also removes the entire hassle 43 | involved in dependency management. On the other hand, it is heavy and hits system resources particularly hard. 44 | 45 | Manual setups are lightweight, tweakable and much more performant as the code runs very close to the operating 46 | system. On the other hand, all dependencies must be manually resolved and each developer has a different setup. 47 | 48 | ### Docker and Docker Compose 49 | 50 | Install Docker and Docker Compose, if you don't already have them on your computer. 51 | 52 | Bring up all services. 53 | 54 | ```bash 55 | $ docker-compose up -d 56 | ``` 57 | 58 | To run `npm` commands, you'll need to enter a Vue Vocabulary container. 59 | 60 | ```bash 61 | $ ./docker/vue-vocabulary/run.sh 62 | docker-desktop:/codebase$ ... 63 | ``` 64 | 65 | If you install new packages, you'll need to rebuild a few things. 66 | 67 | ```bash 68 | $ docker-compose down 69 | $ docker volume prune 70 | $ docker-compose build storybook 71 | ``` 72 | 73 | ### Manual setup 74 | 75 | Install Node.js and NPM, if you don't already have them on your computer. 76 | 77 | Install dependencies. 78 | ``` 79 | $ npm install 80 | ``` 81 | 82 | Start the Storybook process which is an interactive playground of components in 83 | the browser. 84 | 85 | ``` 86 | $ npm run storybook 87 | ``` 88 | 89 | ## Discussing changes, assigning work, making changes and testing 90 | 91 | See [Vocabulary guidelines]. 92 | 93 | [Vocabulary guidelines]:https://cc-vocabulary.netlify.com/?path=/docs/vocabulary-contribution--page 94 | -------------------------------------------------------------------------------- /.storybook/meta/usage.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs/blocks' 2 | 3 | 4 | 5 | # Usage 6 | 7 | We've tried to make it as easy as possible to use Vue Vocabulary in your projects. Depending on your build pipeline you 8 | might prefer to install Vue Vocabulary via `npm` or via a CDN. 9 | 10 | You need to install Vue and [Vue i18n], explaining which is beyond the scope of this guide. The usage of Vue Vocabulary 11 | requires the installation and usage of Vocabulary. See [Vocabulary installation]. Once you are done with installing all 12 | of these, resume installation from the steps here. 13 | 14 | [Vue i18n]:https://kazupon.github.io/vue-i18n/ 15 | [Vocabulary installation]:https://cc-vocabulary.netlify.com/?path=/docs/vocabulary-usage--page 16 | 17 | ## NPM 18 | 19 | For a full fledged app, use `npm` (or if you're one of those people, `yarn`) to install Vue Vocabulary. 20 | 21 | ### Installation 22 | 23 | Just install `@creativecommons/vue-vocabulary` using the package manager of your choice. 24 | 25 | ```bash 26 | # Remember to install dependencies 27 | # npm install vue vue-i18n @creativecommons/vocabulary 28 | $ npm install @creativecommons/vue-vocabulary 29 | ``` 30 | 31 | ### JavaScript 32 | 33 | 78 | 79 | Coming soon. 80 | 81 | ## CDN 82 | 83 | To start using Vue Vocabulary for quick prototyping or development you can use one of our CDN-based deployments. Both 84 | CDNs mirror our `npm` deploys so choose either one based on your personal preference. 85 | 86 | Just link to the master CSS and JS files with any of these one-line `link` and `script` tags within your document 87 | `head` tag. 88 | 89 | ### Installation 90 | 91 | #### unpkg 92 | 93 | ```html 94 | 100 | 101 | ``` 102 | 103 | #### jsDelivr 104 | 105 | ```html 106 | 112 | 113 | ``` 114 | 115 | ### JavaScript 116 | 117 | 118 | Coming soon. 119 | -------------------------------------------------------------------------------- /.storybook/meta/welcome.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta, Story, Preview } from '@storybook/addon-docs/blocks' 2 | 3 | import vocabularySvg from '@creativecommons/vocabulary/assets/logos/products/vocabulary.svg' 4 | import gitHubCornerSvg from '@creativecommons/vocabulary/assets/github_corner.svg' 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 |

14 | Vocabulary is a cohesive design system to unite the web facing Creative Commons.
15 | Vue Vocabulary is a Vue component library implementing Vocabulary. 16 |

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |

25 | This is the Storybook for Vue Vocabulary.
26 | Choose a component from the left panel to know more about it and explore the various customisations it has to offer. 27 |

28 |
29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.storybook/order.js: -------------------------------------------------------------------------------- 1 | const order = { 2 | 'Vue Vocabulary': [ 3 | 'Introduction', 4 | 'Contribution', 5 | 'Usage' 6 | ], 7 | 'Layouts': [] 8 | } 9 | const families = Object.keys(order) 10 | 11 | export default ([, one], [, two]) => { 12 | if (one.kind === two.kind) { 13 | return 0 // Sort stories in a component as defined in the MDX file 14 | } 15 | const [famOne, componentOne] = one.kind.split('/') 16 | const [famTwo, componentTwo] = two.kind.split('/') 17 | if (famOne === famTwo) { 18 | if (order[famOne].length) { 19 | return order[famOne].indexOf(componentOne) - order[famOne].indexOf(componentTwo) 20 | } else { 21 | return componentOne.localeCompare(componentTwo) // Sort components in a family in alphabetical order 22 | } 23 | } else { 24 | return families.indexOf(famOne) - families.indexOf(famTwo) // Sort families according to defined order 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { addDecorator, addParameters } from '@storybook/vue' 2 | 3 | import { withDesign } from 'storybook-addon-designs' 4 | import { withKnobs } from '@storybook/addon-knobs' 5 | 6 | import i18n from '@/i18n' 7 | 8 | import viewports from './viewport' 9 | import order from './order' 10 | 11 | import '@creativecommons/vocabulary/css/vocabulary.css' 12 | 13 | addParameters({ 14 | options: { 15 | showRoots: true, 16 | storySort: order 17 | }, 18 | backgrounds: [ 19 | { name: 'canvas', value: '#f5f5f5', default: true }, 20 | { name: 'white', value: '#ffffff' }, 21 | { name: 'black', value: '#000000' } 22 | ], 23 | viewport: { 24 | viewports 25 | } 26 | }) 27 | 28 | addDecorator(withDesign) 29 | addDecorator(withKnobs) 30 | addDecorator( 31 | () => ({ 32 | i18n, 33 | template: '', 34 | // https://github.com/storybookjs/storybook/issues/6548#issuecomment-504336665 35 | beforeCreate: function () { 36 | this.$root._i18n = this.$i18n 37 | } 38 | }) 39 | ) 40 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import { create } from '@storybook/theming' 2 | 3 | import vocabularySvg from '@creativecommons/vocabulary/assets/logos/products/vocabulary.svg' 4 | 5 | export default create({ 6 | // Inherit 7 | base: 'light', 8 | 9 | // Color scheme 10 | colorPrimary: 'rgb(0, 0, 0)', // No known usage 11 | colorSecondary: 'rgb(251, 119, 41)', // Accent color 12 | 13 | // UI colors 14 | appBg: 'rgb(248, 249, 250)', 15 | 16 | // Rows of controls 17 | barTextColor: 'rgb(73, 80, 87)', 18 | barSelectedColor: 'rgb(251, 119, 41)', 19 | barBg: 'rgb(255, 255, 255)', 20 | 21 | // Typography 22 | fontBase: '"Source Sans Pro", sans-serif', 23 | fontCode: '"Fira Code", monospace', 24 | 25 | // Text colors 26 | textColor: 'rgb(0, 0, 0)', 27 | textInverseColor: 'rgb(255, 255, 255)', 28 | 29 | // Branding 30 | brandTitle: 'Vue Vocabulary', 31 | brandUrl: 'https://opensource.creativecommons.org/cc-vue-vocabulary', 32 | brandImage: vocabularySvg 33 | }) 34 | -------------------------------------------------------------------------------- /.storybook/viewport.js: -------------------------------------------------------------------------------- 1 | // Configuration of addon-viewport 2 | 3 | export default { 4 | // Mobiles 5 | ClassicPhone: { 6 | name: 'Classic phone', 7 | styles: { 8 | width: '320px', 9 | height: '480px' 10 | }, 11 | type: 'mobile' 12 | }, 13 | iPhoneSE: { 14 | name: 'Apple iPhone SE', 15 | styles: { 16 | width: '320px', 17 | height: '568px', 18 | borderTopWidth: '95px', 19 | borderBottomWidth: '95px', 20 | borderLeftWidth: '12.5px', 21 | borderRightWidth: '12.5px', 22 | borderRadius: '55px' 23 | }, 24 | type: 'mobile' 25 | }, 26 | Note9: { 27 | name: 'Samsung Galaxy Note 9', 28 | styles: { 29 | width: '360px', 30 | height: '740px', 31 | borderTopWidth: '35px', 32 | borderBottomWidth: '25px', 33 | borderLeftWidth: '7.5px', 34 | borderRightWidth: '7.5px', 35 | borderRadius: '25px' 36 | }, 37 | type: 'mobile' 38 | }, 39 | iPhone6: { 40 | name: 'Apple iPhone 6', 41 | styles: { 42 | width: '375px', 43 | height: '667px', 44 | borderTopWidth: '95px', 45 | borderBottomWidth: '95px', 46 | borderLeftWidth: '12.5px', 47 | borderRightWidth: '12.5px', 48 | borderRadius: '55px' 49 | }, 50 | type: 'mobile' 51 | }, 52 | iPhone11Pro: { 53 | name: 'Apple iPhone 11 Pro', 54 | styles: { 55 | width: '375px', 56 | height: '812px', 57 | paddingTop: '20px', 58 | borderWidth: '20px', 59 | borderRadius: '50px' 60 | }, 61 | type: 'mobile' 62 | }, 63 | GooglePixel3: { 64 | name: 'Google Pixel 3', 65 | styles: { 66 | width: '412px', 67 | height: '824px', 68 | borderTopWidth: '70px', 69 | borderBottomWidth: '70px', 70 | borderLeftWidth: '20px', 71 | borderRightWidth: '20px', 72 | borderRadius: '60px' 73 | }, 74 | type: 'mobile' 75 | }, 76 | iPhone11: { 77 | name: 'Apple iPhone 11', 78 | styles: { 79 | width: '414px', 80 | height: '896px', 81 | paddingTop: '20px', 82 | borderWidth: '20px', 83 | borderRadius: '50px' 84 | }, 85 | type: 'mobile' 86 | }, 87 | iPhone11ProMax: { 88 | name: 'Apple iPhone 11 Pro Max', 89 | styles: { 90 | width: '414px', 91 | height: '896px', 92 | paddingTop: '20px', 93 | borderWidth: '20px', 94 | borderRadius: '50px' 95 | }, 96 | type: 'mobile' 97 | }, 98 | 99 | // Tablets 100 | ClassicTablet: { 101 | name: 'Classic tablet', 102 | styles: { 103 | width: '600px', 104 | height: '800px' 105 | }, 106 | type: 'tablet' 107 | }, 108 | iPadMini: { 109 | name: 'Apple iPad Mini 7.9"', 110 | styles: { 111 | width: '768px', 112 | height: '1024px', 113 | borderTopWidth: '90px', 114 | borderBottomWidth: '90px', 115 | borderLeftWidth: '20px', 116 | borderRightWidth: '20px', 117 | borderRadius: '55px' 118 | }, 119 | type: 'tablet' 120 | }, 121 | iPad: { 122 | name: 'Apple iPad 10.2"', 123 | styles: { 124 | width: '810px', 125 | height: '1080px', 126 | borderTopWidth: '85px', 127 | borderBottomWidth: '85px', 128 | borderLeftWidth: '20px', 129 | borderRightWidth: '20px', 130 | borderRadius: '45px' 131 | 132 | }, 133 | type: 'tablet' 134 | }, 135 | iPadAir: { 136 | name: 'Apple iPad Air 10.5"', 137 | styles: { 138 | width: '834px', 139 | height: '1112px', 140 | borderTopWidth: '85px', 141 | borderBottomWidth: '85px', 142 | borderLeftWidth: '20px', 143 | borderRightWidth: '20px', 144 | borderRadius: '45px' 145 | }, 146 | type: 'tablet' 147 | }, 148 | iPadPro11: { 149 | name: 'Apple iPad Pro 11"', 150 | styles: { 151 | width: '834px', 152 | height: '1194px', 153 | paddingTop: '20px', 154 | borderWidth: '20px', 155 | borderRadius: '50px' 156 | }, 157 | type: 'tablet' 158 | }, 159 | iPadPro13: { 160 | name: 'Apple iPad Pro 12.9"', 161 | styles: { 162 | width: '1024px', 163 | height: '1366px', 164 | paddingTop: '17.5px', 165 | borderWidth: '17.5px', 166 | borderRadius: '25px' 167 | }, 168 | type: 'tablet' 169 | }, 170 | 171 | // Desktops 172 | ClassicDesktop: { 173 | name: 'Classic desktop', 174 | styles: { 175 | width: '1024px', 176 | height: '768px' 177 | }, 178 | type: 'monitor' 179 | }, 180 | AsusChromebook: { 181 | name: 'Asus Chromebook', 182 | styles: { 183 | width: '1280px', 184 | height: '800px', 185 | borderTopWidth: '25px', 186 | borderBottomWidth: '75px', 187 | borderLeftWidth: '25px', 188 | borderRightWidth: '25px', 189 | borderRadius: '10px' 190 | }, 191 | type: 'monitor' 192 | }, 193 | MacBookPro12: { 194 | name: 'Apple MacBook Pro 12"', 195 | styles: { 196 | width: '1280px', 197 | height: '800px', 198 | borderTopWidth: '35px', 199 | borderBottomWidth: '35px', 200 | borderLeftWidth: '20px', 201 | borderRightWidth: '20px', 202 | borderRadius: '30px' 203 | }, 204 | type: 'monitor' 205 | }, 206 | AcerChromebook: { 207 | name: 'Acer Chromebook', 208 | styles: { 209 | width: '1366px', 210 | height: '768px', 211 | borderTopWidth: '45px', 212 | borderBottomWidth: '65px', 213 | borderLeftWidth: '40px', 214 | borderRightWidth: '40px', 215 | borderRadius: '10px' 216 | }, 217 | type: 'monitor' 218 | }, 219 | MacBookPro15: { 220 | name: 'Apple MacBook Pro 15"', 221 | styles: { 222 | width: '1440px', 223 | height: '900px', 224 | borderTopWidth: '25px', 225 | borderBottomWidth: '25px', 226 | borderLeftWidth: '15px', 227 | borderRightWidth: '15px', 228 | borderRadius: '20px' 229 | }, 230 | type: 'monitor' 231 | }, 232 | MacBookPro16: { 233 | name: 'Apple MacBook Pro 16"', 234 | styles: { 235 | width: '1536px', 236 | height: '960px', 237 | borderTopWidth: '25px', 238 | borderBottomWidth: '25px', 239 | borderLeftWidth: '15px', 240 | borderRightWidth: '15px', 241 | borderRadius: '20px' 242 | }, 243 | type: 'monitor' 244 | }, 245 | DellXPS13: { 246 | name: 'Dell XPS 13', 247 | styles: { 248 | width: '1920px', 249 | height: '1080px', 250 | borderTopWidth: '20px', 251 | borderBottomWidth: '75px', 252 | borderLeftWidth: '20px', 253 | borderRightWidth: '20px', 254 | borderRadius: '20px' 255 | }, 256 | type: 'monitor' 257 | }, 258 | SurfaceProX: { 259 | name: 'Microsoft Surface Pro X', 260 | styles: { 261 | width: '2880px', 262 | height: '1920px', 263 | borderTopWidth: '70px', 264 | borderBottomWidth: '70px', 265 | borderLeftWidth: '25px', 266 | borderRightWidth: '25px', 267 | borderRadius: '35px' 268 | }, 269 | type: 'monitor' 270 | }, 271 | SurfaceBook213: { 272 | name: 'Microsoft Surface Book 2 13.5"', 273 | styles: { 274 | width: '3000px', 275 | height: '2000px', 276 | borderWidth: '52.5px', 277 | borderRadius: '22.5px' 278 | }, 279 | type: 'monitor' 280 | }, 281 | SurfaceBook215: { 282 | name: 'Microsoft Surface Book 2 15"', 283 | styles: { 284 | width: '3240px', 285 | height: '2160px', 286 | borderWidth: '52.5px', 287 | borderRadius: '22.5px' 288 | }, 289 | type: 'monitor' 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | The Creative Commons team is committed to fostering a welcoming community. This 4 | project, CC Vocabulary, and all other Creative Commons open source projects are 5 | governed by our [Code of Conduct][code_of_conduct]. Please report unacceptable 6 | behavior to [conduct@creativecommons.org][email_address] per our 7 | [reporting guidelines][reporting_guide]. 8 | 9 | For a history of updates, see the [page history here][updates]. 10 | 11 | [code_of_conduct]:https://creativecommons.github.io/community/code-of-conduct/ 12 | [email_address]:mailto:conduct@creativecommons.org 13 | [reporting_guide]:https://creativecommons.github.io/community/code-of-conduct/enforcement/ 14 | [updates]:https://github.com/creativecommons/creativecommons.github.io-source/commits/master/content/community/code-of-conduct/contents.lr 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to CC Open Source 2 | 3 | Thank you for your interest in contributing to CC Vocabulary! This document is 4 | a set of guidelines to help you contribute to this project. 5 | 6 | ## Code of Conduct 7 | 8 | By participating in this project, you are expected to uphold our Code of 9 | Conduct, which can be found [on our website][code_of_conduct] and also in the 10 | repository in the file `CODE_OF_CONDUCT.md`. 11 | 12 | [code_of_conduct]:https://creativecommons.github.io/community/code-of-conduct/ 13 | 14 | ## Project Documentation 15 | 16 | The `README.md` file describes the goals and introduces the project. Further 17 | documentation is present in the form of `.md` files placed in the folder 18 | structure as well as in the form of code comments. 19 | 20 | Instructions pertaining to development such as the procedure to set up a copy of 21 | the codebase and a running instance locally on your machine can be found in 22 | `INSTRUCTIONS.md`. 23 | 24 | ## How to Contribute 25 | 26 | Please follow the processes in our general [Contributing Code][contributing] 27 | guidelines on the Creative Common Open Source website. 28 | 29 | Contributions in terms of code, documentation and translations are welcome! 30 | 31 | In addition to this, read the `README.md` and `INSTRUCTIONS.md` files in the 32 | repository for instructions. 33 | 34 | [contributing]:https://creativecommons.github.io/contributing-code/ 35 | 36 | ## Questions or Thoughts? 37 | 38 | Talk to us on [our developer mailing list or Slack community][community]. 39 | 40 | [community]:https://creativecommons.github.io/community/ 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build on top of a Node.js + npm image. 2 | FROM node:lts 3 | 4 | # Make a codebase directory and work in it 5 | RUN mkdir codebase 6 | WORKDIR /codebase 7 | 8 | # Load the package.json and package-lock.json files 9 | COPY package.json ./ 10 | COPY package-lock.json ./ 11 | 12 | # Install packages 13 | RUN npm install 14 | 15 | # Expose ports on the container 16 | EXPOSE 8080 17 | -------------------------------------------------------------------------------- /INSTRUCTIONS.md: -------------------------------------------------------------------------------- 1 | # Development instructions 2 | 3 | ## Setting up the project 4 | 5 | **Step 0:** 6 | Fork the project. This will be useful if you intend to submit PRs. 7 | 8 | **Step 1:** Clone the project to your computer. If you chose to fork the 9 | repository in step 1, clone the fork instead. 10 | 11 | ``` 12 | $ git clone https://github.com/creativecommmons/vue-vocabulary.git 13 | ``` 14 | 15 | **Step 2:** 16 | Change into the project directory. 17 | 18 | ``` 19 | $ cd vue-vocabulary/ 20 | ``` 21 | 22 | After this step, there are two ways to proceed. Choose the one that suits your 23 | needs best. 24 | 25 | ### Dockerised setup (recommended) 26 | 27 | _Requires Docker and Docker Compose to be installed._ 28 | 29 | **Step 3:** 30 | Start the Docker containers for the project. 31 | 32 | ``` 33 | $ docker-compose up 34 | ``` 35 | 36 | ### Manual setup 37 | 38 | _Requires Node.js and npm to be installed._ 39 | 40 | **Step 3:** 41 | Install npm dependencies. 42 | 43 | ``` 44 | $ npm install 45 | ``` 46 | 47 | **Step 4:** 48 | Start the Vocabulary storybook by running the `storybook` task. 49 | 50 | ``` 51 | $ npm run storybook 52 | ``` 53 | 54 | ## Requesting changes 55 | 56 | For bugs reports and feature requests, use GitHub issues with the appropriate 57 | labels. We can discuss the possibility of that change or new feature being 58 | implemented and released in the future. This lets us come to an agreement about 59 | the proposed idea before any work is done. 60 | 61 | ## Submitting changes 62 | 63 | **Step 0:** 64 | Discuss on the issue. If not already being worked on, take it up. Make sure that 65 | the changes are in alignment with the short and long term goals of the project. 66 | 67 | **Step 1:** 68 | Create a branch named after the changes. Use underscores. Be descriptive. 69 | 70 | ``` 71 | $ git checkout -b branch_name 72 | ``` 73 | 74 | **Step 2:** 75 | Resolve the issue by changing the code. Update tests if need be. 76 | 77 | **Step 3:** 78 | Run the `lint` and `test:unit` tasks to ensure code quality and functionality. 79 | 80 | ``` 81 | $ npm run lint 82 | $ npm run test:unit 83 | ``` 84 | 85 | If translations are to be changed, update the `.json` files under individual 86 | components for component-level translations or the `.json` files in `locales/` 87 | for global-level translations. 88 | 89 | New locales must be manually added to the `Locale` component. 90 | 91 | **Step 4:** 92 | Push the commits to your branch on the fork and submit a PR. Fill all relevant 93 | fields in the PR template. 94 | 95 | ``` 96 | $ git add file_name 97 | $ git commit 98 | $ git push --set-upstream fork branch_name 99 | ``` 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Creative Commons 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Important: This repository is archived and has moved to the [main vocabulary monorepo](https://github.com/creativecommons/vocabulary). 2 | 3 | You should clone that repository instead. Note that npm package names have remained the same, only the codebase has moved. 4 | 5 | --- 6 | 7 |

8 | 14 |

15 | 16 | > Vue Vocabulary is a Vue component library implementing a cohesive design system to unite the web facing Creative Commons. 17 | 18 |

19 | 22 | MIT license 23 | 24 | 27 | PRs welcome 28 | 29 | 32 | GitHub Actions 33 | 34 | 37 | Netlify 38 | 39 | 42 | npm version 43 | 44 |

45 | 46 | In essence Vue Vocabulary is a collection of UI components that incorporate Vocabulary under the hood. 47 | Vue Vocabulary makes it easier to develop Creative Commons apps while ensuring a consistently familiar experience. 48 | 49 | ### Using 50 | 51 | To use Vue Vocabulary in your projects, refer to [this document](https://cc-vue-vocabulary.netlify.app/?path=/docs/vue-vocabulary-usage--page). 52 | 53 | ### Contributing 54 | 55 | To contribute to Vue Vocabulary, refer to [this document](https://cc-vue-vocabulary.netlify.app/?path=/docs/vue-vocabulary-contribution--page). 56 | 57 | ### Disclaimer 58 | 59 | This project is still under development and as a consequence of the fact, users 60 | of the library should be expect to encounter bugs. Feedback and bug reports are 61 | welcome, fixes and patches even more so. 62 | 63 | ### License 64 | 65 | Licensed under the Expat/[MIT](http://www.opensource.org/licenses/MIT) license. 66 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@vue/cli-plugin-babel/preset', 5 | { 6 | jsx: false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o errtrace 5 | set -o nounset 6 | 7 | trap '_es=${?}; 8 | _lo=${LINENO}; 9 | _co=${BASH_COMMAND}; 10 | echo "${0}: line ${_lo}: \"${_co}\" exited with a status of ${_es}"; 11 | exit ${_es}' ERR 12 | 13 | npm run build 14 | rm dist/demo.html 15 | cp package.json dist/ 16 | cp README.md dist/ 17 | cp LICENSE dist/ 18 | 19 | cd dist 20 | npm publish --access public 21 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Development Docker Compose # 3 | ############################## 4 | 5 | # This is the version of the Docker Compose standard 6 | version: '3.4' 7 | 8 | services: 9 | storybook: 10 | # Name of the container 11 | container_name: vocabulary-storybook 12 | # Use the CC Vocabulary image 13 | image: ccvocabulary:latest 14 | # Restart build if it fails 15 | restart: always 16 | # If the image is not found, build it 17 | build: . 18 | 19 | # The command to run in the container 20 | command: npm run storybook 21 | 22 | # Volumes attached to the container 23 | volumes: 24 | - .:/codebase 25 | - node_modules:/codebase/node_modules 26 | ports: 27 | # Map 6006 in the container to the same port on the host 28 | - 8080:8080 29 | 30 | volumes: 31 | # Holds the node_modules directory 32 | # Prevents the host node_modules from being mounted and used 33 | node_modules: 34 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: [ 3 | 'js', 4 | 'jsx', 5 | 'json', 6 | 'vue' 7 | ], 8 | transform: { 9 | '^.+\\.vue$': 'vue-jest', 10 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', 11 | '^.+\\.jsx?$': 'babel-jest' 12 | }, 13 | transformIgnorePatterns: [ 14 | '/node_modules/' 15 | ], 16 | moduleNameMapper: { 17 | '^@/(.*)$': '/src/$1' 18 | }, 19 | snapshotSerializers: [ 20 | 'jest-serializer-vue' 21 | ], 22 | testMatch: [ 23 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 24 | ], 25 | testURL: 'http://localhost/', 26 | watchPlugins: [ 27 | 'jest-watch-typeahead/filename', 28 | 'jest-watch-typeahead/testname' 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /library/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const chalk = require('chalk') 3 | 4 | const variables = require('./variables') 5 | 6 | const componentsRegistry = require(variables.libraryRegistryPath) 7 | 8 | console.log( 9 | chalk.blue.inverse(`● Indexing ${variables.verboseName}`) 10 | ) 11 | indexComponents() 12 | console.log( 13 | chalk.green.inverse('\n✔ Done.') 14 | ) 15 | 16 | // Functions 17 | 18 | function indexComponents () { 19 | const fileContent = formContent() 20 | writeIndex(fileContent) 21 | } 22 | 23 | function parseRegistryEntry (entry) { 24 | let directory, name 25 | if (entry instanceof Array) { 26 | directory = entry[0] 27 | name = entry[1] 28 | } else { 29 | directory = entry 30 | name = entry 31 | } 32 | return { directory, name } 33 | } 34 | 35 | function formContent () { 36 | process.stdout.write(chalk.yellow( 37 | '├─ Forming content for index at', 38 | chalk.bold(variables.srcIndexPath), 39 | '... ' 40 | )) 41 | 42 | const families = Object.keys(componentsRegistry) 43 | const imports = families.map( 44 | family => componentsRegistry[family].map( 45 | component => { 46 | let { name, directory } = parseRegistryEntry(component) 47 | return `import ${name} from './${family}/${directory}/${name}'` 48 | } 49 | ).join('\n') 50 | ).join('\n\n') 51 | 52 | const components = families.map( 53 | family => componentsRegistry[family].map( 54 | component => { 55 | let { name } = parseRegistryEntry(component) 56 | return ` ${name}` 57 | } 58 | ).join(',\n') 59 | ).join(',\n\n') 60 | 61 | const registrations = families.map( 62 | family => componentsRegistry[family].map( 63 | component => { 64 | let { name } = parseRegistryEntry(component) 65 | return ` Vue.component('${name}', ${name})` 66 | } 67 | ).join('\n') 68 | ).join('\n\n') 69 | process.stdout.write(chalk.green('done\n')) 70 | 71 | const indexStencilContent = fs.readFileSync( 72 | variables.libraryStencilPath, 73 | { 74 | encoding: 'utf-8' 75 | } 76 | ) 77 | return indexStencilContent 78 | .replace('{{imports}}', imports) 79 | .replace('{{components}}', components) 80 | .replace('{{registrations}}', registrations) 81 | } 82 | 83 | function writeIndex (fileContent) { 84 | process.stdout.write(chalk.yellow( 85 | '└─ Writing library exports to', 86 | chalk.bold(variables.srcIndexPath), 87 | '... ' 88 | )) 89 | fs.writeFileSync(variables.srcIndexPath, fileContent) 90 | process.stdout.write(chalk.green('done\n')) 91 | } 92 | -------------------------------------------------------------------------------- /library/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "utils": [ 3 | "SlotRenderer" 4 | ], 5 | "layouts": [ 6 | "Tabs", 7 | ["Tabs", "Tab"], 8 | "Table", 9 | ["Table", "TableCell"] 10 | ], 11 | "patterns": [ 12 | "Footer", 13 | "Header", 14 | "Locale" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /library/index-stencil.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Fragile magic. Do not touch. 3 | * 4 | * Just kidding, this file is autogenerated and changes will be overwritten on 5 | * the next build. To make changes, edit [library/build.js]. 6 | */ 7 | 8 | {{imports}} 9 | 10 | // Export individual components 11 | export { 12 | {{components}} 13 | } 14 | 15 | // Export as plugin 16 | export default { 17 | install: function (Vue) { 18 | {{registrations}} 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /library/variables.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const verboseName = 'Vue Vocabulary' 4 | 5 | const rootDir = path.resolve(__dirname, '..') 6 | 7 | const srcDir = path.resolve(rootDir, 'src') 8 | const libraryDir = path.resolve(rootDir, 'library') 9 | 10 | const libraryRegistryPath = path.join(libraryDir, 'components.json') 11 | const libraryStencilPath = path.join(libraryDir, 'index-stencil.txt') 12 | const srcIndexPath = path.join(srcDir, 'index.js') 13 | 14 | module.exports = { 15 | verboseName, 16 | libraryRegistryPath, 17 | libraryStencilPath, 18 | srcIndexPath 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@creativecommons/vue-vocabulary", 3 | "version": "1.0.0-beta.10", 4 | "description": "Vue components implementing a cohesive design system to unite the web facing Creative Commons", 5 | "author": "Creative Commons (https://creativecommons.org)", 6 | "scripts": { 7 | "lint": "vue-cli-service lint", 8 | "test:unit": "vue-cli-service test:unit", 9 | "index": "node library/build.js", 10 | "build": "npm run index && vue-cli-service build --target lib --name vue-vocabulary --dest ./dist --entry ./src/index.js", 11 | "watch": "npm run build -- --watch", 12 | "storybook": "vue-cli-service storybook:serve --ci -s ./src/assets -p 8080", 13 | "build:documentation": "npm run build && vue-cli-service storybook:build -s ./src/assets -o ./docs" 14 | }, 15 | "dependencies": { 16 | "@creativecommons/vocabulary": "^2020.8.5", 17 | "@fortawesome/fontawesome-svg-core": "^1.2.30", 18 | "@fortawesome/free-brands-svg-icons": "^5.14.0", 19 | "@fortawesome/free-regular-svg-icons": "^5.14.0", 20 | "@fortawesome/free-solid-svg-icons": "^5.14.0", 21 | "@fortawesome/vue-fontawesome": "^0.1.10", 22 | "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", 23 | "@vue/babel-preset-jsx": "^1.1.2", 24 | "core-js": "^3.4.4", 25 | "lodash": "^4.17.20", 26 | "twemoji": "^12.1.6", 27 | "vue": "^2.6.10", 28 | "vue-i18n": "^8.20.0" 29 | }, 30 | "devDependencies": { 31 | "@kazupon/vue-i18n-loader": "^0.5.0", 32 | "@storybook/addon-backgrounds": "^6.0.15", 33 | "@storybook/addon-docs": "^6.0.15", 34 | "@storybook/addon-knobs": "^6.0.15", 35 | "@storybook/addon-notes": "^5.3.19", 36 | "@storybook/addon-viewport": "^6.0.15", 37 | "@storybook/addons": "^6.0.15", 38 | "@storybook/components": "^6.0.15", 39 | "@storybook/theming": "^6.0.15", 40 | "@storybook/vue": "^6.0.16", 41 | "@vue/cli-plugin-babel": "^4.4.6", 42 | "@vue/cli-plugin-eslint": "^4.4.6", 43 | "@vue/cli-plugin-unit-jest": "^4.4.6", 44 | "@vue/cli-service": "^4.5.4", 45 | "@vue/eslint-config-standard": "^4.0.0", 46 | "@vue/test-utils": "1.0.0-beta.29", 47 | "babel-core": "7.0.0-bridge.0", 48 | "babel-eslint": "^10.0.3", 49 | "babel-jest": "^26.2.2", 50 | "babel-loader": "^8.0.6", 51 | "chalk": "^2.4.2", 52 | "eslint": "^5.16.0", 53 | "eslint-plugin-vue": "^5.2.3", 54 | "fs-extra": "^9.0.1", 55 | "husky": "^4.2.3", 56 | "lerna": "^3.22.1", 57 | "react": "^16.12.0", 58 | "react-is": "^16.12.0", 59 | "storybook-addon-designs": "^5.4.1", 60 | "stylus": "^0.54.8", 61 | "stylus-loader": "^3.0.2", 62 | "vue-cli-plugin-i18n": "^0.6.0", 63 | "vue-cli-plugin-storybook": "^1.3.0", 64 | "vue-template-compiler": "^2.6.10" 65 | }, 66 | "bugs": "https://github.com/creativecommons/vue-vocabulary/issues/", 67 | "homepage": "https://creativecommons.github.io/vue-vocabulary/", 68 | "keywords": [ 69 | "ui", 70 | "ux", 71 | "design", 72 | "design system", 73 | "components", 74 | "vue components", 75 | "library" 76 | ], 77 | "license": "MIT", 78 | "repository": "github:creativecommons/vue-vocabulary" 79 | } 80 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /readme_assets/cc_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cc-archive/vue-vocabulary/ef73a34d2446ad3a0ba69c90908b28539d4a0c76/readme_assets/cc_logo.png -------------------------------------------------------------------------------- /readme_assets/vocabulary_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/icons/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cc-archive/vue-vocabulary/ef73a34d2446ad3a0ba69c90908b28539d4a0c76/src/assets/icons/favicon.png -------------------------------------------------------------------------------- /src/assets/titlecard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cc-archive/vue-vocabulary/ef73a34d2446ad3a0ba69c90908b28539d4a0c76/src/assets/titlecard.png -------------------------------------------------------------------------------- /src/i18n.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | 4 | Vue.use(VueI18n) 5 | 6 | function loadLocaleMessages () { 7 | const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i) 8 | const messages = {} 9 | locales.keys().forEach(key => { 10 | const matched = key.match(/([A-Za-z0-9-_]+)\./i) 11 | if (matched && matched.length > 1) { 12 | const locale = matched[1] 13 | messages[locale] = locales(key) 14 | } 15 | }) 16 | return messages 17 | } 18 | 19 | export default new VueI18n({ 20 | locale: process.env.VUE_APP_I18N_LOCALE || 'en', 21 | fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en', 22 | messages: loadLocaleMessages() 23 | }) 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fragile magic. Do not touch. 3 | * 4 | * Just kidding, this file is autogenerated and changes will be overwritten on 5 | * the next build. To make changes, edit [library/build.js]. 6 | */ 7 | 8 | import SlotRenderer from './utils/SlotRenderer/SlotRenderer' 9 | 10 | import Tabs from './layouts/Tabs/Tabs' 11 | import Tab from './layouts/Tabs/Tab' 12 | import Table from './layouts/Table/Table' 13 | import TableCell from './layouts/Table/TableCell' 14 | 15 | import Footer from './patterns/Footer/Footer' 16 | import Header from './patterns/Header/Header' 17 | import Locale from './patterns/Locale/Locale' 18 | 19 | // Export individual components 20 | export { 21 | SlotRenderer, 22 | 23 | Tabs, 24 | Tab, 25 | Table, 26 | TableCell, 27 | 28 | Footer, 29 | Header, 30 | Locale 31 | } 32 | 33 | // Export as plugin 34 | export default { 35 | install: function (Vue) { 36 | Vue.component('SlotRenderer', SlotRenderer) 37 | 38 | Vue.component('Tabs', Tabs) 39 | Vue.component('Tab', Tab) 40 | Vue.component('Table', Table) 41 | Vue.component('TableCell', TableCell) 42 | 43 | Vue.component('Footer', Footer) 44 | Vue.component('Header', Header) 45 | Vue.component('Locale', Locale) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/knobs/attribute.js: -------------------------------------------------------------------------------- 1 | import { text } from '@storybook/addon-knobs' 2 | 3 | export default { 4 | props: { 5 | type: { 6 | default: () => text('Type', 'type') 7 | }, 8 | name: { 9 | default: () => text('Name', 'name') 10 | }, 11 | title: { 12 | default: () => text('Title', 'title') 13 | }, 14 | value: { 15 | default: () => text('Value', 'title') 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/knobs/branded.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | 3 | const brandOptions = { 4 | Blue: 'blue', 5 | Forest: 'forest', 6 | Gold: 'gold', 7 | Orange: 'orange', 8 | Tomato: 'tomato', 9 | Turquoise: 'turquoise', 10 | Slate: 'slate' 11 | } 12 | 13 | export default { 14 | props: { 15 | brand: { 16 | default: () => select('Brand', brandOptions, brandOptions.Orange) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/knobs/circleable.js: -------------------------------------------------------------------------------- 1 | import { boolean } from '@storybook/addon-knobs' 2 | 3 | export default { 4 | props: { 5 | isCircular: { 6 | default: () => boolean('Is circular?', true) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/knobs/colored.js: -------------------------------------------------------------------------------- 1 | import { number, select } from '@storybook/addon-knobs' 2 | 3 | const colorOptions = { 4 | Red: 'red', 5 | Pink: 'pink', 6 | Grape: 'grape', 7 | Violet: 'violet', 8 | Indigo: 'indigo', 9 | Cyan: 'cyan', 10 | Teal: 'teal', 11 | Green: 'green', 12 | Lime: 'lime', 13 | Yellow: 'yellow' 14 | } 15 | 16 | export default { 17 | props: { 18 | color: { 19 | default: () => select('Color', colorOptions, colorOptions.Indigo) 20 | }, 21 | shade: { 22 | default: () => number('Shade', 9, { 23 | range: true, 24 | min: 0, 25 | max: 9, 26 | step: 1 27 | }) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/knobs/direction.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | 3 | const directionOptions = { 4 | Top: 'top', 5 | Right: 'right', 6 | Bottom: 'bottom', 7 | Left: 'left' 8 | } 9 | 10 | export default { 11 | props: { 12 | direction: { 13 | default: () => select('Direction', directionOptions, directionOptions.Top) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/knobs/iconified.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | import { library } from '@fortawesome/fontawesome-svg-core' 3 | import { 4 | faBars, 5 | faCircle, 6 | faSquare 7 | } from '@fortawesome/free-solid-svg-icons' 8 | import { faCreativeCommons } from '@fortawesome/free-brands-svg-icons' 9 | 10 | library.add( 11 | faBars, 12 | faCircle, 13 | faSquare, 14 | faCreativeCommons 15 | ) 16 | 17 | const iconOptions = { 18 | Circle: 'circle', 19 | Square: 'square', 20 | Bars: 'bars', 21 | 'Creative Commons': 'creative-commons' 22 | } 23 | 24 | export default { 25 | props: { 26 | icon: { 27 | default: () => { 28 | // Change icon into an array to allow display icons from the brand set 29 | let icon = select('Icon', iconOptions, iconOptions['Creative Commons']) 30 | if (icon === 'creative-commons') { 31 | return ['fab', icon] 32 | } 33 | return icon 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/knobs/indicating.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | 3 | const indicationOptions = { 4 | Negative: 'negative', 5 | Probably: 'probably', 6 | Postitive: 'positive' 7 | } 8 | 9 | export default { 10 | props: { 11 | indication: { 12 | default: () => select('Indication', indicationOptions, indicationOptions.Postitive) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/knobs/invertible.js: -------------------------------------------------------------------------------- 1 | import { boolean } from '@storybook/addon-knobs' 2 | 3 | export default { 4 | props: { 5 | isInverted: { 6 | default: () => boolean('Is inverted?', true) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/knobs/joined.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | 3 | const joinedOptions = { 4 | Left: 'left', 5 | Right: 'right', 6 | Both: 'both' 7 | } 8 | 9 | export default { 10 | props: { 11 | joinSide: { 12 | default: () => select('Join side', joinedOptions, joinedOptions.Left) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/knobs/raisable.js: -------------------------------------------------------------------------------- 1 | import { boolean } from '@storybook/addon-knobs' 2 | 3 | export default { 4 | props: { 5 | isRaised: { 6 | default: () => boolean('Is raised?', true) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/knobs/rounded.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | 3 | const roundOptions = { 4 | None: null, 5 | Slight: 'slight', 6 | Complete: 'complete' 7 | } 8 | 9 | export default { 10 | props: { 11 | roundness: { 12 | default: () => select('Roundness', roundOptions, roundOptions.None) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/knobs/scaled.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | 3 | const sizeOptions = { 4 | Small: 'small', 5 | Normal: 'normal', 6 | Big: 'big', 7 | Large: 'large', 8 | Huge: 'huge', 9 | Enormous: 'enormous', 10 | Gigantic: 'gigantic', 11 | Mega: 'mega' 12 | } 13 | 14 | export default { 15 | props: { 16 | size: { 17 | default: () => select('Size', sizeOptions, sizeOptions.Normal) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/knobs/simplified.js: -------------------------------------------------------------------------------- 1 | import { select } from '@storybook/addon-knobs' 2 | 3 | const simplifiedOptions = { 4 | None: null, 5 | Slight: 'slight', 6 | Extreme: 'extreme' 7 | } 8 | 9 | export default { 10 | props: { 11 | simplicity: { 12 | default: () => select('Simplicity', simplifiedOptions, simplifiedOptions.None) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/knobs/text.js: -------------------------------------------------------------------------------- 1 | import { text } from '@storybook/addon-knobs' 2 | 3 | export default { 4 | props: { 5 | text: { 6 | default: () => text('Text', 'Hello World!') 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/knobs/toned.js: -------------------------------------------------------------------------------- 1 | import { number } from '@storybook/addon-knobs' 2 | 3 | export default { 4 | props: { 5 | tone: { 6 | default: () => number('Tone', 9, { 7 | range: true, 8 | min: 0, 9 | max: 9, 10 | step: 1 11 | }) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/knobs/unactionable.js: -------------------------------------------------------------------------------- 1 | import { boolean } from '@storybook/addon-knobs' 2 | 3 | export default { 4 | props: { 5 | isDisabled: { 6 | default: () => boolean('Is disabled?', true) 7 | }, 8 | isReadOnly: { 9 | default: () => boolean('Is read-only?', false) 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/layouts/README.md: -------------------------------------------------------------------------------- 1 | ## lay·outs 2 | 3 |
4 | 7 |
8 | 9 |   10 | 11 | Layouts are components that are concerned with positioning and placement. They 12 | are zero-content components whose sole purpose is to define ways for children 13 | to be placed in a sensible fashion. 14 | 15 | Layouts place content with respect to other content in the same component. This 16 | is different from templates which place entire components next to each other. 17 | Thus, they occupy a level between elements and patterns. 18 | 19 | 20 | ### Working with layouts 21 | 22 | Layouts are nothing but Vue components with a major CSS aspect and consequently 23 | live in eponymous folders containing `Layout.vue`, `Layout.md` and `Layout.styl` 24 | files. 25 | 26 | Layouts should not contain components other than their cells (as is the case with 27 | `Grid`) or their panes as is the case with `Tabbed` in order to uphold the 28 | no-content principle. 29 | 30 | 31 | ### Examples 32 | 33 | We've seen that layouts are purely positional elements with no content 34 | whatsoever. You can think of the `Container` and the `Grid` as perfect examples. 35 | A container restricts content to a fixed size and a Grid allows component 36 | placement in a 2D space. They don't specify the content, rather how to display 37 | it. 38 | 39 | Here are some available layouts in action. 40 | 41 | ```jsx 42 | import Vue from 'vue'; 43 | 44 | import { library } from '@fortawesome/fontawesome-svg-core'; 45 | import { faTh, faTable } from '@fortawesome/free-solid-svg-icons'; 46 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; 47 | 48 | Vue.component('FontAwesomeIcon', FontAwesomeIcon); 49 | 50 | library.add(faTh, faTable); 51 | 52 | let spanSet = [12, 4, 3, 2]; 53 | let style = { 54 | backgroundColor: 'rgb(182, 43, 110)' 55 | }; 56 | 57 | let alphaSet = ['A', 'B', 'C', 'D', 'E']; 58 | let numSet = 5; 59 | 60 | 61 | 62 | 63 | 67 | 76 | 77 | 78 | 82 | 110 | 111 | 112 | ``` 113 | -------------------------------------------------------------------------------- /src/layouts/Table/Table.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 202 | -------------------------------------------------------------------------------- /src/layouts/Table/TableCell.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 71 | -------------------------------------------------------------------------------- /src/layouts/Tabs/Tab.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 42 | -------------------------------------------------------------------------------- /src/layouts/Tabs/Tabs.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta, Story, Preview } from '@storybook/addon-docs/blocks' 2 | import { figmaConfig } from '../../utils/helpers' 3 | 4 | import Tabs from '@/layouts/Tabs/Tabs' 5 | import Tab from '@/layouts/Tabs/Tab' 6 | 7 | 8 | 9 | # Tabs 10 | 11 | 12 | {{ 15 | components: { Tabs, Tab }, 16 | template: ` 17 | 18 | Music content. 19 | Pictures content. 20 | Videos content. 21 | Document content. 22 | ` 23 | }} 24 | 25 | -------------------------------------------------------------------------------- /src/layouts/Tabs/Tabs.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 81 | -------------------------------------------------------------------------------- /src/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "vue": "Vue", 3 | "vue_js": "Vue.js", 4 | "vo_cab_u_lar_y": "vo·cab·u·lar·y", 5 | "vocabulary": "Vocabulary", 6 | "creativecommons": "Creative Commons", 7 | "cc": "CC", 8 | "pronunciation": "vjuː və(ʊ)ˈkabjʊləri" 9 | } 10 | -------------------------------------------------------------------------------- /src/locales/hi.json: -------------------------------------------------------------------------------- 1 | { 2 | "vue": "व्यू", 3 | "vue_js": "व्यू.जे एस", 4 | "vo_cab_u_lar_y": "वो·कै·बु·ल·री", 5 | "vocabulary": "वोकैबुलरी", 6 | "creativecommons": "क्रिएटिव कॉमन्स", 7 | "cc": "सी सी", 8 | "pronunciation": "व्यू वोकैबुलरी" 9 | } 10 | -------------------------------------------------------------------------------- /src/mixins/branded.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the brand color for the component_ 5 | * 6 | * ∈ {`'blue'`, `'forest'`, `'gold'`, `'orange'`, `'tomato'`, `'turquoise'`, `'slate'`} 7 | */ 8 | brand: { 9 | type: String, 10 | validator: val => [ 11 | 'blue', 12 | 'forest', 13 | 'gold', 14 | 'orange', 15 | 'tomato', 16 | 'turquoise', 17 | 'slate' 18 | ].includes(val) 19 | } 20 | }, 21 | computed: { 22 | brandedClasses: function () { 23 | let classes = [] 24 | if (this.brand) { 25 | classes.push(`${this.brand}-branded`) 26 | } 27 | return classes 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/mixins/circleable.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _whether to change the shape of the component into a circle_ 5 | */ 6 | isCircular: { 7 | type: Boolean, 8 | default: false 9 | } 10 | }, 11 | computed: { 12 | circleableClasses: function () { 13 | return [ 14 | { 15 | 'circular': this.isCircular 16 | } 17 | ] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/mixins/colored.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the primary color for the component_ 5 | * 6 | * ∈ {`'red'`, `'pink'`, `'grape'`, `'violet'`, `'indigo'`, `'cyan'`, 7 | * `'teal'`, `'green'`, `'lime'`, `'yellow'`} 8 | * 9 | * If the color is not specified, a default one is chosen as described. 10 | */ 11 | color: { 12 | type: String, 13 | validator: val => [ 14 | 'red', 15 | 'pink', 16 | 'grape', 17 | 'violet', 18 | 'indigo', 19 | 'cyan', 20 | 'teal', 21 | 'green', 22 | 'lime', 23 | 'yellow' 24 | ].includes(val) 25 | }, 26 | /** 27 | * _the accentuating shade of the primary color to use_ 28 | * 29 | * ⩾ 0 and ⩽ 9 30 | * 31 | * If the shade is not specified, the darkest shade of color will be used. 32 | */ 33 | shade: { 34 | type: Number, 35 | default: 9, 36 | validator: val => val >= 0 && val <= 9 37 | } 38 | }, 39 | computed: { 40 | coloredClasses: function () { 41 | let classes = [] 42 | if (this.color) { 43 | classes.push(`${this.color}-colored`) 44 | } 45 | classes.push(`s${this.shade}-shaded`) // Classes cannot start with number 46 | return classes 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/mixins/indicating.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the state to indicate the component in_ 5 | * 6 | * ∈ {`'negative'`, `'positive'`, `'probably'`} 7 | */ 8 | indication: { 9 | type: String, 10 | validator: val => ['negative', 'positive', 'probably'].includes(val) 11 | } 12 | }, 13 | computed: { 14 | indicatingClasses: function () { 15 | let classes = [] 16 | if (this.indication) { 17 | classes.push(`${this.indication}-indicating`) 18 | } 19 | return classes 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/mixins/invertible.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _whether the component appears on a dark or non-white background_ 5 | * 6 | * This essentially negates all greyscale colors. 7 | */ 8 | isInverted: { 9 | type: Boolean, 10 | default: false 11 | } 12 | }, 13 | computed: { 14 | invertibleClasses: function () { 15 | return [ 16 | { 17 | 'inverted': this.isInverted 18 | } 19 | ] 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/mixins/joined.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the side on which the component is connected to other components_ 5 | * 6 | * ∈ {`'left'`, `'right'`, `'both'`} 7 | */ 8 | joinSide: { 9 | type: String, 10 | validator: val => [ 11 | 'left', 12 | 'right', 13 | 'both' 14 | ].includes(val) 15 | } 16 | }, 17 | computed: { 18 | joinClasses: function () { 19 | let classes = [] 20 | if (this.joinSide) { 21 | classes.push(`${this.joinSide}-joined`) 22 | } 23 | return classes 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/mixins/raisable.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _whether the component should appear raised by means of a shadow_ 5 | */ 6 | isRaised: { 7 | type: Boolean, 8 | default: false 9 | } 10 | }, 11 | computed: { 12 | raisableClasses: function () { 13 | return [ 14 | { 15 | 'raised': this.isRaised 16 | } 17 | ] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/mixins/rounded.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the amount of curvature on the vertices of the component_ 5 | * 6 | * ∈ {`'slight'`, `'complete'`} 7 | */ 8 | roundness: { 9 | type: String, 10 | validator: val => ['slight', 'complete'].includes(val) 11 | } 12 | }, 13 | computed: { 14 | roundedClasses: function () { 15 | let classes = [] 16 | if (this.roundness) { 17 | classes.push(`${this.roundness}ly-rounded`) 18 | } 19 | return classes 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/mixins/scaled.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the size of the component_ 5 | * 6 | * ∈ {`'small'`, `'normal'`, `'big'`, `'large'`, `'huge'`, `'enormous'`, 7 | * `'gigantic'`, `'mega'`} 8 | */ 9 | size: { 10 | type: String, 11 | default: 'normal', 12 | validator: val => [ 13 | 'small', 14 | 'normal', 15 | 'big', 16 | 'large', 17 | 'huge', 18 | 'enormous', 19 | 'gigantic', 20 | 'mega' 21 | ].includes(val) 22 | } 23 | }, 24 | computed: { 25 | scaledClasses: function () { 26 | let classes = [] 27 | if (this.size) { 28 | classes.push(`${this.size}-sized`) 29 | } 30 | return classes 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/mixins/simplified.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the amount of simplicity in the appearance of the component_ 5 | * 6 | * ∈ {`'slight'`, `'extreme'`} 7 | */ 8 | simplicity: { 9 | type: String, 10 | validator: val => ['slight', 'extreme'].includes(val) 11 | } 12 | }, 13 | computed: { 14 | simplifiedClasses: function () { 15 | let classes = [] 16 | if (this.simplicity) { 17 | classes.push(`${this.simplicity}ly-simple`) 18 | } 19 | return classes 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/mixins/toned.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _the shade of grey to use_ 5 | * 6 | * ⩾ 0 and ⩽ 9 7 | */ 8 | tone: { 9 | type: Number, 10 | validator: val => val >= 0 && val <= 9 11 | } 12 | }, 13 | computed: { 14 | tonedClasses: function () { 15 | let classes = [] 16 | if (this.tone) { 17 | classes.push(`t${this.tone}-toned`) // Classes cannot start with number 18 | } 19 | return classes 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/mixins/unactionable.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | /** 4 | * _whether to disable input on the component_ 5 | */ 6 | isDisabled: { 7 | type: Boolean, 8 | default: false 9 | }, 10 | /** 11 | * _whether to disable input on the component while preserving readability_ 12 | */ 13 | isReadOnly: { 14 | type: Boolean, 15 | default: false 16 | } 17 | }, 18 | computed: { 19 | unactionableClasses: function () { 20 | return [ 21 | { 22 | 'disabled': this.isDisabled, 23 | 'read-only': this.isReadOnly 24 | } 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/patterns/Footer/Footer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /src/patterns/Header/Header.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /src/patterns/Locale/Locale.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /src/utils/SlotRenderer/SlotRenderer.md: -------------------------------------------------------------------------------- 1 | For example usage, go through the source code of the components 2 | [Tabbed](#/Layouts/Tabbed) and [Navigation](#/Patterns/Navigation). 3 | 4 | Since the above table does not mention it, `SlotComponent` takes a `default` 5 | slot containing the content to show if the passed component (`component` prop) 6 | does not populate the passed slot (`name` prop). 7 | -------------------------------------------------------------------------------- /src/utils/SlotRenderer/SlotRenderer.vue: -------------------------------------------------------------------------------- 1 | 109 | -------------------------------------------------------------------------------- /src/utils/helpers.js: -------------------------------------------------------------------------------- 1 | import { config } from 'storybook-addon-designs' 2 | 3 | export const figmaConfig = (nodeId) => config({ 4 | type: 'figma', 5 | url: `https://www.figma.com/file/l4Mt3dn3Ndtrvrb4aLcwXI/Design-Library?node-id=${nodeId}` 6 | }) 7 | -------------------------------------------------------------------------------- /tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/unit/Dummy.spec.js: -------------------------------------------------------------------------------- 1 | describe('Dummy', () => { 2 | it('matches string with string', () => { 3 | expect('Hello World!').toContain('Hello') 4 | }) 5 | }) 6 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | let publicPath 2 | 3 | if (process.env.NODE_ENV === 'production') { 4 | publicPath = process.env.PUBLIC_PATH || '/vue-vocabulary' 5 | } else { 6 | publicPath = '/' 7 | } 8 | 9 | module.exports = { 10 | publicPath: publicPath, 11 | pluginOptions: { 12 | i18n: { 13 | locale: 'en', 14 | fallbackLocale: 'en', 15 | localeDir: 'locales', 16 | enableInSFC: true 17 | } 18 | }, 19 | chainWebpack: config => { 20 | config.module 21 | .rule('eslint') 22 | .exclude 23 | .add(/storybook\/generated-entry\.js/) 24 | } 25 | } 26 | --------------------------------------------------------------------------------