├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── RELEASE-TEMPLATE.md ├── .gitignore ├── LICENSE ├── README.md ├── app-extension ├── .editorconfig ├── .npmignore ├── LICENSE ├── README.md ├── jsconfig.json ├── package.json └── src │ ├── boot │ └── register.js │ └── index.js ├── docs ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── README.md ├── babel.config.js ├── build │ ├── flat-menu.js │ ├── markdown.js │ ├── md-loader-utils.js │ └── md-loader.js ├── jsconfig.json ├── package.json ├── public │ ├── _redirects │ ├── articles │ │ └── 2021-05-01_writing-your-first-article │ │ │ └── index.jpg │ ├── favicon.ico │ ├── icons │ │ ├── favicon-128x128.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ └── favicon-96x96.png │ └── q-icon-picker.png ├── quasar.conf.js ├── quasar.extensions.json ├── src-ssr │ ├── directives │ │ └── .gitkeep │ ├── middlewares │ │ ├── compression.js │ │ └── render.js │ └── ssr-flag.d.ts └── src │ ├── App.vue │ ├── assets │ ├── examples.js │ ├── get-meta.js │ ├── markdown-store.js │ ├── menu.js │ ├── page-utils.js │ ├── profile.png │ ├── quasar-logo-full.svg │ └── symbols.js │ ├── boot │ └── register.js │ ├── components │ ├── DisplayMac.vue │ ├── DocsMenu.js │ ├── DocsMenu.sass │ ├── EssentialLink.vue │ ├── LeftMenu.vue │ ├── MarkdownFooter.vue │ ├── MarkdownLink.vue │ ├── MarkdownNavBar.vue │ ├── MarkdownPage.vue │ ├── NavigationBar.vue │ ├── ToolbarContents.vue │ ├── getCategoryIndex.js │ └── page-parts │ │ ├── LandingPageContent.vue │ │ ├── apis │ │ └── QIconPickerJsonApi.vue │ │ └── releases │ │ ├── PackageReleases.vue │ │ ├── Releases.vue │ │ ├── md-table-parser.js │ │ └── sanitize.js │ ├── css │ ├── app.sass │ ├── markdown.sass │ ├── prism-theme.sass │ └── quasar.variables.sass │ ├── examples │ ├── Color.vue │ ├── CustomIconSet.vue │ ├── CustomNavigation.vue │ ├── Filter2.vue │ ├── Pagination.vue │ ├── PaginationColor.vue │ ├── PaginationCustom.vue │ ├── SelectedColor.vue │ ├── Size.vue │ ├── Tooltips.vue │ ├── UsingIconSlot.vue │ ├── UsingQInput.vue │ └── UsingQInputWithFilter.vue │ ├── index.template.html │ ├── layouts │ └── MainLayout.vue │ ├── pages │ ├── Error404.vue │ ├── Index.vue │ ├── all-about-qiconpicker │ │ ├── installation-types.md │ │ └── what-is-qiconpicker.md │ ├── contributing │ │ ├── bugs-and-feature-requests.md │ │ ├── call-to-action.md │ │ ├── components.md │ │ ├── documentation.md │ │ ├── overview.md │ │ └── sponsor.md │ ├── developing │ │ └── using-qiconpicker.md │ ├── help │ │ ├── contact-us.md │ │ └── faq.md │ ├── landing-page.md │ └── latest-news │ │ ├── changelog.md │ │ └── roadmap.md │ ├── router │ ├── index.js │ └── routes.js │ └── util │ └── getLocale.js ├── package.json └── ui ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── build ├── build.api.js ├── config.js ├── entry │ ├── index.cjs.js │ ├── index.esm.js │ └── index.umd.js ├── icons │ ├── build.all.js │ ├── build.bootstrap-icons.js │ ├── build.eva.js │ ├── build.fontawesome-v5.js │ ├── build.google.material-icons.js │ ├── build.ion.js │ ├── build.line-awesome.js │ ├── build.material-icons-base.js │ ├── build.mdi-v4.js │ ├── build.mdi-v5.js │ ├── build.mdi-v6.js │ └── build.themify.js ├── index.js ├── script.app-ext.js ├── script.clean.js ├── script.css.js ├── script.javascript.js ├── script.open-umd.js ├── script.version.js ├── utils.js └── version │ └── version-template.js ├── jsconfig.json ├── package.json ├── src ├── components │ ├── QIconPicker.js │ ├── QIconPicker.json │ ├── QIconPicker.sass │ └── icon-set │ │ ├── bootstrap-icons.js │ │ ├── eva-icons.js │ │ ├── fontawesome-v5.js │ │ ├── ionicons-v4.js │ │ ├── line-awesome.js │ │ ├── material-icons-outlined.js │ │ ├── material-icons-round.js │ │ ├── material-icons-sharp.js │ │ ├── material-icons.js │ │ ├── mdi-v4.js │ │ ├── mdi-v5.js │ │ ├── mdi-v6.js │ │ └── themify.js ├── index.cjs.js ├── index.esm.js ├── index.js ├── index.sass ├── index.umd.js ├── version.js └── vue-plugin.js ├── types └── types.d.ts └── umd-test.html /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [hawkeye64, rstoenescu] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | For a legitimate bug, in order to process faster, please go here https://codepen.io/Hawkeye64/pen/vYYYewG, fork the codepen, add code to reproduce the bug and submit link here (don't forget to save your codepen): 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Desktop (please complete the following information):** 29 | - OS: [e.g. iOS] 30 | - Browser [e.g. chrome, safari] 31 | - Version [e.g. 22] 32 | 33 | **Smartphone (please complete the following information):** 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/RELEASE-TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # QIconPicker v2.x.x 2 | 3 | ## What's Changed 4 | 5 | **Features:** 6 | 7 | **Fixes:** 8 | 9 | --- 10 | 11 | ## Installing 12 | 13 | ``` 14 | $ yarn add @quasar/quasar-ui-qiconpicker 15 | # or 16 | $ quasar ext add @quasar/qiconpicker 17 | ``` 18 | 19 | ## Documentation 20 | 21 | [QIconPicker v2 documentation](https://qiconpicker.netlify.app/) is now hosted by Netlify. Visit the documentation to get more information. The documentation is incomplete and is currently being updated. You can help out by PR-ing deficiencies. 22 | 23 | ## Donations 24 | 25 | QIconPicker is an open-source MIT licensed project that has been made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/hawkeye64). If you are interested in supporting this project, please consider: 26 | 27 | - [Becoming a sponsor on Github](https://github.com/users/hawkeye64/sponsorship) 28 | - [One-off donation via PayPal](https://paypal.me/hawkeye64) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .thumbs.db 3 | node_modules 4 | dist 5 | yarn.lock 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Editor directories and files 11 | .idea 12 | .vscode 13 | *.suo 14 | *.ntvs* 15 | *.njsproj 16 | *.sln 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Jeff Galbraith 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > If you are looking for QIconPicker that works with Quasar v1/Vue v2, then look into the [qv1 branch](https://github.com/quasarframework/quasar-ui-qiconpicker/tree/qv1). Documentation can be found [here](https://quasarframework.github.io/quasar-ui-qiconpicker). 2 | 3 | # QIconPicker (Vue v3 Plugin, UMD and Quasar v2 App Extension) 4 | 5 | ![](https://img.shields.io/npm/v/@quasar/quasar-ui-qiconpicker/next?label=@quasar/quasar-ui-qiconpicker) 6 | ![](https://img.shields.io/npm/v/@quasar/quasar-app-extension-qiconpicker/next?label=@quasar/quasar-app-extension-qiconpicker) 7 | [![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/quasarframework/app-extension-qiconpicker.svg)]() 8 | [![GitHub repo size in bytes](https://img.shields.io/github/repo-size/quasarframework/app-extension-qiconpicker.svg)]() 9 | 10 | ![QIconPicker](https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/dev/demo/public/q-icon-picker.png) 11 | 12 | # Structure 13 | 14 | - [/ui](ui) - standalone npm package (go here for more details) 15 | - [/app-extension](app-extension) - Quasar app extension 16 | - [/docs](https://github.com/quasarframework/quasar-ui-qiconpicker/tree/main/docs) - demo and examples 17 | - [Live Demo](https://qiconpicker.netlify.app/) 18 | 19 | # Demo Workflow 20 | 21 | If you fork or download this project, make sure you have the Quasar CLI globally installed: 22 | 23 | ``` 24 | $ npm i -g @quasar/cli 25 | or 26 | yarn global add @quasar/cli 27 | ``` 28 | 29 | The workflow to build the demo, on a fresh project, is as follows: 30 | 31 | ``` 32 | $ cd ui 33 | $ yarn 34 | $ yarn build 35 | $ cd ../docs 36 | $ yarn 37 | $ quasar dev 38 | ``` 39 | 40 | # Donate 41 | 42 | If you appreciate the work that went into this, please consider donating to [Quasar](https://donate.quasar.dev) or [Jeff](https://github.com/sponsors/hawkeye64). 43 | 44 | # License 45 | 46 | MIT (c) Jeff Galbraith 47 | -------------------------------------------------------------------------------- /app-extension/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /app-extension/.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .thumbs.db 3 | yarn.lock 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | .editorconfig 16 | .eslintignore 17 | .eslintrc.js 18 | -------------------------------------------------------------------------------- /app-extension/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Jeff Galbraith 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /app-extension/README.md: -------------------------------------------------------------------------------- 1 | # Quasar App Extension QIconPicker 2 | 3 | The **QIconPicker App Extension** allows you to seamlessly add the [QIconPicker](../ui) component into your Quasar application. It manages the boot file file and all other configuration for you. 4 | 5 | [![npm](https://img.shields.io/npm/v/@quasar/quasar-app-extension-qiconpicker.svg?label=@quasar/quasar-app-extension-qiconpicker)](https://www.npmjs.com/package/quasar-app-extension-qiconpicker) 6 | [![npm](https://img.shields.io/npm/dt/@quasar/quasar-app-extension-qiconpicker.svg)](https://www.npmjs.com/package/@quasar/quasar-app-extension-qiconpicker) 7 | 8 | ![QIconPicker](https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/dev/demo/public/q-icon-picker.png) 9 | 10 | # Install 11 | ```bash 12 | quasar ext add @quasar/qiconpicker 13 | ``` 14 | Quasar CLI will retrieve it from NPM and install the extension. 15 | 16 | # Uninstall 17 | ```bash 18 | quasar ext remove @quasar/qiconpicker 19 | ``` 20 | 21 | # Donate 22 | If you appreciate the work that went into this, please consider donating to [Quasar](https://donate.quasar.dev) or [Jeff](https://github.com/sponsors/hawkeye64). 23 | 24 | # License 25 | MIT (c) Jeff Galbraith 26 | -------------------------------------------------------------------------------- /app-extension/jsconfig.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "target": "es6" 6 | }, 7 | "exclude": ["node_modules"], 8 | "include": ["src/**/*"] 9 | } -------------------------------------------------------------------------------- /app-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@quasar/quasar-app-extension-qiconpicker", 3 | "version": "2.0.7", 4 | "description": "QIconPicker - A Quasar App Extension", 5 | "author": "Jeff Galbraith ", 6 | "license": "MIT", 7 | "main": "src/index.js", 8 | "scripts": { 9 | "lint": "eslint --ext .js,.vue src", 10 | "lint-fix": "eslint --ext .js,.vue src --fix" 11 | }, 12 | "funding": { 13 | "type": "github", 14 | "url": "https://github.com/sponsors/hawkeye64" 15 | }, 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "bugs": "https://github.com/quasarframework/quasar-ui-qiconpicker/issues", 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/quasarframework/quasar-ui-qiconpicker.git" 23 | }, 24 | "homepage": "https://github.com/quasarframework/quasar-ui-qiconpicker", 25 | "keywords": [ 26 | "quasar", 27 | "quasarframework", 28 | "app", 29 | "app extension", 30 | "extension", 31 | "icon picker" 32 | ], 33 | "dependencies": { 34 | "@quasar/quasar-ui-qiconpicker": "^2.0.7" 35 | }, 36 | "engines": { 37 | "node": ">= 10.0.0", 38 | "npm": ">= 5.6.0", 39 | "yarn": ">= 1.6.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app-extension/src/boot/register.js: -------------------------------------------------------------------------------- 1 | import { boot } from 'quasar/wrappers' 2 | import VuePlugin from '@quasar/quasar-ui-qiconpicker' 3 | 4 | export default boot(({ app }) => { 5 | app.use(VuePlugin) 6 | }) 7 | -------------------------------------------------------------------------------- /app-extension/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Quasar App Extension index/runner script 3 | * (runs on each dev/build) 4 | * 5 | * Docs: https://quasar.dev/app-extensions/development-guide/index-api 6 | * API: https://github.com/quasarframework/quasar/blob/master/app/lib/app-extension/IndexAPI.js 7 | */ 8 | 9 | function extendConf(conf, api) { 10 | // register our boot file 11 | conf.boot.push('~@quasar/quasar-app-extension-qiconpicker/src/boot/register.js') 12 | 13 | if (api.hasVite !== true) { 14 | // make sure app extension files & ui package gets transpiled 15 | conf.build.transpileDependencies.push(/quasar-app-extension-qiconpicker[\\/]src/) 16 | conf.build.transpileDependencies.push(/quasar-ui-qiconpicker[\\/]src/) 17 | } 18 | 19 | // make sure the stylesheet goes through webpack to avoid SSR issues 20 | conf.css.push('~@quasar/quasar-ui-qiconpicker/src/index.sass') 21 | } 22 | 23 | module.exports = function (api) { 24 | // Quasar compatibility check; you may need 25 | // hard dependencies, as in a minimum version of the "quasar" 26 | // package or a minimum version of "@quasar/app" CLI 27 | api.compatibleWith('quasar', '^2.0.0') 28 | 29 | if (api.hasVite === true) { 30 | api.compatibleWith('@quasar/app-vite', '^1.0.0 || ^2.0.0 || ^2.0.0-alpha.1') 31 | } else { 32 | // should be "@quasar/app-webpack" but that is not backward compatible 33 | api.compatibleWith('@quasar/app', '^3.0.0 || ^4.0.0 || ^4.0.0-alpha.1') 34 | } 35 | 36 | api.compatibleWith('@quasar/extras', '^1.10.0') // needed for latest font and svg support 37 | 38 | // Uncomment the line below if you provide a JSON API for your component 39 | api.registerDescribeApi('QIconPicker', '~@quasar/quasar-ui-qiconpicker/dist/api/QIconPicker.json') 40 | 41 | // We extend /quasar.conf.js 42 | api.extendQuasarConf(extendConf) 43 | } 44 | -------------------------------------------------------------------------------- /docs/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /docs/.eslintignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /src-bex/www 3 | /src-capacitor 4 | /src-cordova 5 | /.quasar 6 | /node_modules 7 | .eslintrc.js 8 | -------------------------------------------------------------------------------- /docs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy 3 | // This option interrupts the configuration hierarchy at this file 4 | // Remove this if you have an higher level ESLint config file (it usually happens into a monorepos) 5 | root: true, 6 | 7 | parserOptions: { 8 | parser: '@babel/eslint-parser', 9 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features 10 | sourceType: 'module', // Allows for the use of imports 11 | requireConfigFile: false 12 | }, 13 | 14 | env: { 15 | browser: true, 16 | es6: true 17 | }, 18 | 19 | // Rules order is important, please avoid shuffling them 20 | extends: [ 21 | // Base ESLint recommended rules 22 | // 'eslint:recommended', 23 | 24 | // Uncomment any of the lines below to choose desired strictness, 25 | // but leave only one uncommented! 26 | // See https://eslint.vuejs.org/rules/#available-rules 27 | // 'plugin:vue/vue3-essential' // Priority A: Essential (Error Prevention) 28 | // 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability) 29 | 'plugin:vue/vue3-recommended' // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) 30 | ], 31 | 32 | plugins: [ 33 | // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file 34 | // required to lint *.vue files 35 | 'vue' 36 | ], 37 | 38 | globals: { 39 | $q: 'readonly', 40 | $router: 'readonly', 41 | ga: 'readonly', // Google Analytics 42 | cordova: 'readonly', 43 | __statics: 'readonly', 44 | __QUASAR_SSR__: 'readonly', 45 | __QUASAR_SSR_SERVER__: 'readonly', 46 | __QUASAR_SSR_CLIENT__: 'readonly', 47 | __QUASAR_SSR_PWA__: 'readonly', 48 | process: 'readonly', 49 | Capacitor: 'readonly', 50 | chrome: 'readonly', 51 | }, 52 | 53 | // add your custom rules here 54 | rules: { 55 | 'brace-style': [ 'error', 'stroustrup', { allowSingleLine: true } ], 56 | 'prefer-const': 'error', 57 | 'prefer-promise-reject-errors': 'off', 58 | 'multiline-ternary': 'off', 59 | 'no-prototype-builtins': 'off', 60 | 'no-case-declarations': 'off', 61 | 'generator-star-spacing': 'off', 62 | 'arrow-parens': 'off', 63 | 'object-property-newline': 'off', 64 | 'one-var': 'off', 65 | 'no-void': 'off', 66 | 'no-lone-blocks': 'error', 67 | 'no-unused-expressions': [ 'error', { allowTernary: true, "allowShortCircuit": true } ], 68 | 'no-useless-concat': 'error', 69 | 'no-useless-return': 'error', 70 | 'no-unneeded-ternary': 'error', 71 | 'no-confusing-arrow': [ 'error', { allowParens: true } ], 72 | 'operator-linebreak': [ 'error', 'before' ], 73 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 74 | 75 | 'array-bracket-spacing': [ 'error', 'always', { singleValue: false } ], 76 | 'object-curly-spacing': [ 'error', 'always' ], 77 | 'computed-property-spacing': [ 'error', 'always' ], 78 | 'template-curly-spacing': [ 'error', 'always' ], 79 | 80 | 'import/first': 'off', 81 | // 'import/named': 'error', 82 | // 'import/namespace': 'error', 83 | // 'import/default': 'error', 84 | // 'import/export': 'error', 85 | 'import/extensions': 'off', 86 | 'import/no-unresolved': 'off', 87 | 'import/no-extraneous-dependencies': 'off', 88 | 89 | 'import/no-webpack-loader-syntax': 'off', 90 | 91 | 'vue/singleline-html-element-content-newline': 'off', 92 | 'vue/no-multiple-template-root': 'off', 93 | 'vue/multi-word-component-names': 'off', 94 | 'vue/require-default-prop': 'off', 95 | 'vue/no-v-html': 'off', 96 | 'vue/require-prop-types': 'off', 97 | 'vue/valid-v-slot': 'off', 98 | 99 | // allow console.log during production for demo purposes 100 | // 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 101 | 'no-console': 'off' 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .thumbs.db 3 | node_modules 4 | 5 | # Quasar core related directories 6 | .quasar 7 | /dist 8 | 9 | # Cordova related directories and files 10 | /src-cordova/node_modules 11 | /src-cordova/platforms 12 | /src-cordova/plugins 13 | /src-cordova/www 14 | 15 | # Capacitor related directories and files 16 | /src-capacitor/www 17 | /src-capacitor/node_modules 18 | 19 | # BEX related directories and files 20 | /src-bex/www 21 | /src-bex/js/core 22 | 23 | # Log files 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # Editor directories and files 29 | .idea 30 | *.suo 31 | *.ntvs* 32 | *.njsproj 33 | *.sln 34 | -------------------------------------------------------------------------------- /docs/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | plugins: [ 5 | // to edit target browsers: use "browserslist" field in package.json 6 | require('autoprefixer') 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Dev app (playground) 2 | Adding .vue files to src/pages/ will auto-add them to the Index page list. 3 | 4 | # Build docs 5 | From docs folder run `yarn build:site`. This will create some yarn links. 6 | Then run `quasar dev` 7 | -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = api => { 3 | return { 4 | presets: [ 5 | [ 6 | '@quasar/babel-preset-app', 7 | api.caller(caller => caller && caller.target === 'node') 8 | ? { targets: { node: 'current' } } 9 | : {} 10 | ] 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/build/flat-menu.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join 2 | 3 | const menu = require('../src/assets/menu') 4 | const flatMenu = {} 5 | const prefix = join(__dirname, '../src/pages') 6 | 7 | let prev 8 | 9 | function menuWalk (node, path, parentName) { 10 | const newPath = path + (node.path ? `/${ node.path }` : '') 11 | 12 | if (node.children !== void 0) { 13 | node.children.forEach(n => { 14 | menuWalk(n, newPath, node.name) 15 | }) 16 | } 17 | else if (!node.external) { 18 | const current = { 19 | name: node.name, 20 | category: parentName, 21 | path: newPath 22 | } 23 | 24 | if (prev !== void 0) { 25 | prev.next = { 26 | name: current.name, 27 | category: current.category, 28 | path: current.path 29 | } 30 | current.prev = { 31 | name: prev.name, 32 | category: prev.category, 33 | path: prev.path 34 | } 35 | } 36 | 37 | flatMenu[ join(prefix, newPath + '.md') ] = current 38 | prev = current 39 | } 40 | } 41 | 42 | menu.forEach(n => { 43 | menuWalk(n, '', null) 44 | }) 45 | 46 | // console.log('flatmenu', flatMenu) 47 | 48 | module.exports.flatMenu = flatMenu 49 | module.exports.convertToRelated = function (entry) { 50 | const menu = flatMenu[ join(prefix, entry + '.md') ] 51 | 52 | if (!menu) { 53 | // console.error('Erroneous related link: ' + prefix + entry) 54 | console.error('Erroneous related link: ' + entry) 55 | return {} 56 | } 57 | 58 | return { 59 | name: menu.name, 60 | category: menu.category, 61 | path: menu.path 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/build/md-loader-utils.js: -------------------------------------------------------------------------------- 1 | const 2 | matter = require('gray-matter'), 3 | toml = require('toml') 4 | 5 | function getComponentsImport (comp) { 6 | return comp.map(c => { 7 | const parts = c.split('/') 8 | return `import ${ parts[ parts.length - 1 ] } from 'components/page-parts/${ c }.vue'\n` 9 | }).join('') 10 | } 11 | 12 | function getComponentsDeclaration (comp) { 13 | const list = comp.map(c => { 14 | const parts = c.split('/') 15 | return parts[ parts.length - 1 ] 16 | }).join(',') 17 | 18 | return `components: { ${ list } },` 19 | } 20 | 21 | module.exports.getVueComponent = function (rendered, data, toc) { 22 | return ` 23 | 26 | ` 46 | } 47 | 48 | module.exports.parseFrontMatter = function (content) { 49 | return matter(content, { 50 | excerpt_separator: '', 51 | engines: { 52 | toml: toml.parse.bind(toml), 53 | excerpt: false 54 | } 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /docs/build/md-loader.js: -------------------------------------------------------------------------------- 1 | const 2 | LRU = require('lru-cache'), 3 | hash = require('hash-sum') 4 | 5 | const 6 | md = require('./markdown.js'), 7 | { convertToRelated, flatMenu } = require('./flat-menu') 8 | 9 | const { 10 | getVueComponent, 11 | parseFrontMatter 12 | } = require('./md-loader-utils') 13 | 14 | const cache = new LRU({ max: 1000 }) 15 | 16 | module.exports = function (source) { 17 | const key = hash(source) 18 | const hit = cache.get(key) 19 | 20 | if (hit) { 21 | return hit 22 | } 23 | 24 | const { data, content } = parseFrontMatter(source) 25 | 26 | data.title = data.title || 'Generic Page' 27 | 28 | if (data.related !== void 0) { 29 | data.related = data.related.map(entry => convertToRelated(entry)) 30 | } 31 | 32 | if (flatMenu[ this.resourcePath ]) { 33 | const { prev, next } = flatMenu[ this.resourcePath ] 34 | 35 | if (prev !== void 0 || next !== void 0) { 36 | data.nav = [] 37 | } 38 | 39 | if (prev !== void 0) { 40 | data.nav.push({ ...prev, dir: 'left' }) 41 | } 42 | if (next !== void 0) { 43 | data.nav.push({ ...next, dir: 'right' }) 44 | } 45 | } 46 | 47 | // console.log('data', data) 48 | 49 | // md.$data = { 50 | // toc: [] 51 | // } 52 | 53 | const { rendered, tocData } = md.render(content) 54 | const toc = tocData 55 | // const toc = data.toc !== false 56 | // ? md.$data.toc 57 | // : [] 58 | 59 | // md.$data = {} 60 | 61 | const res = getVueComponent( 62 | rendered, 63 | data, 64 | JSON.stringify(toc) 65 | ) 66 | 67 | cache.set(key, res) 68 | 69 | return res 70 | } 71 | -------------------------------------------------------------------------------- /docs/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "src/*": [ 6 | "src/*" 7 | ], 8 | "app/*": [ 9 | "*" 10 | ], 11 | "components/*": [ 12 | "src/components/*" 13 | ], 14 | "layouts/*": [ 15 | "src/layouts/*" 16 | ], 17 | "pages/*": [ 18 | "src/pages/*" 19 | ], 20 | "assets/*": [ 21 | "src/assets/*" 22 | ], 23 | "boot/*": [ 24 | "src/boot/*" 25 | ], 26 | "vue$": [ 27 | "node_modules/vue/dist/vue.runtime.esm-bundler.js" 28 | ] 29 | } 30 | }, 31 | "exclude": [ 32 | "dist", 33 | ".quasar", 34 | "node_modules" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.1", 4 | "description": "QIconPicker Docs", 5 | "productName": "Quasar App", 6 | "author": "Jeff Galbraith ", 7 | "contributors": [ 8 | { 9 | "name": "Christian Behon", 10 | "email": "christian.behon@knusperleicht.at", 11 | "url": "https://knusperleicht.at" 12 | } 13 | ], 14 | "private": true, 15 | "scripts": { 16 | "lint": "eslint --ext .js,.vue ./", 17 | "lint-fix": "eslint --ext .js,.vue src --fix", 18 | "build:site": "cd ../ui && yarn && yarn build && yarn link && cd ../docs && yarn link @quasar/quasar-ui-qiconpicker && quasar build", 19 | "dev": "quasar dev", 20 | "dev:ssr": "quasar dev -m ssr", 21 | "dev:ios": "quasar dev -m ios", 22 | "dev:android": "quasar dev -m android", 23 | "dev:electron": "quasar dev -m electron" 24 | }, 25 | "dependencies": { 26 | "@quasar/extras": "^1.16.4", 27 | "@quasar/quasar-ui-qiconpicker": "./ui", 28 | "core-js": "^3.30.2", 29 | "quasar": "^2.12.0", 30 | "quasar-ui-example-viewer": "^2.0.0-alpha.9", 31 | "quasar-ui-json-api-viewer": "^2.0.0-alpha.6", 32 | "vue": "^3.3.4", 33 | "vue-router": "^4.2.2" 34 | }, 35 | "devDependencies": { 36 | "@babel/core": "^7.22.1", 37 | "@babel/eslint-parser": "^7.21.8", 38 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 39 | "@babel/preset-env": "^7.22.4", 40 | "@quasar/app": "^3.3.3", 41 | "babel-loader": "9.1.2", 42 | "eslint": "^8.41.0", 43 | "eslint-config-standard": "^17.1.0", 44 | "eslint-plugin-import": "^2.27.5", 45 | "eslint-plugin-node": "^11.1.0", 46 | "eslint-plugin-promise": "^6.1.1", 47 | "eslint-plugin-vue": "^9.14.1", 48 | "eslint-webpack-plugin": "^4.0.1", 49 | "gray-matter": "^4.0.3", 50 | "markdown-it": "^13.0.1", 51 | "markdown-it-abbr": "^1.0.4", 52 | "markdown-it-container": "^3.0.0", 53 | "markdown-it-deflist": "^2.1.0", 54 | "markdown-it-emoji": "^2.0.2", 55 | "markdown-it-footnote": "^3.0.3", 56 | "markdown-it-imsize": "^2.0.1", 57 | "markdown-it-ins": "^3.0.1", 58 | "markdown-it-mark": "^3.0.1", 59 | "markdown-it-sub": "^1.0.0", 60 | "markdown-it-sup": "^1.0.0", 61 | "markdown-it-task-lists": "^2.1.1", 62 | "prismjs": "^1.29.0", 63 | "raw-loader": "^4.0.2", 64 | "toml": "^3.0.0", 65 | "ware-loader": "^0.2.4" 66 | }, 67 | "browserslist": [ 68 | "last 10 Chrome versions", 69 | "last 10 Firefox versions", 70 | "last 10 Edge versions", 71 | "last 10 Safari versions", 72 | "last 10 Android versions", 73 | "last 10 ChromeAndroid versions", 74 | "last 10 FirefoxAndroid versions", 75 | "last 10 iOS versions" 76 | ], 77 | "engines": { 78 | "node": ">= 12.22.1", 79 | "npm": ">= 7.10.0", 80 | "yarn": ">= 1.22.5" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /docs/public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /docs/public/articles/2021-05-01_writing-your-first-article/index.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/public/articles/2021-05-01_writing-your-first-article/index.jpg -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/icons/favicon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/public/icons/favicon-128x128.png -------------------------------------------------------------------------------- /docs/public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/public/icons/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/public/icons/favicon-96x96.png -------------------------------------------------------------------------------- /docs/public/q-icon-picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/public/q-icon-picker.png -------------------------------------------------------------------------------- /docs/quasar.extensions.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /docs/src-ssr/directives/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/src-ssr/directives/.gitkeep -------------------------------------------------------------------------------- /docs/src-ssr/middlewares/compression.js: -------------------------------------------------------------------------------- 1 | import compression from 'compression' 2 | import { ssrMiddleware } from 'quasar/wrappers' 3 | 4 | export default ssrMiddleware(({ app }) => { 5 | app.use( 6 | compression({ threshold: 0 }) 7 | ) 8 | }) 9 | -------------------------------------------------------------------------------- /docs/src-ssr/middlewares/render.js: -------------------------------------------------------------------------------- 1 | import { ssrMiddleware } from 'quasar/wrappers' 2 | 3 | // This middleware should execute as last one 4 | // since it captures everything and tries to 5 | // render the page with Vue 6 | 7 | export default ssrMiddleware(({ app, resolve, render, serve }) => { 8 | // we capture any other Express route and hand it 9 | // over to Vue and Vue Router to render our page 10 | app.get(resolve.urlPath('*'), (req, res) => { 11 | res.setHeader('Content-Type', 'text/html') 12 | 13 | render(/* the ssrContext: */ { req, res }) 14 | .then(html => { 15 | // now let's send the rendered html to the client 16 | res.send(html) 17 | }) 18 | .catch(err => { 19 | // oops, we had an error while rendering the page 20 | 21 | // we were told to redirect to another URL 22 | if (err.url) { 23 | if (err.code) { 24 | res.redirect(err.code, err.url) 25 | } 26 | else { 27 | res.redirect(err.url) 28 | } 29 | } 30 | else if (err.code === 404) { 31 | // hmm, Vue Router could not find the requested route 32 | 33 | // Should reach here only if no "catch-all" route 34 | // is defined in /src/routes 35 | res.status(404).send('404 | Page Not Found') 36 | } 37 | else if (process.env.DEV) { 38 | // well, we treat any other code as error; 39 | // if we're in dev mode, then we can use Quasar CLI 40 | // to display a nice error page that contains the stack 41 | // and other useful information 42 | 43 | // serve.error is available on dev only 44 | serve.error({ err, req, res }) 45 | } 46 | else { 47 | // we're in production, so we should have another method 48 | // to display something to the client when we encounter an error 49 | // (for security reasons, it's not ok to display the same wealth 50 | // of information as we do in development) 51 | 52 | // Render Error Page on production or 53 | // create a route (/src/routes) for an error page and redirect to it 54 | res.status(500).send('500 | Internal Server Error') 55 | } 56 | }) 57 | }) 58 | }) 59 | -------------------------------------------------------------------------------- /docs/src-ssr/ssr-flag.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED, 3 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING 4 | import "quasar/dist/types/feature-flag"; 5 | 6 | declare module "quasar/dist/types/feature-flag" { 7 | interface QuasarFeatureFlags { 8 | ssr: true; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 30 | -------------------------------------------------------------------------------- /docs/src/assets/examples.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Export files list for /pages folder 3 | */ 4 | 5 | function kebabCase (str) { 6 | const result = str.replace( 7 | /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, 8 | match => '-' + match.toLowerCase() 9 | ) 10 | return (str[ 0 ] === str[ 0 ].toUpperCase()) 11 | ? result.substring(1) 12 | : result 13 | } 14 | 15 | function slugify (str) { 16 | return encodeURIComponent(String(str).trim().replace(/\s+/g, '-')) 17 | } 18 | 19 | export default require.context('../examples', true, /^\.\/.*\.vue$/) 20 | .keys() 21 | .map(page => page.slice(2).replace('.vue', '')) 22 | .filter(page => page !== 'Index' && page !== 'Error404') 23 | .map(page => { 24 | return { 25 | component: () => import(`../examples/${ page }.vue`), 26 | name: page, 27 | title: page + '.vue', 28 | path: slugify(kebabCase(page)) 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /docs/src/assets/get-meta.js: -------------------------------------------------------------------------------- 1 | export default function (title, desc) { 2 | return { 3 | title: { 4 | name: 'title', 5 | content: title 6 | }, 7 | ogTitle: { 8 | name: 'og:title', 9 | content: title 10 | }, 11 | twitterTitle: { 12 | name: 'twitter:title', 13 | content: title 14 | }, 15 | 16 | description: { 17 | name: 'description', 18 | content: desc 19 | }, 20 | ogDesc: { 21 | name: 'og:description', 22 | content: desc 23 | }, 24 | twitterDesc: { 25 | name: 'twitter:description', 26 | content: desc 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/src/assets/markdown-store.js: -------------------------------------------------------------------------------- 1 | import { inject, provide, reactive } from 'vue' 2 | import { markdownStoreKey } from './symbols.js' 3 | 4 | export function useMarkdownStore () { 5 | return inject(markdownStoreKey) 6 | } 7 | 8 | export function provideMarkdownStore () { 9 | const store = { 10 | toc: [], 11 | title: 'Simplified icon picker for your Quasar apps' 12 | } 13 | 14 | provide( 15 | markdownStoreKey, 16 | process.env.SERVER === true ? store : reactive(store) 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /docs/src/assets/menu.js: -------------------------------------------------------------------------------- 1 | const biTwitter = 'M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z|0 0 16 16' 2 | const biGithub = 'M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z|0 0 16 16' 3 | const mdiCharity = 'M12.75,3.94C13.75,3.22 14.91,2.86 16.22,2.86C16.94,2.86 17.73,3.05 18.59,3.45C19.45,3.84 20.13,4.3 20.63,4.83C21.66,6.11 22.09,7.6 21.94,9.3C21.78,11 21.22,12.33 20.25,13.27L12.66,20.86C12.47,21.05 12.23,21.14 11.95,21.14C11.67,21.14 11.44,21.05 11.25,20.86C11.06,20.67 10.97,20.44 10.97,20.16C10.97,19.88 11.06,19.64 11.25,19.45L15.84,14.86C16.09,14.64 16.09,14.41 15.84,14.16C15.59,13.91 15.36,13.91 15.14,14.16L10.55,18.75C10.36,18.94 10.13,19.03 9.84,19.03C9.56,19.03 9.33,18.94 9.14,18.75C8.95,18.56 8.86,18.33 8.86,18.05C8.86,17.77 8.95,17.53 9.14,17.34L13.73,12.75C14,12.5 14,12.25 13.73,12C13.5,11.75 13.28,11.75 13.03,12L8.44,16.64C8.25,16.83 8,16.92 7.73,16.92C7.45,16.92 7.21,16.83 7,16.64C6.8,16.45 6.7,16.22 6.7,15.94C6.7,15.66 6.81,15.41 7.03,15.19L11.63,10.59C11.88,10.34 11.88,10.11 11.63,9.89C11.38,9.67 11.14,9.67 10.92,9.89L6.28,14.5C6.06,14.7 5.83,14.81 5.58,14.81C5.3,14.81 5.06,14.71 4.88,14.5C4.69,14.3 4.59,14.06 4.59,13.78C4.59,13.5 4.69,13.27 4.88,13.08C7.94,10 9.83,8.14 10.55,7.45L14.11,10.97C14.5,11.34 14.95,11.53 15.5,11.53C16.2,11.53 16.75,11.25 17.16,10.69C17.44,10.28 17.54,9.83 17.46,9.33C17.38,8.83 17.17,8.41 16.83,8.06L12.75,3.94M14.81,10.27L10.55,6L3.47,13.08C2.63,12.23 2.15,10.93 2.04,9.16C1.93,7.4 2.41,5.87 3.47,4.59C4.66,3.41 6.08,2.81 7.73,2.81C9.39,2.81 10.8,3.41 11.95,4.59L16.22,8.86C16.41,9.05 16.5,9.28 16.5,9.56C16.5,9.84 16.41,10.08 16.22,10.27C16.03,10.45 15.8,10.55 15.5,10.55C15.23,10.55 15,10.45 14.81,10.27V10.27Z' 4 | 5 | const menu = [ 6 | { 7 | name: 'All about QIconPicker', 8 | path: 'all-about-qiconpicker', 9 | expanded: false, 10 | children: [ 11 | { 12 | name: 'What is QIconPicker', 13 | path: 'what-is-qiconpicker' 14 | }, 15 | { 16 | name: 'Installation types', 17 | path: 'installation-types' 18 | } 19 | ] 20 | }, 21 | { 22 | name: 'Developing', 23 | path: 'developing', 24 | expanded: false, 25 | children: [ 26 | { 27 | name: 'Using QIconPicker', 28 | path: 'using-qiconpicker' 29 | } 30 | ] 31 | }, 32 | { 33 | name: 'Contributing', 34 | path: 'contributing', 35 | expanded: false, 36 | children: [ 37 | { 38 | name: 'Overview', 39 | path: 'overview' 40 | }, 41 | { 42 | name: 'Call to action', 43 | path: 'call-to-action' 44 | }, 45 | { 46 | name: 'Bugs and feature requests', 47 | path: 'bugs-and-feature-requests' 48 | }, 49 | { 50 | name: 'Documentation', 51 | path: 'documentation' 52 | }, 53 | { 54 | name: 'Components', 55 | path: 'components' 56 | }, 57 | { 58 | name: 'Sponsor', 59 | path: 'sponsor', 60 | rightIcon: mdiCharity, 61 | rightIconColor: 'red-8' 62 | } 63 | ] 64 | }, 65 | { 66 | name: 'Latest news', 67 | path: 'latest-news', 68 | expanded: false, 69 | children: [ 70 | { 71 | name: 'Changelog', 72 | path: 'changelog' 73 | }, 74 | { 75 | name: 'Roadmap', 76 | path: 'roadmap' 77 | } 78 | ] 79 | }, 80 | { 81 | name: 'Help', 82 | path: 'help', 83 | expanded: false, 84 | children: [ 85 | { 86 | name: 'GitHub', 87 | external: true, 88 | path: 'https://github.com/quasarframework/quasar-ui-qiconpicker', 89 | rightIcon: biGithub 90 | }, 91 | { 92 | name: 'Twitter', 93 | external: true, 94 | path: 'https://twitter.com/jgalbraith64', 95 | rightIcon: biTwitter 96 | }, 97 | { 98 | name: 'FAQ', 99 | path: 'faq' 100 | }, 101 | { 102 | name: 'Contact us', 103 | path: 'contact-us' 104 | } 105 | ] 106 | } 107 | ] 108 | 109 | // export default menu 110 | module.exports = menu 111 | module.exports.default = menu 112 | -------------------------------------------------------------------------------- /docs/src/assets/page-utils.js: -------------------------------------------------------------------------------- 1 | import { Notify } from 'quasar' 2 | 3 | export function copyToClipboard (text) { 4 | const textArea = document.createElement('textarea') 5 | textArea.className = 'fixed-top' 6 | textArea.value = text 7 | document.body.appendChild(textArea) 8 | textArea.focus() 9 | textArea.select() 10 | 11 | document.execCommand('copy') 12 | document.body.removeChild(textArea) 13 | } 14 | 15 | export function copyHeading (id) { 16 | const text = window.location.origin + window.location.pathname + '#' + id 17 | const el = document.getElementById(id) 18 | 19 | if (el) { 20 | el.id = '' 21 | } 22 | 23 | if ('replaceState' in history) { 24 | history.replaceState(history.state, '', `${ location.pathname }#${ id }`) 25 | } 26 | else { 27 | window.location.hash = '#' + id 28 | } 29 | 30 | if (el) { 31 | setTimeout(() => { 32 | el.id = id 33 | }, 300) 34 | } 35 | 36 | copyToClipboard(text) 37 | 38 | Notify.create({ 39 | message: 'Anchor has been copied to clipboard.', 40 | position: 'top', 41 | color: 'white', 42 | textColor: 'primary', 43 | actions: [{ icon: 'cancel', color: 'red-8', dense: true, round: true }], 44 | timeout: 2000 45 | }) 46 | } 47 | 48 | // eslint-disable-next-line 49 | const specialRE = /[\s·/_\\,:;\.\(\)\[\]]+/g 50 | const andRE = /&/g 51 | const nonWordRE = /[^\w-]+/g 52 | const multipleDashRE = /--+/g 53 | 54 | export function slugify (str) { 55 | return String(str).toLowerCase() 56 | .replace(specialRE, '-') 57 | .replace(andRE, '-and-') 58 | .replace(nonWordRE, '') 59 | .replace(multipleDashRE, '-') 60 | } 61 | -------------------------------------------------------------------------------- /docs/src/assets/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quasarframework/quasar-ui-qiconpicker/b7e18632794226fdc790ff11a0748c2d4e37a6f4/docs/src/assets/profile.png -------------------------------------------------------------------------------- /docs/src/assets/symbols.js: -------------------------------------------------------------------------------- 1 | const hasSymbol = typeof Symbol === 'function' 2 | && typeof Symbol.toStringTag === 'symbol' 3 | 4 | export const markdownStoreKey = hasSymbol === true 5 | ? Symbol('_markdown_store_') 6 | : '_markdown_store_' 7 | -------------------------------------------------------------------------------- /docs/src/boot/register.js: -------------------------------------------------------------------------------- 1 | import { boot } from 'quasar/wrappers' 2 | import JsonApiViewer from 'quasar-ui-json-api-viewer/src/components/JsonApiViewer' 3 | import MarkdownPage from '../components/MarkdownPage.vue' 4 | import MarkdownLink from '../components/MarkdownLink.vue' 5 | import ExampleViewer, { setDefaults } from 'quasar-ui-example-viewer/src' 6 | import { version } from '@quasar/quasar-ui-qiconpicker/src/version.js' 7 | 8 | setDefaults({ 9 | locationUrl: 'https://github.com/quasarframework/quasar-ui-qiconpicker/tree/next/docs/src/examples', 10 | jsPaths: [`https://cdn.jsdelivr.net/npm/@quasar/quasar-ui-qiconpicker@${ version }/dist/index.umd.min.js`], 11 | cssPaths: [ 12 | `https://cdn.jsdelivr.net/npm/@quasar/quasar-ui-qiconpicker@${ version }/dist/index.min.css`, 13 | 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.0/css/all.css' 14 | ], 15 | noEdit: true 16 | }) 17 | 18 | export default boot(({ app }) => { 19 | app.use(ExampleViewer) 20 | app.component('JsonApiViewer', JsonApiViewer) 21 | app.component('MarkdownPage', MarkdownPage) 22 | app.component('MarkdownLink', MarkdownLink) 23 | }) 24 | -------------------------------------------------------------------------------- /docs/src/components/DisplayMac.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 115 | -------------------------------------------------------------------------------- /docs/src/components/DocsMenu.js: -------------------------------------------------------------------------------- 1 | import { 2 | QExpansionItem, 3 | QList, 4 | QItem, 5 | QItemSection, 6 | QIcon, 7 | QBadge, 8 | Ripple 9 | } from 'quasar' 10 | 11 | import { biCaretDown, biCaretDownFill } from '@quasar/extras/bootstrap-icons' 12 | import { h, ref, watch, onMounted, onBeforeUpdate, withDirectives } from 'vue' 13 | import { useRoute } from 'vue-router' 14 | 15 | import Menu from 'assets/menu.js' 16 | import './DocsMenu.sass' 17 | 18 | function getParentVm (vm) { 19 | if (vm.$parent !== void 0 && vm.$parent !== null) { 20 | return vm.$parent 21 | } 22 | 23 | vm = vm.$.parent 24 | 25 | while (vm !== void 0 && vm !== null) { 26 | if (vm.proxy !== void 0 && vm.proxy !== null) { 27 | return vm.proxy 28 | } 29 | 30 | vm = vm.parent 31 | } 32 | } 33 | 34 | export default { 35 | name: 'AppMenu', 36 | 37 | setup () { 38 | const $route = useRoute() 39 | const routePath = $route.path 40 | 41 | const rootRef = ref(null) 42 | 43 | watch(() => $route.path, val => { 44 | showMenu(childRefs[ val ]) 45 | }) 46 | 47 | onMounted(() => { 48 | // needed if using different layouts or 49 | // User navigated here via an external link (ie: Discord) 50 | showMenu(childRefs[ $route.path ]) 51 | }) 52 | 53 | let childRefs = [] 54 | 55 | onBeforeUpdate(() => { 56 | childRefs = [] 57 | }) 58 | 59 | /** 60 | * Recursive method to find the QExpansionItem parent 61 | * @param {any} vm The Vue node 62 | * @returns 63 | */ 64 | function showMenu (vm) { 65 | if (vm !== void 0 && vm !== rootRef.value) { 66 | if(vm.show === void 0 && vm.$parent !== void 0) { 67 | const parent = getParentVm(vm) 68 | if (parent !== void 0) { 69 | showMenu(parent) 70 | return 71 | } 72 | } 73 | // eslint-disable-next-line no-unused-expressions 74 | vm.show !== void 0 && vm.show() 75 | } 76 | } 77 | 78 | function getDrawerMenu (menu, path, level) { 79 | if (menu.children !== void 0) { 80 | return h( 81 | QExpansionItem, 82 | { 83 | class: 'non-selectable', 84 | ref: vm => { if (vm) { childRefs[ path ] = vm } }, 85 | key: `${ menu.name }-${ path }`, 86 | label: menu.name, 87 | dense: true, 88 | icon: menu.icon, 89 | contentInsetLevel: level > 0 ? 0.5 : 0.25, 90 | expandIcon: level > 0 ? biCaretDownFill : biCaretDown, 91 | defaultOpened: menu.expanded || routePath.startsWith(path + '/'), 92 | expandSeparator: true, 93 | denseToggle: level > 0 94 | }, 95 | () => menu.children.map(item => getDrawerMenu( 96 | item, 97 | item.path !== void 0 98 | ? item.path.charAt(0) === '/' 99 | ? item.path 100 | : path + '/' + item.path 101 | : '', 102 | level + 1 103 | )) 104 | ) 105 | } 106 | 107 | const props = { 108 | ref: vm => { if (vm) { childRefs[ path ] = vm } }, 109 | key: path, 110 | class: 'non-selectable', 111 | to: path, 112 | dense: level > 0 113 | // insetLevel: level > 1 ? 0 : level / 2.5 114 | // insetLevel: level > 1 ? 0.8 : level 115 | } 116 | 117 | // eslint-disable-next-line no-unused-expressions 118 | menu.external === true && Object.assign(props, { 119 | to: void 0, 120 | clickable: true, 121 | tag: 'a', 122 | href: menu.path, 123 | target: '_blank', 124 | rel: 'noopener' 125 | }) 126 | 127 | const child = [] 128 | 129 | // eslint-disable-next-line no-unused-expressions 130 | menu.icon !== void 0 && child.push( 131 | h(QItemSection, { 132 | avatar: true 133 | }, () => h(QIcon, { name: menu.icon, color: (menu.iconColor ? menu.iconColor : undefined) })) 134 | ) 135 | 136 | child.push( 137 | h(QItemSection, () => menu.name) 138 | ) 139 | 140 | // eslint-disable-next-line no-unused-expressions 141 | menu.rightIcon !== void 0 && child.push( 142 | h(QItemSection, { 143 | avatar: true 144 | }, () => h(QIcon, { name: menu.rightIcon, color: (menu.rightIconColor ? menu.rightIconColor : undefined) })) 145 | ) 146 | 147 | // eslint-disable-next-line no-unused-expressions 148 | menu.badge !== void 0 && menu.rightIcon === void 0 && child.push( 149 | h(QItemSection, { 150 | side: true 151 | }, () => h(QBadge, { label: menu.badge, color: (menu.badgeColor ? menu.badgeColor : undefined) })) 152 | ) 153 | 154 | return withDirectives( 155 | h(QItem, props, () => child), 156 | [[Ripple]] 157 | ) 158 | } 159 | 160 | return () => h(QList, { ref: rootRef, class: 'app-menu', dense: true }, () => Menu.map( 161 | item => getDrawerMenu(item, '/' + item.path, 0) 162 | )) 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /docs/src/components/DocsMenu.sass: -------------------------------------------------------------------------------- 1 | .docs-menu 2 | .q-item 3 | font-size: 12px 4 | 5 | > .q-item, > .q-expansion-item > .q-expansion-item__container > .q-item 6 | padding-top: 6px 7 | padding-bottom: 6px 8 | 9 | .q-item__section--avatar 10 | color: $primary 11 | .q-expansion-item__toggle-icon 12 | color: $grey-5 13 | 14 | .q-expansion-item--expanded > div > .q-item 15 | > .q-item__section--main 16 | color: $primary 17 | font-weight: 500 18 | > .q-item__section--side .q-expansion-item__toggle-icon 19 | color: $primary 20 | 21 | .q-expansion-item__content .q-item 22 | border-radius: 0 10px 10px 0 23 | margin-right: 12px 24 | 25 | .q-item.q-router-link--active 26 | background: scale-color($primary, $lightness: 90%) 27 | -------------------------------------------------------------------------------- /docs/src/components/EssentialLink.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 52 | -------------------------------------------------------------------------------- /docs/src/components/LeftMenu.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 134 | -------------------------------------------------------------------------------- /docs/src/components/MarkdownFooter.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 58 | 75 | -------------------------------------------------------------------------------- /docs/src/components/MarkdownLink.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 40 | 41 | 59 | -------------------------------------------------------------------------------- /docs/src/components/MarkdownNavBar.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 89 | 90 | 114 | -------------------------------------------------------------------------------- /docs/src/components/MarkdownPage.vue: -------------------------------------------------------------------------------- 1 | 74 | 75 | 134 | 135 | 182 | -------------------------------------------------------------------------------- /docs/src/components/NavigationBar.vue: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /docs/src/components/ToolbarContents.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 85 | -------------------------------------------------------------------------------- /docs/src/components/getCategoryIndex.js: -------------------------------------------------------------------------------- 1 | import { h } from 'vue' 2 | import { QIcon } from 'quasar' 3 | 4 | import { farFileAlt, fasFolderOpen } from '@quasar/extras/fontawesome-v5' 5 | 6 | import MarkdownPage from './MarkdownPage.vue' 7 | import MarkdownLink from './MarkdownLink.vue' 8 | 9 | export default function (title, links) { 10 | function getContent () { 11 | return links.map(link => { 12 | return h('div', { class: 'markdown-page-listing' }, [ 13 | h(QIcon, { 14 | name: link.page === true ? farFileAlt : fasFolderOpen 15 | }), 16 | 17 | h(MarkdownLink, { to: link.to }, () => link.title) 18 | ]) 19 | }) 20 | } 21 | 22 | return { 23 | name: 'MarkdownListingPage', 24 | 25 | setup () { 26 | return () => h(MarkdownPage, { 27 | title, 28 | noEdit: true, 29 | metaTitle: title, 30 | metaDesc: `List of pages under the '${ title }' section` 31 | }, getContent) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/src/components/page-parts/LandingPageContent.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 63 | 64 | 90 | -------------------------------------------------------------------------------- /docs/src/components/page-parts/apis/QIconPickerJsonApi.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /docs/src/components/page-parts/releases/PackageReleases.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 150 | 151 | 167 | -------------------------------------------------------------------------------- /docs/src/components/page-parts/releases/Releases.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 160 | 161 | 166 | -------------------------------------------------------------------------------- /docs/src/components/page-parts/releases/md-table-parser.js: -------------------------------------------------------------------------------- 1 | function getTable (rows) { 2 | const header = rows[ 0 ].split('|') 3 | .filter(col => col) 4 | .map(col => `${ col.trim() }`) 5 | .join('') 6 | 7 | const body = rows.slice(2).map(row => '' 8 | + row.split('|') 9 | .filter(col => col) 10 | .map(col => `${ col.trim() }`) 11 | .join('') 12 | + '' 13 | ).join('') 14 | 15 | return '
' 18 | + `${ header }` 19 | + `${ body }
` 20 | } 21 | 22 | export default raw => { 23 | let content = '' 24 | let tableRows = [] 25 | 26 | for (const row of raw.split('\n')) { 27 | if (row.indexOf('|') > -1) { 28 | tableRows.push(row.trim()) 29 | } 30 | else { 31 | if (tableRows.length > 0) { 32 | content += getTable(tableRows) + '\n' 33 | tableRows = [] 34 | } 35 | content += row + '\n' 36 | } 37 | } 38 | 39 | if (tableRows.length > 0) { 40 | content += getTable(tableRows) + '\n' 41 | } 42 | 43 | return content 44 | } 45 | -------------------------------------------------------------------------------- /docs/src/components/page-parts/releases/sanitize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sanitizer which filters a set of whitelisted tags, attributes and css. 3 | * For now, the whitelist is small but can be easily extended. 4 | * 5 | * @param bool whether to escape or strip undesirable content. 6 | * @param map of allowed tag-attribute-attribute-parsers. 7 | * @param array of allowed css elements. 8 | * @param array of allowed url scheme 9 | */ 10 | function HtmlWhitelistedSanitizer (escape, tags, css, urls) { 11 | this.escape = escape 12 | this.allowedTags = tags 13 | this.allowedCss = css 14 | 15 | // Use the browser to parse the input but create a new HTMLDocument. 16 | // This won't evaluate any potentially dangerous scripts since the element 17 | // isn't attached to the window's document. It also won't cause img.src to 18 | // preload images. 19 | // 20 | // To be extra cautious, you can dynamically create an iframe, pass the 21 | // input to the iframe and get back the sanitized string. 22 | this.doc = document.implementation.createHTMLDocument() 23 | 24 | if (urls == null) { 25 | urls = [ 'http://', 'https://' ] 26 | } 27 | 28 | if (this.allowedTags == null) { 29 | // Configure small set of default tags 30 | const unconstrainted = function (x) { 31 | return x 32 | } 33 | const globalAttributes = { 34 | dir: unconstrainted, 35 | lang: unconstrainted, 36 | title: unconstrainted 37 | } 38 | const urlSanitizer = HtmlWhitelistedSanitizer.makeUrlSanitizer(urls) 39 | this.allowedTags = { 40 | a: HtmlWhitelistedSanitizer.mergeMap(globalAttributes, { 41 | download: unconstrainted, 42 | href: urlSanitizer, 43 | hreflang: unconstrainted, 44 | ping: urlSanitizer, 45 | rel: unconstrainted, 46 | target: unconstrainted, 47 | type: unconstrainted 48 | }), 49 | img: HtmlWhitelistedSanitizer.mergeMap(globalAttributes, { 50 | alt: unconstrainted, 51 | height: unconstrainted, 52 | src: urlSanitizer, 53 | width: unconstrainted 54 | }), 55 | p: globalAttributes, 56 | div: globalAttributes, 57 | span: globalAttributes, 58 | br: globalAttributes, 59 | b: globalAttributes, 60 | i: globalAttributes, 61 | u: globalAttributes 62 | } 63 | } 64 | if (this.allowedCss == null) { 65 | // Small set of default css properties 66 | this.allowedCss = [ 'border', 'margin', 'padding' ] 67 | } 68 | } 69 | 70 | HtmlWhitelistedSanitizer.makeUrlSanitizer = function (allowedUrls) { 71 | return function (str) { 72 | if (!str) { 73 | return '' 74 | } 75 | for (const i in allowedUrls) { 76 | if (str.startsWith(allowedUrls[ i ])) { 77 | return str 78 | } 79 | } 80 | return '' 81 | } 82 | } 83 | 84 | HtmlWhitelistedSanitizer.mergeMap = function (/* ... */) { 85 | const r = {} 86 | for (const arg in arguments) { 87 | for (const i in arguments[ arg ]) { 88 | r[ i ] = arguments[ arg ][ i ] 89 | } 90 | } 91 | return r 92 | } 93 | 94 | HtmlWhitelistedSanitizer.prototype.sanitizeString = function (input) { 95 | const div = this.doc.createElement('div') 96 | div.innerHTML = input 97 | 98 | // Return the sanitized version of the node. 99 | return this.sanitizeNode(div).innerHTML 100 | } 101 | 102 | HtmlWhitelistedSanitizer.prototype.sanitizeNode = function (node) { 103 | // Note:
can have its nodeName overridden by a child node. It's 104 | // not a big deal here, so we can punt on this. 105 | const nodeName = node.nodeName.toLowerCase() 106 | if (nodeName === '#text') { 107 | // text nodes are always safe 108 | return node 109 | } 110 | if (nodeName === '#comment') { 111 | // always strip comments 112 | return this.doc.createTextNode('') 113 | } 114 | if (this.allowedTags[ nodeName ] === void 0) { 115 | // this node isn't allowed 116 | if (this.escape) { 117 | return this.doc.createTextNode(node.outerHTML) 118 | } 119 | return this.doc.createTextNode('') 120 | } 121 | 122 | // create a new node 123 | const copy = this.doc.createElement(nodeName) 124 | 125 | // copy the whitelist of attributes using the per-attribute sanitizer 126 | for (let nAttr = 0; nAttr < node.attributes.length; nAttr++) { 127 | const attr = node.attributes.item(nAttr).name 128 | if (this.allowedTags[ nodeName ][ attr ] !== void 0) { 129 | const sanitizer = this.allowedTags[ nodeName ][ attr ] 130 | copy.setAttribute(attr, sanitizer(node.getAttribute(attr))) 131 | } 132 | } 133 | // copy the whitelist of css properties 134 | for (const css in this.allowedCss) { 135 | copy.style[ this.allowedCss[ css ] ] = node.style[ this.allowedCss[ css ] ] 136 | } 137 | 138 | // recursively sanitize child nodes 139 | while (node.childNodes.length > 0) { 140 | const child = node.removeChild(node.childNodes[ 0 ]) 141 | copy.appendChild(this.sanitizeNode(child)) 142 | } 143 | return copy 144 | } 145 | 146 | export default function runSanitizer (html) { 147 | const parser = new HtmlWhitelistedSanitizer(true) 148 | return parser.sanitizeString(html) 149 | } 150 | -------------------------------------------------------------------------------- /docs/src/css/prism-theme.sass: -------------------------------------------------------------------------------- 1 | .token.comment, 2 | .token.block-comment, 3 | .token.prolog, 4 | .token.doctype, 5 | .token.cdata 6 | color: #7D8B99 7 | 8 | .token 9 | &.punctuation 10 | color: #5F6364 11 | 12 | &.important 13 | font-weight: normal 14 | 15 | &.bold 16 | font-weight: bold 17 | 18 | &.italic 19 | font-style: italic 20 | 21 | &.entity 22 | cursor: help 23 | 24 | .token.property, 25 | .token.tag, 26 | .token.boolean, 27 | .token.number, 28 | .token.function-name, 29 | .token.constant, 30 | .token.symbol, 31 | .token.deleted 32 | color: #c92c2c 33 | 34 | .token.selector, 35 | .token.attr-name, 36 | .token.string, 37 | .token.char, 38 | .token.function, 39 | .token.builtin, 40 | .token.inserted 41 | color: #2f9c0a 42 | 43 | .token.operator 44 | color: #ff2211 45 | 46 | .token.entity, 47 | .token.url, 48 | .token.variable 49 | color: #a67f59 50 | 51 | .token.atrule, 52 | .token.attr-value, 53 | .token.keyword, 54 | .token.class-name 55 | color: #1990b8 56 | 57 | .token.regex, 58 | .token.important 59 | color: #e90 60 | 61 | .language-css .token.string, 62 | .style .token.string 63 | color: #a67f59 64 | background: rgba(255, 255, 255, 0.5) 65 | 66 | .namespace 67 | opacity: .7 68 | 69 | .token.tab:not(:empty):before, 70 | .token.cr:before, 71 | .token.lf:before 72 | color: #e0d7d1 73 | 74 | -------------------------------------------------------------------------------- /docs/src/css/quasar.variables.sass: -------------------------------------------------------------------------------- 1 | // Quasar Sass (& SCSS) Variables 2 | // -------------------------------------------------- 3 | // To customize the look and feel of this app, you can override 4 | // the Sass/SCSS variables found in Quasar's source Sass/SCSS files. 5 | 6 | // Check documentation for full list of Quasar variables 7 | 8 | // Your own variables (that are declared here) and Quasar's own 9 | // ones will be available out of the box in your .vue/.scss/.sass files 10 | 11 | // It's highly recommended to change the default colors 12 | // to match your app's branding. 13 | // Tip: Use the "Theme Builder" on Quasar's documentation website. 14 | 15 | $primary : #1976D2 16 | $secondary : #26A69A 17 | $accent : #9C27B0 18 | 19 | $dark : #1D1D1D 20 | 21 | $positive : #21BA45 22 | $negative : #C10015 23 | $info : #31CCEC 24 | $warning : #F2C037 25 | -------------------------------------------------------------------------------- /docs/src/examples/Color.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 40 | -------------------------------------------------------------------------------- /docs/src/examples/CustomIconSet.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 50 | -------------------------------------------------------------------------------- /docs/src/examples/CustomNavigation.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 84 | -------------------------------------------------------------------------------- /docs/src/examples/Filter2.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 47 | -------------------------------------------------------------------------------- /docs/src/examples/Pagination.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 46 | -------------------------------------------------------------------------------- /docs/src/examples/PaginationColor.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 52 | -------------------------------------------------------------------------------- /docs/src/examples/PaginationCustom.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 48 | -------------------------------------------------------------------------------- /docs/src/examples/SelectedColor.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 40 | -------------------------------------------------------------------------------- /docs/src/examples/Size.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 39 | -------------------------------------------------------------------------------- /docs/src/examples/Tooltips.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 39 | -------------------------------------------------------------------------------- /docs/src/examples/UsingIconSlot.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 60 | 93 | 94 | -------------------------------------------------------------------------------- /docs/src/examples/UsingQInput.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 61 | 62 | 68 | -------------------------------------------------------------------------------- /docs/src/examples/UsingQInputWithFilter.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 75 | -------------------------------------------------------------------------------- /docs/src/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= productName %> 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/src/pages/Error404.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 35 | -------------------------------------------------------------------------------- /docs/src/pages/Index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /docs/src/pages/all-about-qiconpicker/what-is-qiconpicker.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: What is QIconPicker 3 | desc: Simplfied qiconpicker 4 | keys: All about QIconPicker 5 | related: 6 | - /contributing/bugs-and-feature-requests 7 | - /contributing/components 8 | - /contributing/documentation 9 | - /contributing/sponsor 10 | --- 11 | ::: warning 12 | Please note that the codepen links, in the documentation examples, do not work at this time. 13 | 14 | And, if you're looking to help out, check out our [Call to action](/contributing/call-to-action) in the **Contributing** section. 15 | ::: 16 | 17 | ## Everything you need for a complete solution 18 | 19 | QIconPicker is an icon picker for your Quasar application. It allows you to have an icon selector embedded in your app. It uses a Quasar Icon Set or you can pass in an array of objects defining the icons to be displayed. 20 | 21 | ## Features 22 | 23 | - Add filter for searchable icons 24 | - Tooltips 25 | - Show icons in pop up 26 | - Customize navigation: 27 | - Show/hide navigation 28 | - Customize navigation 29 | (nextPage, lastPage, firstPage, nextPage, isFirstPage, isLastPage) 30 | - Support for custom icons 31 | - Support multiple fonts: 32 | - material-icons 33 | - material-icons-outlined 34 | - material-icons-round 35 | - material-icons-sharp 36 | - ionicons-v4 37 | - mdi-v4 38 | - mdi-v5 39 | - mdi-v6 40 | - fontawesome-v5 41 | - line-awesome 42 | - eva-icons 43 | - themify 44 | - bootstrap-icons 45 | -------------------------------------------------------------------------------- /docs/src/pages/contributing/bugs-and-feature-requests.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bugs and Feature Requests 3 | desc: 4 | keys: Contributing 5 | related: 6 | - /contributing/sponsor 7 | --- 8 | 9 | ## Checking for known issues 10 | 11 | ### GitHub 12 | 13 | We use GitHub to track our bugs. If you have a bug to report or wish to request a new feature, please check the [existing issues](https://github.com/quasarframework/quasar-ui-qiconpicker/issues) before opening a new one. There may already be something similar in the works. 14 | 15 | ### QIconPicker website 16 | 17 | Please take some time to explore the content on this website before opening an issue. The site is comprehensive and most guidelines and components are well documented. 18 | 19 | ## Creating an issue 20 | 21 | Report bugs, request features and leave feedback with a [GitHub issue](https://github.com/quasarframework/quasar-ui-qiconpicker/issues). 22 | 23 | ## GitHub pull requests 24 | 25 | If you have a specific fix or contribution, start by generating a pull request in the appropriate [QIconPicker repo](https://github.com/quasarframework/quasar-ui-qiconpicker/pulls). 26 | 27 | ## Requests for comment 28 | 29 | For changes that are larger in scale, an RFC (request for comment) may be appropriate. You can do that in the [QIconPicker discussions](https://github.com/quasarframework/quasar-ui-qiconpicker/discussions). 30 | 31 | ## Need more help? 32 | 33 | If you have more questions about issues or requesting features, there are multiple ways to reach us at [Contact us](/help/contact-us). 34 | -------------------------------------------------------------------------------- /docs/src/pages/contributing/call-to-action.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Call to action 3 | desc: Things that need help from the community 4 | keys: Contributing 5 | related: 6 | - /contributing/overview 7 | - /contributing/sponsor 8 | --- 9 | 10 | ## Helping out 11 | 12 | This **Call to action** page is where items can be listed where community involvement will be greatly appreciated. In this respect, so that more time can be devoted to the components and not the docs site. If you take something on, please coordinate in the [Discussions](https://github.com/quasarframework/quasar-ui-qiconpicker/discussions) area so there are not duplicated efforts. 13 | 14 | ### Docs site 15 | 16 | The Docs site has several empty pages that need to be filled in. If you think you are up to it, pick one and help out. 17 | 18 | ### Testing 19 | 20 | It'd be very welcomed if someone could write up tests for the UI component. 21 | -------------------------------------------------------------------------------- /docs/src/pages/contributing/components.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Components 3 | desc: How to contribute to components 4 | keys: Contributing 5 | related: 6 | - /contributing/overview 7 | - /contributing/sponsor 8 | --- 9 | 10 | ## Design 11 | 12 | You do not have to be a developer to contribute to a new QIconPicker component. You can also design one and either core developers will work on it or the community will get involved. 13 | ## Parts of a component contribution 14 | 15 | Component contributions ideally include all of the following parts. 16 | 17 | 1. **A rationale** 18 | Explain how your component will add value to the system. QIconPicker serves the widest possible range of products, and contributions that increase the scope of the system are more likely to be accepted. Be sure to include any user experience and interaction descriptions. 19 | 20 | 2. **A design spec** 21 | Create sizing and styling annotations for all aspects of the component. This spec should provide a developer with everything they need to create the design in code. 22 | 23 | 3. **Code documentation** 24 | We recommend reading through existing code documentation on this site for inspiration. 25 | 26 | ## First steps to contributing 27 | 28 | To contribute a component to QIconPicker, start by opening a [GitHub Issue](https://github.com/quasarframework/quasar-ui-qiconpicker/issues). Include a detailed description in which you: 29 | 30 | - Explain the rationale 31 | - Detail the intended behavior 32 | - Clarify whether it’s a variation of an existing component, or a new asset 33 | - Include mockups of any fidelity (optional) 34 | - Include any inspirations from other products (optional) 35 | 36 | This issue will be the staging ground for the contribution and an opportunity for the community to weigh in with any suggestions. We encourage you to surface work in progress. Someone in the community may be working on the same component and interested in collaborating with you. 37 | -------------------------------------------------------------------------------- /docs/src/pages/contributing/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Documentation 3 | desc: Contribute to the Documentation 4 | keys: Contributing 5 | related: 6 | - /contributing/overview 7 | - /contributing/sponsor 8 | --- 9 | 10 | You can contribute to the content on the QIconPicker site in a few different ways. Choose the way that works best for you. 11 | 12 | ## Editing pages 13 | 14 | The easiest was to edit a page is with the ++Edit this page on GitHub++ link that appears on the bottom of almost all pages on this site. The link opens a specific GitHub page where you can edit the content and then propose the change with a Pull Request. 15 | 16 | Alternatively, you can fork the QIconPicker repo, make your changes and generate a Pull Request. 17 | 18 | ## Using markdown 19 | 20 | The site is written using a syntax called [markdown](https://en.wikipedia.org/wiki/Markdown). If you are unfamiliar with this syntax, it is quite easily learned. 21 | 22 | ## Guidelines for writing content 23 | 24 | Please keep this in mind when writing content for QIconPicker: 25 | 26 | - Aim for a friendly tone and encouragement of others. 27 | - Speak directly to the user. You can use the second person pronoun ("you"). 28 | - Keep sentences and paragraphs short and focused. 29 | - Be clear and concise by removing unnecessary words. The more concise the text, the easier it is for all users to understand. 30 | -------------------------------------------------------------------------------- /docs/src/pages/contributing/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | desc: Innovation through collaboration 4 | keys: Contributing 5 | related: 6 | - /contributing/sponsor 7 | --- 8 | 9 | Interested in contributing to QIconPicker? Here's how you can contribute: 10 | 11 | ## Introduction 12 | 13 | QIconPicker is free to use (MIT License) for anybody building a web-based product or website. The QIconPicker community is working to make it better. Contributors like ++you++ help make QIconPicker great! We are happy to see you here. 14 | 15 | Contributions are not limited to code. We also encourage feedback, documentation, new design, and tools. And, we also encourage [sponsorship](/contributing/sponsor), especially if you are using QIconPicker in a business endeavor. 16 | 17 | All you need is a [GitHub account](https://github.com/join) to get started. 18 | 19 | ## Working in the open 20 | 21 | QIconPicker lives on [GitHub](https://github.com/quasarframework/quasar-ui-qiconpicker). All work, discussion, issues, bugs, features, improvements, and comments happen right out in the open where everyone can see. 22 | 23 | If you’re looking for something that we don’t have, or you notice something could be improved, you have two options: 24 | 25 | 1. Open an issue for the request. We’ll review the issue and get back to you with next steps. If we decide the request should be part of our pipeline, we’ll add it to our roadmap. There are never timeline guarantees for requests, but we’ll do our best to give you an estimate. 26 | 27 | 2. Begin the work yourself and contribute it back to QIconPicker. We appreciate completed contributions but also works-in-progress. You’re welcome to open an issue to surface your work and we’ll weigh in and help where we can. 28 | 29 | Regardless of how you choose to contribute, we encourage you to open an issue as early as possible in the process. 30 | 31 | If working with GitHub sounds like a lot, check out this [free video series](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github). 32 | 33 | ## Innovation through collaboration 34 | 35 | Please take time to read this [excellent article](https://blogs.vmware.com/opensource/2020/12/01/why-companies-contribute-to-open-source/). 36 | -------------------------------------------------------------------------------- /docs/src/pages/contributing/sponsor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sponsor 3 | desc: About sponsoring QIconPicker 4 | keys: Contributing 5 | related: 6 | - /contributing/overview 7 | --- 8 | 9 | ## Introduction 10 | 11 | My name is Jeff Galbraith (also known as @Hawkeye64). I have been programming since 1988, mostly in C++ and then web development. I have worked for companies such as Honeywell, Microsoft, and Vulcan. 12 | 13 | At my current position, I write software that detects pipeline leaks using a combination of proprietary software with AI and ML. 14 | 15 | In my spare time, I am a core member of the [Quasar Framework](https://quasar.dev) team, and I am heavily involved in making UI Components and App Extensions. You may have heard of some of them: 16 | - [QCalendar](https://github.com/quasarframework/quasar-ui-qcalendar) 17 | - [QMediaPlayer](https://github.com/quasarframework/quasar-ui-qmediaplayer) 18 | - [QMarkdown](https://github.com/quasarframework/quasar-ui-qmarkdown) 19 | - [QIconPicker](https://github.com/quasarframework/quasar-ui-qiconpicker) 20 | - and many more. 21 | 22 | I am also the creator and maintainer of the [**eslint-plugin-quasar**](https://github.com/quasarframework/eslint-plugin-quasar). 23 | 24 | ## Sponsorship 25 | 26 | I am a big believer in free and open-source (FOSS), and at the same time, I am a big supporter of sustainability. It's nice to get something for free. But, if you are using someone else's work to further your own work, and getting paid for that work, then you should consider paying, in all fairness, those that are part of your "supply chain". 27 | 28 | FOSS is always fraught with sustainability concerns. Socially, allowing so few people to perform so much work for so little compensation (or none at all) is inappropriate and does not scale. From a business perspective, it's poor practice to rely upon suppliers who may burn out and disappear at any moment. This does nothing good for the longevity prospects of your organization and dramatically increases its risk profile. 29 | 30 | Proprietary software is incredibly expensive, less flexible, leads to vendor lock-in, and is at least as likely to disappear without notice. [90% of software startups fail](https://s3.amazonaws.com/startupcompass-public/StartupGenomeReport2_Why_Startups_Fail_v2.pdf), taking their products and their code with them. The high cost, low innovation, and equal risk of mortality for proprietary software make it a less appealing solution when considering the longevity and sustainability of your own company. Free and open-source solutions are simply the better option. 31 | 32 | There are several ways to sustain FOSS: 33 | 1. Financial backing 34 | 2. Contributing 35 | a. Reporting bugs 36 | b. Requesting features 37 | c. Fixing bugs 38 | d. Adding features 39 | e. Community involvement 40 | 41 | Pick one that works well with you. 42 | 43 | For businesses, I highly encourage you to pick #1. Many hours have gone into QIconPicker. That's time and money you saved from hiring a developer and writing such a component yourself. 44 | 45 | For individuals and hobbiests, I encourage you more on the contributions-side of things (#2), but if you can, then #1 is also a good option. Small amounts by large numbers of people do add up. 46 | 47 | 1. Sign up for a monthly contribution: [GitHub Sponsorship](https://github.com/sponsors/hawkeye64) 48 | 49 | 2. Make a one-off contribution: [PayPal](https://paypal.me/hawkeye64) 50 | -------------------------------------------------------------------------------- /docs/src/pages/developing/using-qiconpicker.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using QIconPicker 3 | desc: How to use QIconPicker 4 | keys: developing 5 | components: 6 | - apis/QIconPickerJsonApi 7 | --- 8 | ## API 9 | 10 | 11 | ## QIconPicker Examples 12 | ### Color 13 | 18 | 19 | ### Custom Icon Set 20 | 25 | 26 | ### Custom Navigation 27 | 32 | 33 | ### Filter2 34 | 39 | 40 | ### Pagination 41 | 46 | 47 | ### Pagination Color 48 | 53 | 54 | ### Pagination Custom 55 | 60 | 61 | 62 | ### Selected Color 63 | 68 | 69 | 70 | ### Size 71 | 76 | 77 | ### Tooltips 78 | 83 | 84 | ### Using Icon Slot 85 | 90 | 91 | ### Using QInput 92 | 97 | 98 | ### Using QInput With Filter 99 | 104 | -------------------------------------------------------------------------------- /docs/src/pages/help/contact-us.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contact Us 3 | desc: Contacting us 4 | keys: Help 5 | --- 6 | 7 | Have a question about QIconPicker? We're here to help. Before you start, be sure to check the following resources to see if your topic has already been covered. 8 | 9 | ## Check existing resources 10 | 11 | ### QIconPicker GitHub issues 12 | 13 | As a first step, it's always good to search open and closed issues on the QIconPicker [GitHub repo](https://github.com/quasarframework/quasar-ui-qiconpicker/tree/next). 14 | 15 | ### QIconPicker GitHub discussions 16 | 17 | Don't forget to look into the [GitHub Discussions](https://github.com/quasarframework/quasar-ui-qiconpicker/discussions). 18 | 19 | ### Frequently asked questions 20 | 21 | Answers to the most common questions regarding QIconPicker can be found in the [QIconPicker FAQ](/help/faq). 22 | 23 | ## Provide a suggestion/contribution 24 | 25 | ### GitHub issues 26 | 27 | File on the [GitHub Issues](https://github.com/quasarframework/quasar-ui-qiconpicker/issues) location. 28 | 29 | ### GitHub pull requests (PR) 30 | 31 | If you have a specific fix or contribution, you can generate a pull request on the [QIconPicker repo](https://github.com/quasarframework/quasar-ui-qiconpicker/tree/next). Make sure to use the `next` branch for QIconPicker v2.x+ 32 | 33 | ## Start a discussion 34 | 35 | ### GitHub discussions 36 | 37 | If it's not an issue, bug, or feature request, you can use the [GitHub Discussions](https://github.com/quasarframework/quasar-ui-qiconpicker/discussions) to ask questions. 38 | 39 | ### Discord 40 | 41 | Use the [Quasar Discord](https://chat.quasar.dev) and head to the `#app-extensions` channel. 42 | 43 | ### Twitter 44 | 45 | The creator/maintainer of QIconPicker can be contacted on Twitter: [@jgalbraith64](https://twitter.com/jgalbraith64). 46 | -------------------------------------------------------------------------------- /docs/src/pages/help/faq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FAQ 3 | desc: Tips and Tricks as contributed by the community. 4 | keys: Help 5 | --- 6 | 7 | 8 | This is an accumulation of Tips and Tricks as contributed by the community. -------------------------------------------------------------------------------- /docs/src/pages/landing-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: QIconPicker » IconPicker simplified 3 | desc: Simple qiconpicker for your Quasar apps 4 | keys: Help 5 | noEdit: true, 6 | components: 7 | - LandingPageContent 8 | --- 9 | 10 | -------------------------------------------------------------------------------- /docs/src/pages/latest-news/changelog.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Changelog 3 | desc: The latest QIconPicker releases 4 | keys: latest-news 5 | components: 6 | - releases/Releases 7 | --- 8 | 9 | -------------------------------------------------------------------------------- /docs/src/pages/latest-news/roadmap.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Roadmap 3 | desc: The future of QIconPicker 4 | keys: latest-news 5 | --- 6 | Information to come after QIconPicker v2.0.0 release. 7 | -------------------------------------------------------------------------------- /docs/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { route } from 'quasar/wrappers' 2 | import { createRouter, createMemoryHistory, createWebHistory, createWebHashHistory } from 'vue-router' 3 | import routes from './routes' 4 | 5 | /* 6 | * If not building with SSR mode, you can 7 | * directly export the Router instantiation; 8 | * 9 | * The function below can be async too; either use 10 | * async/await or return a Promise which resolves 11 | * with the Router instance. 12 | */ 13 | 14 | export default route(function (/* { store, ssrContext } */) { 15 | const createHistory = process.env.SERVER 16 | ? createMemoryHistory 17 | : process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory 18 | 19 | const Router = createRouter({ 20 | scrollBehavior (to, from, savedPosition) { 21 | return new Promise(resolve => { 22 | setTimeout(() => { 23 | if (to.hash !== undefined && to.hash !== '' && document) { 24 | const el = document.getElementById(to.hash.substring(1)) 25 | 26 | if (el !== null) { 27 | resolve({ left: 0, top: el.offsetTop - el.scrollHeight }) 28 | return 29 | } 30 | } 31 | 32 | resolve(savedPosition || { left: 0, top: 0 }) 33 | }, 100) 34 | }) 35 | }, 36 | routes, 37 | 38 | // Leave this as is and make changes in quasar.conf.js instead! 39 | // quasar.conf.js -> build -> vueRouterMode 40 | // quasar.conf.js -> build -> publicPath 41 | history: createHistory(process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE) 42 | }) 43 | 44 | return Router 45 | }) 46 | -------------------------------------------------------------------------------- /docs/src/router/routes.js: -------------------------------------------------------------------------------- 1 | import menuItems from '../assets/menu.js' 2 | import examples from '../assets/examples.js' 3 | import getCategoryIndex from 'src/components/getCategoryIndex.js' 4 | 5 | const menuRoutes = [ 6 | { 7 | name: 'Landing Page', 8 | path: '', 9 | component: () => import('../pages/landing-page.md') 10 | } 11 | ] 12 | 13 | function parseMenuNode (node, __path) { 14 | const prefix = __path + (node.path !== void 0 ? '/' + node.path : '') 15 | 16 | if (node.children !== void 0) { 17 | // eslint-disable-next-line no-unused-expressions 18 | prefix !== '/start' && menuRoutes.push({ 19 | path: prefix, 20 | component: getCategoryIndex( 21 | node.name, 22 | node.children.map(node => { 23 | const to = node.external === true 24 | ? node.path 25 | : ( 26 | prefix + ( 27 | node.path !== void 0 28 | ? '/' + node.path 29 | : (node.listPath !== void 0 ? '/' + node.listPath : '') 30 | ) 31 | ) 32 | 33 | if (node.external !== true && node.listPath !== void 0) { 34 | menuRoutes.push({ 35 | path: to, 36 | component: getCategoryIndex( 37 | node.name, 38 | node.children.map(node => ({ 39 | title: node.name, 40 | name: node.name, 41 | to: node.internal === true ? node.path : prefix + (node.path !== void 0 ? '/' + node.path : ''), 42 | page: true 43 | })) 44 | ) 45 | }) 46 | } 47 | 48 | return { 49 | title: node.name, 50 | name: node.name, 51 | to, 52 | page: node.children === void 0 53 | } 54 | }) 55 | ) 56 | }) 57 | 58 | node.children.forEach(node => parseMenuNode(node, prefix)) 59 | } 60 | else if (node.external !== true && node.internal !== true) { 61 | menuRoutes.push({ 62 | path: prefix, 63 | name: node.name, 64 | component: () => import('pages/' + prefix.substring(1) + '.md') 65 | }) 66 | } 67 | } 68 | 69 | menuItems.forEach(node => { 70 | parseMenuNode(node, '') 71 | }) 72 | 73 | // console.log('menuRoutes:', menuRoutes) 74 | 75 | const routes = [ 76 | { 77 | path: '/', 78 | component: () => import('../layouts/MainLayout.vue'), 79 | children: menuRoutes 80 | }, 81 | 82 | { 83 | path: '/examples', 84 | component: () => import('../layouts/MainLayout.vue'), 85 | children: [].concat(examples) 86 | }, 87 | 88 | // Always leave this as last one, 89 | // but you can also remove it 90 | { 91 | path: '/:catchAll(.*)*', 92 | component: () => import('pages/Error404.vue') 93 | } 94 | ] 95 | 96 | export default routes 97 | -------------------------------------------------------------------------------- /docs/src/util/getLocale.js: -------------------------------------------------------------------------------- 1 | export const getLocale = () => { 2 | if (navigator.languages && navigator.languages.length > 0) { 3 | return navigator.languages[ 0 ] 4 | } 5 | else { 6 | return navigator.userLanguages || navigator.language || navigator.browserLanguages || 'en-US' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qiconpicker", 3 | "version": "1.0.0", 4 | "description": "QIconPicker mono-repo", 5 | "workspaces": [ 6 | "ui", 7 | "docs" 8 | ], 9 | "author": "Jeff Galbraith ", 10 | "license": "MIT", 11 | "private": true, 12 | "scripts": { 13 | "build": "yarn && cd ./ui && yarn build && cd ../docs && quasar build" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ui/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@babel/plugin-syntax-dynamic-import"], 3 | "env": { 4 | "test": { 5 | "plugins": ["dynamic-import-node"], 6 | "presets": [ 7 | [ 8 | "@babel/preset-env", 9 | { 10 | "modules": "commonjs", 11 | "targets": { 12 | "node": "current" 13 | } 14 | } 15 | ] 16 | ] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ui/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /ui/.eslintignore: -------------------------------------------------------------------------------- 1 | /docs 2 | /dist 3 | 4 | -------------------------------------------------------------------------------- /ui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy 3 | // This option interrupts the configuration hierarchy at this file 4 | // Remove this if you have an higher level ESLint config file (it usually happens into a monorepos) 5 | root: true, 6 | 7 | parser: '@babel/eslint-parser', 8 | parserOptions: { 9 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features 10 | sourceType: 'module', // Allows for the use of imports 11 | requireConfigFile: false 12 | }, 13 | 14 | env: { 15 | browser: true, 16 | es6: true, 17 | 'jest/globals': true 18 | }, 19 | 20 | // Rules order is important, please avoid shuffling them 21 | extends: [ 22 | // Base ESLint recommended rules 23 | // 'eslint:recommended', 24 | 25 | // Uncomment any of the lines below to choose desired strictness, 26 | // but leave only one uncommented! 27 | // See https://eslint.vuejs.org/rules/#available-rules 28 | 'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention) 29 | // 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability) 30 | // 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) 31 | 32 | // 'plugin:quasar/standard', 33 | 34 | // 'standard', 35 | 'plugin:promise/recommended' 36 | ], 37 | 38 | plugins: [ 39 | // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file 40 | // required to lint *.vue files 41 | 'vue', 42 | 'node', 43 | 'promise', 44 | 'import' 45 | ], 46 | 47 | globals: { 48 | $q: 'readonly', 49 | $router: 'readonly', 50 | ga: 'readonly', // Google Analytics 51 | cordova: 'readonly', 52 | __statics: 'readonly', 53 | __QUASAR_SSR__: 'readonly', 54 | __QUASAR_SSR_SERVER__: 'readonly', 55 | __QUASAR_SSR_CLIENT__: 'readonly', 56 | __QUASAR_SSR_PWA__: 'readonly', 57 | process: 'readonly', 58 | Capacitor: 'readonly', 59 | chrome: 'readonly', 60 | }, 61 | 62 | // add your custom rules here 63 | rules: { 64 | 'brace-style': [ 'error', 'stroustrup', { allowSingleLine: true } ], 65 | 'prefer-const': 'error', 66 | 'prefer-promise-reject-errors': 'off', 67 | 'multiline-ternary': 'off', 68 | 'no-prototype-builtins': 'off', 69 | 'no-case-declarations': 'off', 70 | 'generator-star-spacing': 'off', 71 | 'arrow-parens': 'off', 72 | 'object-property-newline': 'off', 73 | 'one-var': 'off', 74 | 'no-void': 'off', 75 | 'no-lone-blocks': 'error', 76 | 'no-unused-expressions': [ 'error', { allowTernary: true, "allowShortCircuit": true } ], 77 | 'no-useless-concat': 'error', 78 | 'no-useless-return': 'error', 79 | 'no-unneeded-ternary': 'error', 80 | 'no-confusing-arrow': [ 'error', { allowParens: true } ], 81 | 'operator-linebreak': [ 'error', 'before' ], 82 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 83 | 84 | 'array-bracket-spacing': [ 'error', 'always', { singleValue: false } ], 85 | 'object-curly-spacing': [ 'error', 'always' ], 86 | 'computed-property-spacing': [ 'error', 'always' ], 87 | 'template-curly-spacing': [ 'error', 'always' ], 88 | 89 | 'import/first': 'off', 90 | 'import/named': 'error', 91 | 'import/namespace': 'error', 92 | 'import/default': 'error', 93 | 'import/export': 'error', 94 | 'import/extensions': 'off', 95 | 'import/no-unresolved': 'off', 96 | 'import/no-extraneous-dependencies': 'off', 97 | 98 | 'import/no-webpack-loader-syntax': 'off', 99 | 100 | 'vue/singleline-html-element-content-newline': 'off', 101 | 'vue/no-multiple-template-root': 'off', 102 | 103 | // allow console.log during production for demo purposes 104 | // 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 105 | 'no-console': 'off' 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | # Testing 2 | /test/jest/coverage 3 | 4 | ui/yarn.lock 5 | ui/node_modules 6 | ui/dev/yarn.lock 7 | ui/dev/node_modules 8 | 9 | demo/yarn.lock 10 | demo/node_modules 11 | 12 | ./dist 13 | -------------------------------------------------------------------------------- /ui/.npmignore: -------------------------------------------------------------------------------- 1 | /build 2 | /dev 3 | umd-test.html 4 | 5 | .DS_Store 6 | .thumbs.db 7 | yarn.lock 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | jsconfig.json 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | .editorconfig 21 | 22 | # Linters 23 | .eslintignore 24 | .eslintrc.js 25 | .babelrc 26 | 27 | # Other 28 | /src/components/QIconPicker.json 29 | 30 | # Testing 31 | /test 32 | .env.jest 33 | jest.config.js 34 | -------------------------------------------------------------------------------- /ui/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Jeff Galbraith 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ui/build/build.api.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | global.rootDir = path.resolve(__dirname, '..') 3 | global.distDir = path.resolve(__dirname, '../dist') 4 | 5 | require('quasar-json-api')({ 6 | buildVetur: true, 7 | buildTypes: true 8 | }) 9 | -------------------------------------------------------------------------------- /ui/build/config.js: -------------------------------------------------------------------------------- 1 | const { name, author, version } = require('../package.json') 2 | const year = (new Date()).getFullYear() 3 | 4 | module.exports = { 5 | name, 6 | version, 7 | banner: 8 | '/*!\n' 9 | + ' * ' + name + ' v' + version + '\n' 10 | + ' * (c) ' + year + ' ' + author + '\n' 11 | + ' * Released under the MIT License.\n' 12 | + ' */\n' 13 | } 14 | -------------------------------------------------------------------------------- /ui/build/entry/index.cjs.js: -------------------------------------------------------------------------------- 1 | import Plugin from '../../src/index' 2 | 3 | export default Plugin 4 | -------------------------------------------------------------------------------- /ui/build/entry/index.esm.js: -------------------------------------------------------------------------------- 1 | import Plugin from '../../src/index' 2 | 3 | export default Plugin 4 | export * from '../../src/index' 5 | -------------------------------------------------------------------------------- /ui/build/entry/index.umd.js: -------------------------------------------------------------------------------- 1 | export * from '../../src/index' 2 | -------------------------------------------------------------------------------- /ui/build/icons/build.all.js: -------------------------------------------------------------------------------- 1 | const parallel = require('os').cpus().length > 1 2 | const runJob = parallel ? require('child_process').fork : require 3 | const { join } = require('path') 4 | 5 | runJob(join(__dirname, './build.google.material-icons.js')) 6 | runJob(join(__dirname, './build.mdi-v4.js')) 7 | runJob(join(__dirname, './build.mdi-v5.js')) 8 | runJob(join(__dirname, './build.mdi-v6.js')) 9 | runJob(join(__dirname, './build.ion.js')) 10 | runJob(join(__dirname, './build.eva.js')) 11 | runJob(join(__dirname, './build.themify.js')) 12 | runJob(join(__dirname, './build.fontawesome-v5.js')) 13 | runJob(join(__dirname, './build.line-awesome.js')) 14 | runJob(join(__dirname, './build.bootstrap-icons.js')) 15 | -------------------------------------------------------------------------------- /ui/build/icons/build.bootstrap-icons.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { green, blue, red } = require('kolorist') 3 | const { readFile, writeFile } = require('../utils') 4 | 5 | const name = 'bootstrap-icons' 6 | const inputLocation = `../../src/components/icon-set/${name}.js` 7 | const outputLocation = `../../src/components/icon-set/${name}.js` 8 | const oldIcons = {} 9 | const icons = [] 10 | const blacklisted = [ 11 | ] 12 | 13 | let fa = readFile(path.resolve(__dirname, inputLocation)) 14 | fa = fa.split('\n') 15 | fa.shift() 16 | fa.shift() 17 | fa.shift() 18 | fa.pop() 19 | fa.pop() 20 | fa.pop() 21 | fa = '[\n' + fa.join(',\n') + '\n]\n' 22 | // eslint-disable-next-line no-eval 23 | fa = eval(fa) 24 | fa.forEach(f => { 25 | const name = f.name 26 | const tags = f.tags 27 | oldIcons[name] = { tags: Array(tags).join(',') } 28 | }) 29 | 30 | const location = require.resolve('@quasar/extras/bootstrap-icons/bootstrap-icons.css') 31 | const fileContents = readFile(location) 32 | 33 | fileContents 34 | .split('\n') 35 | .forEach(line => { 36 | line = line.trim() 37 | if (line.startsWith('.')) { 38 | const pos = line.indexOf('::before') 39 | if (pos > 0) { 40 | line = line.slice(1, pos) 41 | if (blacklisted.includes(line) === false) { 42 | if (oldIcons[line]) { 43 | const tags = oldIcons[line].tags.split(',').map(tag => { 44 | if (tag === '') return tag 45 | return "'" + tag + "'" 46 | }).join(', ') 47 | icons.push(`{ name: '${line}', tags: [${tags}] }`) 48 | } 49 | else { 50 | icons.push(`{ name: '${line}', tags: [] }`) 51 | } 52 | } 53 | } 54 | } 55 | }) 56 | 57 | if (icons.length === 0) { 58 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 59 | process.exit(1) 60 | } 61 | 62 | let output = 'export default {\n' 63 | output += ` name: '${name}',\n` 64 | output += ' icons: [\n' 65 | 66 | icons.forEach((icon, index) => { 67 | if (index !== 0) { 68 | output += ',\n' 69 | } 70 | 71 | output += ` ${icon}` 72 | }) 73 | 74 | output += '\n ]\n' 75 | output += '}\n' 76 | 77 | writeFile(path.resolve(__dirname, outputLocation), output) 78 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 79 | -------------------------------------------------------------------------------- /ui/build/icons/build.eva.js: -------------------------------------------------------------------------------- 1 | /* 2 | This generator reads existing output to get tags. Reads the 3 | actual font info and then rebuilds the output with tags. 4 | */ 5 | const path = require('path') 6 | const { green, blue, red } = require('kolorist') 7 | const { readFile, writeFile } = require('../utils') 8 | 9 | const name = 'eva-icons' 10 | const inputLocation = `../../src/components/icon-set/${name}.js` 11 | const outputLocation = `../../src/components/icon-set/${name}.js` 12 | const oldIcons = {} 13 | const icons = [] 14 | // no blacklisted items (yet) 15 | const blacklisted = [ 16 | ] 17 | 18 | let fa = readFile(path.resolve(__dirname, inputLocation)) 19 | fa = fa.split('\n') 20 | fa.shift() 21 | fa.shift() 22 | fa.shift() 23 | fa.pop() 24 | fa.pop() 25 | fa.pop() 26 | fa = '[\n' + fa.join(',\n') + '\n]\n' 27 | // eslint-disable-next-line no-eval 28 | fa = eval(fa) 29 | fa.forEach(f => { 30 | const name = f.name 31 | const tags = f.tags 32 | oldIcons[name] = { tags: Array(tags).join(',') } 33 | }) 34 | 35 | const location = require.resolve('@quasar/extras/eva-icons/eva-icons.css') 36 | const fileContents = readFile(location) 37 | 38 | fileContents 39 | .split('\n') 40 | .forEach(line => { 41 | line = line.trim() 42 | if (line.startsWith('.')) { 43 | const pos = line.indexOf(':before') 44 | if (pos > 0) { 45 | line = line.slice(1, pos - 1) 46 | if (blacklisted.includes(line) === false) { 47 | if (oldIcons[line]) { 48 | const tags = oldIcons[line].tags.split(',').map(tag => { 49 | if (tag === '') return tag 50 | return "'" + tag + "'" 51 | }).join(', ') 52 | icons.push(`{ name: '${line}', tags: [${tags}] }`) 53 | } 54 | else { 55 | icons.push(`{ name: '${line}', tags: [] }`) 56 | } 57 | } 58 | } 59 | } 60 | }) 61 | 62 | if (icons.length === 0) { 63 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 64 | process.exit(1) 65 | } 66 | 67 | let output = 'export default {\n' 68 | output += ` name: '${name}',\n` 69 | output += ' icons: [\n' 70 | 71 | icons.forEach((icon, index) => { 72 | if (index !== 0) { 73 | output += ',\n' 74 | } 75 | output += ` ${icon}` 76 | }) 77 | 78 | output += '\n ]\n' 79 | output += '}\n' 80 | 81 | writeFile(path.resolve(__dirname, outputLocation), output) 82 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 83 | -------------------------------------------------------------------------------- /ui/build/icons/build.fontawesome-v5.js: -------------------------------------------------------------------------------- 1 | /* 2 | This generator is a bit different from the rest. Fontawesome uses 3 | a prefix (ex: 'fab', 'fas', 'far', etc) to determine which font file to 4 | use. However, this information is not in the css file that we will 5 | be parsing. So, we open the old fontawesome-v5.js file (which was 6 | made for web, not node), read it in, make adjustments, and eval it 7 | (yeah I know, eval bad). Then we make a map of fonts and the 8 | prefixes so we can add the prefix back. If it's a new font, we make 9 | the prefix '---' so we can search the file for it and hand-curate 10 | the prefix manually. Then, we have a finished file. 11 | */ 12 | const path = require('path') 13 | const { green, blue, red } = require('kolorist') 14 | const { readFile, writeFile } = require('../utils') 15 | const { validateTags } = require('../utils') 16 | 17 | const name = 'fontawesome-v5' 18 | const inputLocation = `../../src/components/icon-set/${name}.js` 19 | const outputLocation = `../../src/components/icon-set/${name}.js` 20 | const oldIcons = {} 21 | const icons = [] 22 | const blacklisted = [ 23 | 'fa-font-awesome-logo-full' 24 | ] 25 | 26 | let fa = readFile(path.resolve(__dirname, inputLocation)) 27 | fa = fa.split('\n') 28 | fa.shift() 29 | fa.shift() 30 | fa.shift() 31 | fa.pop() 32 | fa.pop() 33 | fa.pop() 34 | fa = '[\n' + fa.join('\n') + '\n]\n' 35 | // eslint-disable-next-line no-eval 36 | fa = eval(fa) 37 | fa.forEach(f => { 38 | const name = f.name 39 | const prefix = f.prefix 40 | const tags = f.tags 41 | if (oldIcons[name] !== void 0) { 42 | oldIcons[name].prefix.push(prefix) 43 | } 44 | else { 45 | if (prefix === 'fab') { 46 | if (tags.includes('brand') !== true) { 47 | tags.push('brand') 48 | } 49 | } 50 | oldIcons[name] = { prefix: Array(prefix), tags: tags.sort() } 51 | } 52 | }) 53 | 54 | const location = require.resolve('@quasar/extras/fontawesome-v5/fontawesome-v5.css') 55 | const fileContents = readFile(location) 56 | 57 | fileContents 58 | .split('\n') 59 | .forEach(line => { 60 | line = line.trim() 61 | if (line.startsWith('.fa')) { 62 | const pos = line.indexOf(':before') 63 | if (pos > 0) { 64 | const name = line.slice(1, pos) 65 | if (blacklisted.includes(name) !== true) { 66 | if (oldIcons[name] !== void 0) { 67 | oldIcons[name].prefix.forEach(pfx => { 68 | // if type is 'fab' make sure it has brand 69 | if (pfx === 'fab') { 70 | if (oldIcons[name].tags.includes('brand') !== true) { 71 | oldIcons[name].tags.push('brand') 72 | } 73 | } 74 | // validate tags 75 | validateTags(oldIcons[name].tags) 76 | const tags = oldIcons[name].tags.map(tag => { 77 | if (tag === '') return tag 78 | return "'" + tag + "'" 79 | }).join(', ') 80 | icons.push(`{ name: '${name}', prefix: '${pfx}', tags: [${tags}] }`) 81 | }) 82 | } 83 | else { 84 | icons.push(`{ name: '${name}', prefix: '---', tags: [] }`) 85 | } 86 | } 87 | } 88 | } 89 | }) 90 | 91 | if (icons.length === 0) { 92 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 93 | process.exit(1) 94 | } 95 | 96 | let output = 'export default {\n' 97 | output += ` name: '${name}',\n` 98 | output += ' icons: [\n' 99 | 100 | icons.forEach((icon, index) => { 101 | if (index !== 0) { 102 | output += ',\n' 103 | } 104 | 105 | output += ` ${icon}` 106 | }) 107 | 108 | output += '\n ]\n' 109 | output += '}\n' 110 | 111 | writeFile(path.resolve(__dirname, outputLocation), output) 112 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 113 | -------------------------------------------------------------------------------- /ui/build/icons/build.google.material-icons.js: -------------------------------------------------------------------------------- 1 | const fetch = require('cross-fetch') 2 | const { blue } = require('kolorist') 3 | 4 | const themeMap = { 5 | baseline: 'baseline', 6 | outlined: 'outlined', 7 | round: 'round', 8 | sharp: 'sharp' 9 | } 10 | 11 | async function run () { 12 | try { 13 | console.log(`${blue('[downloading]')} Google Material Design SVG icons meta data...`) 14 | 15 | const response = await fetch('https://fonts.google.com/metadata/icons') 16 | const text = await response.text() 17 | const data = JSON.parse(text.replace(")]}'", '')) 18 | let icons = data.icons 19 | icons = icons.map((icon, index) => ({ index, ...icon })) 20 | Object.keys(themeMap).forEach(theme => { 21 | // give function clean copy of google icons 22 | require('./build.material-icons-base.js').run(JSON.parse(JSON.stringify(icons)), themeMap[theme]) 23 | }) 24 | } 25 | catch (err) { 26 | console.log('err', err) 27 | throw err 28 | } 29 | } 30 | 31 | run() 32 | -------------------------------------------------------------------------------- /ui/build/icons/build.ion.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { green, blue, red } = require('kolorist') 3 | const { readFile, writeFile } = require('../utils') 4 | 5 | const name = 'ionicons-v4' 6 | const inputLocation = `../../src/components/icon-set/${name}.js` 7 | const outputLocation = `../../src/components/icon-set/${name}.js` 8 | const oldIcons = {} 9 | const icons = [] 10 | const blacklisted = [ 11 | 'ionicon', 12 | 'ionicons' 13 | ] 14 | 15 | let fa = readFile(path.resolve(__dirname, inputLocation)) 16 | fa = fa.split('\n') 17 | fa.shift() 18 | fa.shift() 19 | fa.shift() 20 | fa.pop() 21 | fa.pop() 22 | fa.pop() 23 | fa = '[\n' + fa.join(',\n') + '\n]\n' 24 | // eslint-disable-next-line no-eval 25 | fa = eval(fa) 26 | fa.forEach(f => { 27 | const name = f.name 28 | const tags = f.tags 29 | oldIcons[name] = { tags: Array(tags).join(',') } 30 | }) 31 | 32 | const location = require.resolve('@quasar/extras/ionicons-v4/ionicons-v4.css') 33 | const fileContents = readFile(location) 34 | 35 | fileContents 36 | .split('\n') 37 | .forEach(line => { 38 | line = line.trim() 39 | if (line.startsWith('.')) { 40 | const pos = line.indexOf(':before') 41 | if (pos > 0) { 42 | line = line.slice(1, pos) 43 | if (blacklisted.includes(line) === false) { 44 | if (oldIcons[line]) { 45 | const tags = oldIcons[line].tags.split(',').map(tag => { 46 | if (tag === '') return tag 47 | return "'" + tag + "'" 48 | }).join(', ') 49 | icons.push(`{ name: '${line}', tags: [${tags}] }`) 50 | } 51 | else { 52 | icons.push(`{ name: '${line}', tags: [] }`) 53 | } 54 | } 55 | } 56 | } 57 | }) 58 | 59 | if (icons.length === 0) { 60 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 61 | process.exit(1) 62 | } 63 | 64 | let output = 'export default {\n' 65 | output += ` name: '${name}',\n` 66 | output += ' icons: [\n' 67 | 68 | icons.forEach((icon, index) => { 69 | if (index !== 0) { 70 | output += ',\n' 71 | } 72 | 73 | output += ` ${icon}` 74 | }) 75 | 76 | output += '\n ]\n' 77 | output += '}\n' 78 | 79 | writeFile(path.resolve(__dirname, outputLocation), output) 80 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 81 | -------------------------------------------------------------------------------- /ui/build/icons/build.line-awesome.js: -------------------------------------------------------------------------------- 1 | /* 2 | This generator is a bit different from the rest. Line-awesome uses 3 | a prefix (ex: 'lab', 'las', 'lar', etc) to determine which font file to 4 | use. However, this information is not in the css file that we will 5 | be parsing. So, we open the old line-awesome.js file (which was 6 | made for web, not node), read it in, make adjustments, and eval it 7 | (yeah I know, eval bad). Then we make a map of fonts and the 8 | prefixes so we can add the prefix back. If it's a new font, we make 9 | the prefix '---' so we can search the file for it and hand-curate 10 | the prefix manually. Then, we have a finished file. 11 | */ 12 | const path = require('path') 13 | const { green, blue, red } = require('kolorist') 14 | const { readFile, writeFile } = require('../utils') 15 | const { validateTags } = require('../utils') 16 | 17 | const name = 'line-awesome' 18 | const inputLocation = `../../src/components/icon-set/${name}.js` 19 | const outputLocation = `../../src/components/icon-set/${name}.js` 20 | const oldIcons = {} 21 | const icons = [] 22 | const blacklisted = [ 23 | 'la-font-awesome-logo-full' 24 | ] 25 | 26 | let fa = readFile(path.resolve(__dirname, inputLocation)) 27 | fa = fa.split('\n') 28 | fa.shift() 29 | fa.shift() 30 | fa.shift() 31 | fa.pop() 32 | fa.pop() 33 | fa.pop() 34 | fa = '[\n' + fa.join('\n') + '\n]\n' 35 | // eslint-disable-next-line no-eval 36 | fa = eval(fa) 37 | fa.forEach(f => { 38 | const name = f.name 39 | const prefix = f.prefix 40 | const tags = f.tags 41 | if (oldIcons[name] !== void 0) { 42 | oldIcons[name].prefix.push(prefix) 43 | } 44 | else { 45 | if (prefix === 'lab') { 46 | if (tags.includes('brand') !== true) { 47 | tags.push('brand') 48 | } 49 | } 50 | oldIcons[name] = { prefix: Array(prefix), tags: tags.sort() } 51 | } 52 | }) 53 | 54 | const location = require.resolve('@quasar/extras/line-awesome/line-awesome.css') 55 | const fileContents = readFile(location) 56 | 57 | fileContents 58 | .split('\n') 59 | .forEach(line => { 60 | line = line.trim() 61 | if (line.startsWith('.')) { 62 | const pos = line.indexOf(':before') 63 | if (pos > 0) { 64 | const name = line.slice(1, pos) 65 | if (blacklisted.includes(name) !== true) { 66 | if (oldIcons[name] !== void 0) { 67 | oldIcons[name].prefix.forEach(pfx => { 68 | // if type is 'lab' make sure it has brand 69 | if (pfx === 'lab') { 70 | if (oldIcons[name].tags.includes('brand') !== true) { 71 | oldIcons[name].tags.push('brand') 72 | } 73 | } 74 | // validate tags 75 | validateTags(oldIcons[name].tags) 76 | const tags = oldIcons[name].tags.map(tag => { 77 | if (tag === '') return tag 78 | return "'" + tag + "'" 79 | }).join(', ') 80 | icons.push(`{ name: '${name}', prefix: '${pfx}', tags: [${tags}] }`) 81 | }) 82 | } 83 | else { 84 | if (!name.startsWith('la.la')) { 85 | icons.push(`{ name: '${name}', prefix: '---', tags: [] }`) 86 | } 87 | } 88 | } 89 | } 90 | } 91 | }) 92 | 93 | if (icons.length === 0) { 94 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 95 | process.exit(1) 96 | } 97 | 98 | let output = 'export default {\n' 99 | output += ` name: '${name}',\n` 100 | output += ' icons: [\n' 101 | 102 | icons.forEach((icon, index) => { 103 | if (index !== 0) { 104 | output += ',\n' 105 | } 106 | 107 | output += ` ${icon}` 108 | }) 109 | 110 | output += '\n ]\n' 111 | output += '}\n' 112 | 113 | writeFile(path.resolve(__dirname, outputLocation), output) 114 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 115 | -------------------------------------------------------------------------------- /ui/build/icons/build.material-icons-base.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const {green, blue, red} = require('kolorist') 3 | const {readFile, writeFile} = require('../utils') 4 | 5 | const themeMap = { 6 | baseline: '', 7 | outlined: 'o_', 8 | round: 'r_', 9 | sharp: 's_' 10 | } 11 | 12 | function run(googleIcons, theme) { 13 | const name = 'material-icons' + (theme === 'baseline' ? '' : '-' + theme) 14 | // console.log(`${blue('[building]')} ${name}...`) 15 | const inputLocation = `../../src/components/icon-set/${name}.js` 16 | const outputLocation = `../../src/components/icon-set/${name}.js` 17 | const oldIcons = {} 18 | const icons = [] 19 | const blacklisted = [ 20 | 'grade', 21 | 'grading', 22 | 'dynamic_feed', 23 | 'o_dynamic_feed', 24 | 'r_dynamic_feed', 25 | 's_dynamic_feed', 26 | 's_grade', 27 | 's_grading', 28 | 'r_grade', 29 | 'r_grading', 30 | 'o_grade', 31 | 'o_grading' 32 | ] 33 | const whiteListed = { 34 | baseline: [ 35 | 'border_color', 36 | 'do_not_disturb', 37 | 'do_not_disturb_alt', 38 | 'do_not_disturb_off', 39 | 'do_not_disturb_on', 40 | 'file_download', 41 | 'file_upload', 42 | 'format_color_fill', 43 | 'format_color_text', 44 | 'info_outline', 45 | 'label_outline', 46 | 'lightbulb_outline', 47 | 'lock_outline', 48 | 'mode_edit', 49 | 'motorcycle', 50 | 'network_cell', 51 | 'network_wifi', 52 | 'pie_chart_outlined', 53 | 'sim_card_alert' 54 | ], 55 | outlined: [ 56 | 'motorcycle', 57 | 'pie_chart_outlined' 58 | ], 59 | round: [ 60 | 'info_outline', 61 | 'label_outline', 62 | 'lightbulb_outline', 63 | 'lock_outline', 64 | 'motorcycle', 65 | 'pie_chart_outlined' 66 | ], 67 | sharp: [ 68 | 'label_outline', 69 | 'lightbulb_outline', 70 | 'lock_outline', 71 | 'motorcycle' 72 | ] 73 | } 74 | 75 | let fa = readFile(path.resolve(__dirname, inputLocation)) 76 | fa = fa.split('\n') 77 | fa.shift() 78 | fa.shift() 79 | fa.shift() 80 | fa.pop() 81 | fa.pop() 82 | fa.pop() 83 | fa = '[\n' + fa.join('\n') + '\n]\n' 84 | // eslint-disable-next-line no-eval 85 | fa = eval(fa) 86 | fa.forEach(f => { 87 | const name = f.name 88 | const tags = f.tags 89 | oldIcons[name] = {tags: Array(tags).join(',')} 90 | }) 91 | 92 | googleIcons.forEach(gi => { 93 | gi.name = themeMap[theme] + gi.name 94 | }) 95 | 96 | whiteListed[theme].forEach(name => { 97 | googleIcons.push({name: themeMap[theme] + name}) 98 | }) 99 | 100 | googleIcons.sort((a, b) => { 101 | return ('' + a.name).localeCompare(b.name) 102 | }) 103 | 104 | googleIcons 105 | .forEach(gi => { 106 | const name = gi.name 107 | if (blacklisted.includes(name) === false) { 108 | if (oldIcons[name]) { 109 | 110 | const oldTags = oldIcons[name].tags 111 | .split(',') 112 | 113 | // Merge old and new tags 114 | const tagsWithoutDuplicates = [...new Set(oldTags.concat(gi.tags))]; 115 | const newTags = tagsWithoutDuplicates 116 | .filter(tag => tag !== "") 117 | .map(tag => "'" + tag + "'") 118 | .join(', ') 119 | 120 | // Add merged tags old/new 121 | icons.push(`{ name: '${name}', tags: [${newTags}] }`) 122 | } else { 123 | // Add new tags 124 | icons.push(`{ name: '${name}', tags: [${gi.tags}] }`) 125 | } 126 | } 127 | }) 128 | 129 | if (icons.length === 0) { 130 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 131 | process.exit(1) 132 | } 133 | 134 | let output = 'export default {\n' 135 | output += ` name: '${name}',\n` 136 | output += ' icons: [\n' 137 | 138 | icons.forEach((icon, index) => { 139 | if (index !== 0) { 140 | output += ',\n' 141 | } 142 | 143 | output += ` ${icon}` 144 | }) 145 | 146 | output += '\n ]\n' 147 | output += '}\n' 148 | 149 | writeFile(path.resolve(__dirname, outputLocation), output) 150 | .catch(exception => console.error(exception)) 151 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 152 | } 153 | 154 | module.exports = { 155 | run 156 | } 157 | -------------------------------------------------------------------------------- /ui/build/icons/build.mdi-v4.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { green, blue, red } = require('kolorist') 3 | const { readFile, writeFile } = require('../utils') 4 | 5 | const name = 'mdi-v4' 6 | const inputLocation = `../../src/components/icon-set/${name}.js` 7 | const outputLocation = `../../src/components/icon-set/${name}.js` 8 | const oldIcons = {} 9 | const icons = [] 10 | const blacklisted = [ 11 | 'md', 12 | 'mdi-blank', 13 | 'mdi-18px.mdi-set, .mdi-18px.md', 14 | 'mdi-24px.mdi-set, .mdi-24px.md', 15 | 'mdi-36px.mdi-set, .mdi-36px.md', 16 | 'mdi-48px.mdi-set, .mdi-48px.md', 17 | 'mdi-dar', 18 | 'mdi-dark.mdi-inactiv', 19 | 'mdi-ligh', 20 | 'mdi-light.mdi-inactiv', 21 | 'mdi-rotate-4', 22 | 'mdi-rotate-9', 23 | 'mdi-rotate-13', 24 | 'mdi-rotate-18', 25 | 'mdi-rotate-22', 26 | 'mdi-rotate-27', 27 | 'mdi-rotate-31', 28 | 'mdi-flip-', 29 | 'mdi-spi' 30 | ] 31 | 32 | let fa = readFile(path.resolve(__dirname, inputLocation)) 33 | fa = fa.split('\n') 34 | fa.shift() 35 | fa.shift() 36 | fa.shift() 37 | fa.pop() 38 | fa.pop() 39 | fa.pop() 40 | fa = '[\n' + fa.join(',\n') + '\n]\n' 41 | // eslint-disable-next-line no-eval 42 | fa = eval(fa) 43 | fa.forEach(f => { 44 | const name = f.name 45 | const tags = f.tags 46 | oldIcons[name] = { tags: Array(tags).join(',') } 47 | }) 48 | 49 | const location = require.resolve('@quasar/extras/mdi-v4/mdi-v4.css') 50 | const fileContents = readFile(location) 51 | 52 | fileContents 53 | .split('\n') 54 | .forEach(line => { 55 | line = line.trim() 56 | if (line.startsWith('.')) { 57 | const pos = line.indexOf(':before') 58 | if (pos > 0) { 59 | line = line.slice(1, pos - 1) 60 | if (blacklisted.includes(line) === false) { 61 | if (oldIcons[line]) { 62 | const tags = oldIcons[line].tags.split(',').map(tag => { 63 | if (tag === '') return tag 64 | return "'" + tag + "'" 65 | }).join(', ') 66 | icons.push(`{ name: '${line}', tags: [${tags}] }`) 67 | } 68 | else { 69 | icons.push(`{ name: '${line}', tags: [] }`) 70 | } 71 | } 72 | } 73 | } 74 | }) 75 | 76 | if (icons.length === 0) { 77 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 78 | process.exit(1) 79 | } 80 | 81 | let output = 'export default {\n' 82 | output += ` name: '${name}',\n` 83 | output += ' icons: [\n' 84 | 85 | icons.forEach((icon, index) => { 86 | if (index !== 0) { 87 | output += ',\n' 88 | } 89 | 90 | output += ` ${icon}` 91 | }) 92 | 93 | output += '\n ]\n' 94 | output += '}\n' 95 | 96 | writeFile(path.resolve(__dirname, outputLocation), output) 97 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 98 | -------------------------------------------------------------------------------- /ui/build/icons/build.mdi-v5.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { green, blue, red } = require('kolorist') 3 | const { readFile, writeFile } = require('../utils') 4 | 5 | const name = 'mdi-v5' 6 | const inputLocation = `../../src/components/icon-set/${name}.js` 7 | const outputLocation = `../../src/components/icon-set/${name}.js` 8 | const oldIcons = {} 9 | const icons = [] 10 | const blacklisted = [ 11 | 'md', 12 | 'mdi-blank', 13 | 'mdi-18px.mdi-set, .mdi-18px.md', 14 | 'mdi-24px.mdi-set, .mdi-24px.md', 15 | 'mdi-36px.mdi-set, .mdi-36px.md', 16 | 'mdi-48px.mdi-set, .mdi-48px.md', 17 | 'mdi-dar', 18 | 'mdi-dark.mdi-inactiv', 19 | 'mdi-ligh', 20 | 'mdi-light.mdi-inactiv', 21 | 'mdi-rotate-4', 22 | 'mdi-rotate-9', 23 | 'mdi-rotate-13', 24 | 'mdi-rotate-18', 25 | 'mdi-rotate-22', 26 | 'mdi-rotate-27', 27 | 'mdi-rotate-31', 28 | 'mdi-flip-', 29 | 'mdi-spi' 30 | ] 31 | 32 | let fa = readFile(path.resolve(__dirname, inputLocation)) 33 | fa = fa.split('\n') 34 | fa.shift() 35 | fa.shift() 36 | fa.shift() 37 | fa.pop() 38 | fa.pop() 39 | fa.pop() 40 | fa = '[\n' + fa.join(',\n') + '\n]\n' 41 | // eslint-disable-next-line no-eval 42 | fa = eval(fa) 43 | fa.forEach(f => { 44 | const name = f.name 45 | const tags = f.tags 46 | oldIcons[name] = { tags: Array(tags).join(',') } 47 | }) 48 | 49 | const location = require.resolve('@quasar/extras/mdi-v5/mdi-v5.css') 50 | const fileContents = readFile(location) 51 | 52 | fileContents 53 | .split('\n') 54 | .forEach(line => { 55 | line = line.trim() 56 | if (line.startsWith('.')) { 57 | const pos = line.indexOf(':before') 58 | if (pos > 0) { 59 | line = line.slice(1, pos - 1) 60 | if (blacklisted.includes(line) === false) { 61 | if (oldIcons[line]) { 62 | const tags = oldIcons[line].tags.split(',').map(tag => { 63 | if (tag === '') return tag 64 | return "'" + tag + "'" 65 | }).join(', ') 66 | icons.push(`{ name: '${line}', tags: [${tags}] }`) 67 | } 68 | else { 69 | icons.push(`{ name: '${line}', tags: [] }`) 70 | } 71 | } 72 | } 73 | } 74 | }) 75 | 76 | if (icons.length === 0) { 77 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 78 | process.exit(1) 79 | } 80 | 81 | let output = 'export default {\n' 82 | output += ` name: '${name}',\n` 83 | output += ' icons: [\n' 84 | 85 | icons.forEach((icon, index) => { 86 | if (index !== 0) { 87 | output += ',\n' 88 | } 89 | 90 | output += ` ${icon}` 91 | }) 92 | 93 | output += '\n ]\n' 94 | output += '}\n' 95 | 96 | writeFile(path.resolve(__dirname, outputLocation), output) 97 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 98 | -------------------------------------------------------------------------------- /ui/build/icons/build.mdi-v6.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { green, blue, red } = require('kolorist') 3 | const { readFile, writeFile } = require('../utils') 4 | 5 | const name = 'mdi-v6' 6 | const inputLocation = `../../src/components/icon-set/${name}.js` 7 | const outputLocation = `../../src/components/icon-set/${name}.js` 8 | const oldIcons = {} 9 | const icons = [] 10 | const blacklisted = [ 11 | 'md', 12 | 'mdi-blank', 13 | 'mdi-18px.mdi-set, .mdi-18px.md', 14 | 'mdi-24px.mdi-set, .mdi-24px.md', 15 | 'mdi-36px.mdi-set, .mdi-36px.md', 16 | 'mdi-48px.mdi-set, .mdi-48px.md', 17 | 'mdi-dar', 18 | 'mdi-dark.mdi-inactiv', 19 | 'mdi-ligh', 20 | 'mdi-light.mdi-inactiv', 21 | 'mdi-rotate-4', 22 | 'mdi-rotate-9', 23 | 'mdi-rotate-13', 24 | 'mdi-rotate-18', 25 | 'mdi-rotate-22', 26 | 'mdi-rotate-27', 27 | 'mdi-rotate-31', 28 | 'mdi-flip-', 29 | 'mdi-spi' 30 | ] 31 | 32 | let fa = readFile(path.resolve(__dirname, inputLocation)) 33 | fa = fa.split('\n') 34 | fa.shift() 35 | fa.shift() 36 | fa.shift() 37 | fa.pop() 38 | fa.pop() 39 | fa.pop() 40 | fa = '[\n' + fa.join(',\n') + '\n]\n' 41 | // eslint-disable-next-line no-eval 42 | fa = eval(fa) 43 | fa.forEach(f => { 44 | const name = f.name 45 | const tags = f.tags 46 | oldIcons[name] = { tags: Array(tags).join(',') } 47 | }) 48 | 49 | const location = require.resolve('@quasar/extras/mdi-v6/mdi-v6.css') 50 | const fileContents = readFile(location) 51 | 52 | fileContents 53 | .split('\n') 54 | .forEach(line => { 55 | line = line.trim() 56 | if (line.startsWith('.')) { 57 | const pos = line.indexOf(':before') 58 | if (pos > 0) { 59 | line = line.slice(1, pos - 1) 60 | if (blacklisted.includes(line) === false) { 61 | if (oldIcons[line]) { 62 | const tags = oldIcons[line].tags.split(',').map(tag => { 63 | if (tag === '') return tag 64 | return "'" + tag + "'" 65 | }).join(', ') 66 | icons.push(`{ name: '${line}', tags: [${tags}] }`) 67 | } 68 | else { 69 | icons.push(`{ name: '${line}', tags: [] }`) 70 | } 71 | } 72 | } 73 | } 74 | }) 75 | 76 | if (icons.length === 0) { 77 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 78 | process.exit(1) 79 | } 80 | 81 | let output = 'export default {\n' 82 | output += ` name: '${name}',\n` 83 | output += ' icons: [\n' 84 | 85 | icons.forEach((icon, index) => { 86 | if (index !== 0) { 87 | output += ',\n' 88 | } 89 | 90 | output += ` ${icon}` 91 | }) 92 | 93 | output += '\n ]\n' 94 | output += '}\n' 95 | 96 | writeFile(path.resolve(__dirname, outputLocation), output) 97 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 98 | -------------------------------------------------------------------------------- /ui/build/icons/build.themify.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { green, blue, red } = require('kolorist') 3 | const { readFile, writeFile } = require('../utils') 4 | 5 | const name = 'themify' 6 | const inputLocation = `../../src/components/icon-set/${name}.js` 7 | const outputLocation = `../../src/components/icon-set/${name}.js` 8 | const oldIcons = {} 9 | const icons = [] 10 | const blacklisted = [ 11 | ] 12 | 13 | let fa = readFile(path.resolve(__dirname, inputLocation)) 14 | fa = fa.split('\n') 15 | fa.shift() 16 | fa.shift() 17 | fa.shift() 18 | fa.pop() 19 | fa.pop() 20 | fa.pop() 21 | fa = '[\n' + fa.join(',\n') + '\n]\n' 22 | // eslint-disable-next-line no-eval 23 | fa = eval(fa) 24 | fa.forEach(f => { 25 | const name = f.name 26 | const tags = f.tags 27 | oldIcons[name] = { tags: Array(tags).join(',') } 28 | }) 29 | 30 | const location = require.resolve('@quasar/extras/themify/themify.css') 31 | const fileContents = readFile(location) 32 | 33 | fileContents 34 | .split('\n') 35 | .forEach(line => { 36 | line = line.trim() 37 | if (line.startsWith('.')) { 38 | const pos = line.indexOf(':before') 39 | if (pos > 0) { 40 | line = line.slice(1, pos) 41 | if (blacklisted.includes(line) === false) { 42 | if (oldIcons[line]) { 43 | const tags = oldIcons[line].tags.split(',').map(tag => { 44 | if (tag === '') return tag 45 | return "'" + tag + "'" 46 | }).join(', ') 47 | icons.push(`{ name: '${line}', tags: [${tags}] }`) 48 | } 49 | else { 50 | icons.push(`{ name: '${line}', tags: [] }`) 51 | } 52 | } 53 | } 54 | } 55 | }) 56 | 57 | if (icons.length === 0) { 58 | console.log(`${red('[error]')} ${name} icons parsed 0 icons...exiting`) 59 | process.exit(1) 60 | } 61 | 62 | let output = 'export default {\n' 63 | output += ` name: '${name}',\n` 64 | output += ' icons: [\n' 65 | 66 | icons.forEach((icon, index) => { 67 | if (index !== 0) { 68 | output += ',\n' 69 | } 70 | 71 | output += ` ${icon}` 72 | }) 73 | 74 | output += '\n ]\n' 75 | output += '}\n' 76 | 77 | writeFile(path.resolve(__dirname, outputLocation), output) 78 | console.log(`${blue('[icon]')} ${green(name + ':')} ${icons.length} generated`) 79 | -------------------------------------------------------------------------------- /ui/build/index.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'production' 2 | 3 | const parallel = require('os').cpus().length > 1 4 | const runJob = parallel ? require('child_process').fork : require 5 | const { join } = require('path') 6 | const { createFolder } = require('./utils') 7 | const { green, blue } = require('kolorist') 8 | 9 | console.log() 10 | 11 | require('./script.app-ext.js').syncAppExt() 12 | require('./script.clean.js') 13 | 14 | console.log(` 📦 Building ${ green('v' + require('../package.json').version) }...${ parallel ? blue(' [multi-threaded]') : '' }\n`) 15 | 16 | createFolder('dist') 17 | 18 | require('./script.version.js') 19 | 20 | require('./build.api.js') 21 | 22 | runJob(join(__dirname, './script.javascript.js')) 23 | runJob(join(__dirname, './script.css.js')) 24 | -------------------------------------------------------------------------------- /ui/build/script.app-ext.js: -------------------------------------------------------------------------------- 1 | const 2 | fs = require('fs'), 3 | path = require('path'), 4 | root = path.resolve(__dirname, '../..'), 5 | resolvePath = file => path.resolve(root, file), 6 | { blue } = require('kolorist') 7 | 8 | const writeJson = function (file, json) { 9 | return fs.writeFileSync(file, JSON.stringify(json, null, 2) + '\n', 'utf-8') 10 | } 11 | 12 | module.exports.syncAppExt = function (both = true) { 13 | // make sure this project has an app-extension project 14 | const appExtDir = resolvePath('app-extension') 15 | if (!fs.existsSync(appExtDir)) { 16 | return 17 | } 18 | 19 | // make sure this project has an ui project 20 | const uiDir = resolvePath('ui') 21 | if (!fs.existsSync(uiDir)) { 22 | return 23 | } 24 | 25 | // get version and name from ui package.json 26 | const { name, version } = require(resolvePath(resolvePath('ui/package.json'))) 27 | 28 | // read app-ext package.json 29 | const appExtFile = resolvePath('app-extension/package.json') 30 | const appExtJson = require(appExtFile) 31 | let finished = false 32 | 33 | // sync version numbers 34 | if (both === true) { 35 | appExtJson.version = version 36 | } 37 | 38 | // check dependencies 39 | if (appExtJson.dependencies !== void 0) { 40 | if (appExtJson.dependencies[ name ] !== void 0) { 41 | appExtJson.dependencies[ name ] = '^' + version 42 | finished = true 43 | } 44 | } 45 | // check devDependencies, if not finished 46 | if (finished === false && appExtJson.devDependencies !== void 0) { 47 | if (appExtJson.devDependencies[ name ] !== void 0) { 48 | appExtJson.devDependencies[ name ] = '^' + version 49 | finished = true 50 | } 51 | } 52 | 53 | if (finished === true) { 54 | writeJson(appExtFile, appExtJson) 55 | console.log(` ⭐️ App Extension version ${ blue(appExtJson.name) } synced with UI version.\n`) 56 | return 57 | } 58 | 59 | console.error(' App Extension version and dependency NOT synced.\n') 60 | } 61 | -------------------------------------------------------------------------------- /ui/build/script.clean.js: -------------------------------------------------------------------------------- 1 | var 2 | rimraf = require('rimraf'), 3 | path = require('path') 4 | 5 | rimraf.sync(path.resolve(__dirname, '../dist/*')) 6 | console.log(' 💥 Cleaned build artifacts.\n') 7 | -------------------------------------------------------------------------------- /ui/build/script.css.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable array-bracket-spacing */ 2 | const path = require('path') 3 | const sass = require('sass') 4 | const postcss = require('postcss') 5 | const cssnano = require('cssnano') 6 | const rtl = require('rtlcss') 7 | const autoprefixer = require('autoprefixer') 8 | 9 | const buildConf = require('./config') 10 | const buildUtils = require('./utils') 11 | 12 | const postCssCompiler = postcss([ autoprefixer ]) 13 | const postCssRtlCompiler = postcss([ rtl({}) ]) 14 | 15 | const nano = postcss([ 16 | cssnano({ 17 | preset: ['default', { 18 | mergeLonghand: false, 19 | convertValues: false, 20 | cssDeclarationSorter: false, 21 | reduceTransforms: false 22 | }] 23 | }) 24 | ]) 25 | 26 | Promise 27 | .all([ 28 | generate('src/index.sass', 'dist/index') 29 | ]) 30 | .catch(e => { 31 | console.error(e) 32 | process.exit(1) 33 | }) 34 | 35 | /** 36 | * Helpers 37 | */ 38 | 39 | function resolve (_path) { 40 | return path.resolve(__dirname, '..', _path) 41 | } 42 | 43 | function generate (src, dest) { 44 | src = resolve(src) 45 | dest = resolve(dest) 46 | 47 | return new Promise((resolve, reject) => { 48 | sass.render({ file: src, includePaths: ['node_modules'] }, (err, result) => { 49 | if (err) { 50 | reject(err) 51 | return 52 | } 53 | 54 | resolve(result.css) 55 | }) 56 | }) 57 | .then(code => buildConf.banner + code) 58 | .then(code => postCssCompiler.process(code, { from: void 0 })) 59 | .then(code => { 60 | code.warnings().forEach(warn => { 61 | console.warn(warn.toString()) 62 | }) 63 | return code.css 64 | }) 65 | .then(code => Promise.all([ 66 | generateUMD(dest, code), 67 | // eslint-disable-next-line promise/no-nesting 68 | postCssRtlCompiler.process(code, { from: void 0 }) 69 | .then(code => generateUMD(dest, code.css, '.rtl')) 70 | ])) 71 | } 72 | 73 | function generateUMD (dest, code, ext = '') { 74 | return buildUtils.writeFile(`${ dest }${ ext }.css`, code, true) 75 | .then(code => nano.process(code, { from: void 0 })) 76 | .then(code => buildUtils.writeFile(`${ dest }${ ext }.min.css`, code.css, true)) 77 | } 78 | -------------------------------------------------------------------------------- /ui/build/script.javascript.js: -------------------------------------------------------------------------------- 1 | process.env.BABEL_ENV = 'production' 2 | 3 | const path = require('path') 4 | const fs = require('fs') 5 | const fse = require('fs-extra') 6 | const rollup = require('rollup') 7 | const uglify = require('uglify-js') 8 | // const buble = require('@rollup/plugin-buble') 9 | const json = require('@rollup/plugin-json') 10 | const { nodeResolve } = require('@rollup/plugin-node-resolve') 11 | 12 | const buildConf = require('./config') 13 | const buildUtils = require('./utils') 14 | 15 | function pathResolve (_path) { 16 | return path.resolve(__dirname, _path) 17 | } 18 | 19 | const rollupPluginsModern = [ 20 | nodeResolve(), 21 | json() 22 | ] 23 | 24 | // const bubleConfig = { 25 | // objectAssign: 'Object.assign' 26 | // } 27 | 28 | // const nodeResolveConfig = { 29 | // extensions: ['.js'], 30 | // preferBuiltins: false 31 | // } 32 | 33 | const uglifyJsOptions = { 34 | compress: { 35 | // turn off flags with small gains to speed up minification 36 | arrows: false, 37 | collapse_vars: false, 38 | comparisons: false, 39 | // computed_props: false, 40 | hoist_funs: false, 41 | hoist_props: false, 42 | hoist_vars: false, 43 | inline: false, 44 | loops: false, 45 | negate_iife: false, 46 | properties: false, 47 | reduce_funcs: false, 48 | reduce_vars: false, 49 | switches: false, 50 | toplevel: false, 51 | typeofs: false, 52 | 53 | // a few flags with noticable gains/speed ratio 54 | booleans: true, 55 | if_return: true, 56 | sequences: true, 57 | unused: true, 58 | 59 | // required features to drop conditional branches 60 | conditionals: true, 61 | dead_code: true, 62 | evaluate: true 63 | } 64 | } 65 | 66 | // const rollupPlugins = [ 67 | // nodeResolve(nodeResolveConfig), 68 | // json(), 69 | // buble(bubleConfig) 70 | // ] 71 | 72 | const buildEntries = [ 73 | 'QIconPicker' 74 | ] 75 | 76 | function generateBuilds () { 77 | const builds = [] 78 | 79 | buildEntries.forEach(entry => { 80 | builds.push({ 81 | rollup: { 82 | input: { 83 | input: pathResolve('../src/index.esm.js') 84 | }, 85 | output: { 86 | file: pathResolve('../dist/index.esm.js'), 87 | format: 'es', 88 | exports: 'auto' 89 | } 90 | }, 91 | build: { 92 | unminified: true, 93 | minified: true, 94 | minExt: true 95 | } 96 | }) 97 | builds.push({ 98 | rollup: { 99 | input: { 100 | input: pathResolve('../src/index.cjs.js') 101 | }, 102 | output: { 103 | file: pathResolve('../dist/index.cjs.js'), 104 | format: 'cjs', 105 | exports: 'auto' 106 | } 107 | }, 108 | build: { 109 | unminified: true, 110 | minified: true, 111 | minExt: true 112 | } 113 | }) 114 | builds.push({ 115 | rollup: { 116 | input: { 117 | input: pathResolve('../src/index.umd.js') 118 | }, 119 | output: { 120 | name: entry, 121 | file: pathResolve('../dist/index.umd.js'), 122 | format: 'umd' 123 | } 124 | }, 125 | build: { 126 | unminified: true, 127 | minified: true, 128 | minExt: true 129 | } 130 | }) 131 | }) 132 | 133 | return builds 134 | } 135 | 136 | const builds = generateBuilds() 137 | 138 | // Add your asset folders here, if needed 139 | addAssets(builds, 'icon-set', 'iconSet') 140 | // addAssets(builds, 'lang', 'lang') 141 | 142 | build(builds) 143 | 144 | /** 145 | * Helpers 146 | */ 147 | 148 | // eslint-disable-next-line no-unused-vars 149 | function addAssets (builds, type, injectName) { 150 | const 151 | files = fs.readdirSync(pathResolve('../../ui/src/components/' + type)), 152 | // plugins = [buble(bubleConfig)], 153 | outputDir = pathResolve(`../dist/${ type }`) 154 | 155 | fse.mkdirp(outputDir) 156 | 157 | files 158 | .filter(file => file.endsWith('.js')) 159 | .forEach(file => { 160 | const name = file.substr(0, file.length - 3).replace(/-([a-z])/g, g => g[ 1 ].toUpperCase()) 161 | builds.push({ 162 | rollup: { 163 | input: { 164 | input: pathResolve(`../src/components/${ type }/${ file }`) 165 | }, 166 | output: { 167 | file: addExtension(pathResolve(`../dist/${ type }/${ file }`), 'umd'), 168 | format: 'umd', 169 | name: `QIconPicker.${ injectName }.${ name }` 170 | } 171 | }, 172 | build: { 173 | minified: true 174 | } 175 | }) 176 | }) 177 | } 178 | 179 | function build (builds) { 180 | return Promise 181 | .all(builds.map(genConfig).map(buildEntry)) 182 | .catch(buildUtils.logError) 183 | } 184 | 185 | function genConfig (opts) { 186 | Object.assign(opts.rollup.input, { 187 | plugins: rollupPluginsModern, 188 | external: [ 'vue', 'quasar' ] 189 | }) 190 | 191 | Object.assign(opts.rollup.output, { 192 | banner: buildConf.banner, 193 | globals: { vue: 'Vue', quasar: 'Quasar' } 194 | }) 195 | 196 | return opts 197 | } 198 | 199 | function addExtension (filename, ext = 'min') { 200 | const insertionPoint = filename.lastIndexOf('.') 201 | return `${ filename.slice(0, insertionPoint) }.${ ext }${ filename.slice(insertionPoint) }` 202 | } 203 | 204 | function injectVueRequirement (code) { 205 | // eslint-disable-next-line quotes 206 | const index = code.indexOf(`Vue = Vue && Vue.hasOwnProperty('default') ? Vue['default'] : Vue`) 207 | 208 | if (index === -1) { 209 | return code 210 | } 211 | 212 | const checkMe = ` if (Vue === void 0) { 213 | console.error('[ QIconPicker ] Vue is required to run. Please add a script tag for it before loading QIconPicker.') 214 | return 215 | } 216 | ` 217 | 218 | return code.substring(0, index - 1) 219 | + checkMe 220 | + code.substring(index) 221 | } 222 | 223 | function buildEntry (config) { 224 | return rollup 225 | .rollup(config.rollup.input) 226 | .then(bundle => bundle.generate(config.rollup.output)) 227 | .then(({ output }) => { 228 | const code = config.rollup.output.format === 'umd' 229 | ? injectVueRequirement(output[ 0 ].code) 230 | : output[ 0 ].code 231 | 232 | return config.build.unminified 233 | ? buildUtils.writeFile(config.rollup.output.file, code) 234 | : code 235 | }) 236 | .then(code => { 237 | if (!config.build.minified) { 238 | return code 239 | } 240 | 241 | // const minified = uglify.minify(code, { 242 | // compress: { 243 | // pure_funcs: ['makeMap'] 244 | // } 245 | // }) 246 | const minified = uglify.minify(code, uglifyJsOptions) 247 | 248 | if (minified.error) { 249 | // eslint-disable-next-line promise/no-return-wrap 250 | return Promise.reject(minified.error) 251 | } 252 | 253 | return buildUtils.writeFile( 254 | config.build.minExt === true 255 | ? addExtension(config.rollup.output.file) 256 | : config.rollup.output.file, 257 | buildConf.banner + minified.code, 258 | true 259 | ) 260 | }) 261 | .catch(err => { 262 | console.error(err) 263 | process.exit(1) 264 | }) 265 | } 266 | -------------------------------------------------------------------------------- /ui/build/script.open-umd.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path') 2 | const open = require('open') 3 | 4 | open( 5 | resolve(__dirname, '../umd-test.html') 6 | ) 7 | -------------------------------------------------------------------------------- /ui/build/script.version.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | // get version 5 | const version = require('../package.json').version 6 | 7 | // read in the template as text 8 | let template = fs.readFileSync(path.resolve(__dirname, './version/version-template.js'), 'utf-8') 9 | 10 | // do the replacement 11 | template = template.replace('__UI_VERSION__', `'${ version }'`) 12 | 13 | // write the file 14 | fs.writeFileSync(path.resolve(__dirname, '../src/version.js'), template, 'utf-8') 15 | -------------------------------------------------------------------------------- /ui/build/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const zlib = require('zlib') 4 | const { green, blue, red, magenta, yellow, underline } = require('kolorist') 5 | 6 | const kebabRegex = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g 7 | const tableData = [] 8 | 9 | const { version, name } = require('../package.json') 10 | 11 | /* 12 | Keep valid tags short - no plural 13 | Try to keep list this list (no additions) 14 | For instance, Fontawesome 'Fruits & Vegetables' 15 | can go into the 'food' tag. 'Currency' and 'Finance' 16 | can go into into 'money' tag. 'Hotel' can go into 17 | the 'travel' tag. 'Audio & Video' can go into the 18 | 'media' tag, etc. 'Animal', 'plants', etc, can all 19 | go into 'nature'. Also, 'buildings' can go to 'map'. 20 | Use 'other' when it cannot be categorized and we 21 | will review to see where it may fit in best. 22 | After modifications, run "yarn build" to validate 23 | and generate new files. 24 | */ 25 | module.exports.validateTags = function (tags) { 26 | const validTags = [ 27 | 'accessibility', 28 | 'alert', 29 | 'arrow', 30 | 'art', 31 | 'brand', 32 | 'buildings', 33 | 'calendar', 34 | 'computer', 35 | 'editor', 36 | 'emotions', 37 | 'family', 38 | 'file', 39 | 'food', 40 | 'health', 41 | 'home', 42 | 'map', 43 | 'media', 44 | 'money', 45 | 'nature', 46 | 'office', 47 | 'other', 48 | 'people', 49 | 'religion', 50 | 'science', 51 | 'social', 52 | 'sport', 53 | 'technology', 54 | 'travel', 55 | 'weather', 56 | 'web' 57 | ] 58 | tags.forEach(tag => { 59 | if (validTags.includes(tag) !== true) { 60 | console.error('\n' + red('[Error]'), `Invalid tag type found: ${ tag }`) 61 | console.log() 62 | process.exit(1) 63 | } 64 | }) 65 | } 66 | 67 | 68 | 69 | process.on('exit', code => { 70 | if (code === 0 && tableData.length > 0) { 71 | const { table } = require('table') 72 | 73 | tableData.sort((a, b) => { 74 | return a[ 0 ] === b[ 0 ] 75 | ? a[ 1 ] < b[ 1 ] ? -1 : 1 76 | : a[ 0 ] < b[ 0 ] ? -1 : 1 77 | }) 78 | 79 | tableData.unshift([ 80 | underline('Ext'), 81 | underline('Filename'), 82 | underline('Size'), 83 | underline('Gzipped') 84 | ]) 85 | 86 | const output = table(tableData, { 87 | columns: { 88 | 0: { alignment: 'right' }, 89 | 1: { alignment: 'left' }, 90 | 2: { alignment: 'right' }, 91 | 3: { alignment: 'right' } 92 | } 93 | }) 94 | 95 | console.log() 96 | console.log(` Summary of ${ name } v${ version }:`) 97 | console.log(output) 98 | } 99 | }) 100 | 101 | function getSize (code) { 102 | return (code.length / 1024).toFixed(2) + 'kb' 103 | } 104 | 105 | module.exports.createFolder = function (folder) { 106 | const dir = path.join(__dirname, '..', folder) 107 | if (!fs.existsSync(dir)) { 108 | fs.mkdirSync(dir) 109 | } 110 | } 111 | 112 | function getDestinationInfo (dest) { 113 | if (dest.endsWith('.json')) { 114 | return { 115 | banner: yellow('[json]'), 116 | tableEntryType: yellow('json'), 117 | toTable: true 118 | } 119 | } 120 | 121 | if (dest.endsWith('.js')) { 122 | return { 123 | banner: green('[js] '), 124 | tableEntryType: green('js'), 125 | toTable: dest.indexOf('dist/') > -1 126 | } 127 | } 128 | 129 | if (dest.endsWith('.css') || dest.endsWith('.styl') || dest.endsWith('.sass')) { 130 | return { 131 | banner: blue('[css] '), 132 | tableEntryType: blue('css'), 133 | toTable: true 134 | } 135 | } 136 | 137 | if (dest.endsWith('.ts')) { 138 | return { 139 | banner: magenta('[ts] '), 140 | tableEntryType: magenta('ts'), 141 | toTable: true 142 | } 143 | } 144 | 145 | logError(`Unknown file type using buildUtils.writeFile: ${ dest }`) 146 | process.exit(1) 147 | } 148 | 149 | module.exports.writeFile = function (dest, code, zip) { 150 | const { banner, tableEntryType, toTable } = getDestinationInfo(dest) 151 | 152 | const fileSize = getSize(code) 153 | const filePath = path.relative(process.cwd(), dest) 154 | 155 | return new Promise((resolve, reject) => { 156 | function report (gzippedString, gzippedSize) { 157 | console.log(`${ banner } ${ filePath.padEnd(49) } ${ fileSize.padStart(8) }${ gzippedString || '' }`) 158 | 159 | if (toTable) { 160 | tableData.push([ 161 | tableEntryType, 162 | filePath, 163 | fileSize, 164 | gzippedSize || '-' 165 | ]) 166 | } 167 | 168 | resolve(code) 169 | } 170 | 171 | fs.writeFile(dest, code, err => { 172 | if (err) return reject(err) 173 | if (zip) { 174 | zlib.gzip(code, (err, zipped) => { 175 | if (err) return reject(err) 176 | const size = getSize(zipped) 177 | report(` (gzipped: ${ size.padStart(8) })`, size) 178 | }) 179 | } 180 | else { 181 | report() 182 | } 183 | }) 184 | }) 185 | } 186 | 187 | module.exports.readFile = function (file) { 188 | return fs.readFileSync(file, 'utf-8') 189 | } 190 | 191 | function logError (err) { 192 | console.error('\n' + red('[Error]'), err) 193 | console.log() 194 | } 195 | 196 | module.exports.logError = logError 197 | 198 | module.exports.kebabCase = function (str) { 199 | return str.replace( 200 | kebabRegex, 201 | match => '-' + match.toLowerCase() 202 | ).substring(1) 203 | } 204 | -------------------------------------------------------------------------------- /ui/build/version/version-template.js: -------------------------------------------------------------------------------- 1 | export const version = __UI_VERSION__ -------------------------------------------------------------------------------- /ui/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6" 5 | }, 6 | "exclude": ["node_modules", "dist"], 7 | "include": ["src/**/*", "build/**/*", "test/**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@quasar/quasar-ui-qiconpicker", 3 | "version": "2.0.7", 4 | "author": "Jeff Galbraith ", 5 | "description": "QIconPicker - Quasar component", 6 | "contributors": [ 7 | { 8 | "name": "Christian Behon", 9 | "email": "christian.behon@knusperleicht.at", 10 | "url": "https://knusperleicht.at" 11 | } 12 | ], 13 | "license": "MIT", 14 | "module": "dist/index.esm.js", 15 | "main": "dist/index.cjs.js", 16 | "typings": "dist/types/index.d.ts", 17 | "scripts": { 18 | "lint": "eslint --ext .js,.vue src", 19 | "lint-fix": "eslint --ext .js,.vue src --fix", 20 | "dev": "cd dev && yarn dev && cd ..", 21 | "dev:umd": "yarn build && node build/script.open-umd.js", 22 | "dev:ssr": "cd dev && yarn 'dev:ssr' && cd ..", 23 | "dev:ios": "cd dev && yarn 'dev:ios' && cd ..", 24 | "dev:android": "cd dev && yarn 'dev:android' && cd ..", 25 | "dev:electron": "cd dev && yarn 'dev:electron' && cd ..", 26 | "build": "node build/index.js", 27 | "build:js": "node build/script.javascript.js", 28 | "build:css": "node build/script.css.js", 29 | "build:api": "node build/build.api.js", 30 | "icons:mdi-v4": "node build/icons/build.mdi-v4.js", 31 | "icons:mdi-v5": "node build/icons/build.mdi-v5.js", 32 | "icons:mdi-v6": "node build/icons/build.mdi-v6.js", 33 | "icons:ion": "node build/icons/build.ion.js", 34 | "icons:eva": "node build/icons/build.eva.js", 35 | "icons:themify": "node build/icons/build.themify.js", 36 | "icons:bootstrap-icons": "node build/icons/build.bootstrap-icons.js", 37 | "icons:fontawesome": "node build/icons/build.fontawesome.js", 38 | "icons:material": "node build/icons/build.google.material-icons.js", 39 | "icons:all": "node build/icons/build.all.js" 40 | }, 41 | "funding": { 42 | "type": "github", 43 | "url": "https://github.com/sponsors/hawkeye64" 44 | }, 45 | "publishConfig": { 46 | "access": "public" 47 | }, 48 | "repository": { 49 | "type": "git", 50 | "url": "git+https://github.com/quasarframework/quasar-ui-qiconpicker.git" 51 | }, 52 | "bugs": "https://github.com/quasarframework/quasar-ui-qiconpicker/issues", 53 | "homepage": "https://github.com/quasarframework/quasar-ui-qiconpicker", 54 | "keywords": [ 55 | "quasar", 56 | "quasarframework", 57 | "iconpicker", 58 | "icon", 59 | "picker" 60 | ], 61 | "vetur": { 62 | "tags": "dist/vetur/tags.json", 63 | "attributes": "dist/vetur/attributes.json" 64 | }, 65 | "devDependencies": { 66 | "@babel/core": "^7.22.1", 67 | "@babel/eslint-parser": "^7.21.8", 68 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 69 | "@babel/preset-env": "^7.22.4", 70 | "@quasar/extras": "^1.16.4", 71 | "@rollup/plugin-buble": "^1.0.2", 72 | "@rollup/plugin-json": "^6.0.0", 73 | "@rollup/plugin-node-resolve": "^15.0.2", 74 | "@rollup/plugin-replace": "^5.0.2", 75 | "@types/node": "^20.2.5", 76 | "@typescript-eslint/eslint-plugin": "^5.59.8", 77 | "@typescript-eslint/parser": "^5.59.8", 78 | "autoprefixer": "^10.4.14", 79 | "cross-fetch": "^3.1.6", 80 | "cssnano": "^6.0.1", 81 | "eslint": "^8.41.0", 82 | "eslint-config-standard": "^17.1.0", 83 | "eslint-plugin-import": "^2.27.5", 84 | "eslint-plugin-jsdoc": "^45.0.0", 85 | "eslint-plugin-node": "^11.1.0", 86 | "eslint-plugin-promise": "^6.1.1", 87 | "eslint-plugin-quasar": "^1.1.0", 88 | "eslint-plugin-vue": "^9.14.1", 89 | "eslint-webpack-plugin": "^4.0.1", 90 | "fs-extra": "^11.1.1", 91 | "kolorist": "^1.8.0", 92 | "open": "^9.1.0", 93 | "postcss": "^8.4.24", 94 | "quasar": "^2.12.0", 95 | "quasar-json-api": "^2.0.0-alpha.3", 96 | "rimraf": "^5.0.1", 97 | "rollup": "^3.23.0", 98 | "rtlcss": "^4.1.0", 99 | "sass": "^1.62.1", 100 | "uglify-js": "^3.17.4", 101 | "zlib": "^1.0.5" 102 | }, 103 | "browserslist": [ 104 | "last 4 Chrome versions", 105 | "last 4 Firefox versions", 106 | "last 2 Edge versions", 107 | "last 4 Safari versions", 108 | "last 4 Android versions", 109 | "last 4 ChromeAndroid versions", 110 | "last 4 FirefoxAndroid versions", 111 | "last 4 iOS versions" 112 | ] 113 | } -------------------------------------------------------------------------------- /ui/src/components/QIconPicker.sass: -------------------------------------------------------------------------------- 1 | 2 | .q-icon-picker 3 | display: flex 4 | flex-direction: column 5 | flex-wrap: nowrap 6 | width: 100% 7 | height: 100% 8 | 9 | &__body 10 | overflow: hidden 11 | flex: 1 1 auto 12 | position: relative 13 | width: 100% 14 | 15 | &__scroll-area 16 | overflow: hidden 17 | flex: 1 1 auto 18 | width: 100% 19 | 20 | &__container 21 | display: flex 22 | flex: 1 1 auto 23 | flex-wrap: wrap 24 | flex-direction: row 25 | justify-content: center 26 | width: 100% 27 | 28 | &__header 29 | width: 100% 30 | 31 | &__footer 32 | width: 100% 33 | -------------------------------------------------------------------------------- /ui/src/index.cjs.js: -------------------------------------------------------------------------------- 1 | 2 | export * from './vue-plugin' 3 | -------------------------------------------------------------------------------- /ui/src/index.esm.js: -------------------------------------------------------------------------------- 1 | 2 | import * as VuePlugin from './vue-plugin' 3 | 4 | export * from './vue-plugin' 5 | export default VuePlugin 6 | -------------------------------------------------------------------------------- /ui/src/index.js: -------------------------------------------------------------------------------- 1 | import QIconPicker from './components/QIconPicker' 2 | 3 | import { version } from './version' 4 | 5 | export { 6 | version, 7 | QIconPicker 8 | } 9 | 10 | export default { 11 | version, 12 | QIconPicker, 13 | 14 | install (Vue) { 15 | Vue.component(QIconPicker.name, QIconPicker) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ui/src/index.sass: -------------------------------------------------------------------------------- 1 | @import './components/QIconPicker.sass' 2 | 3 | -------------------------------------------------------------------------------- /ui/src/index.umd.js: -------------------------------------------------------------------------------- 1 | 2 | // import * as VuePlugin from './vue-plugin' 3 | // export default VuePlugin 4 | export * from './vue-plugin' -------------------------------------------------------------------------------- /ui/src/version.js: -------------------------------------------------------------------------------- 1 | export const version = '2.0.7' -------------------------------------------------------------------------------- /ui/src/vue-plugin.js: -------------------------------------------------------------------------------- 1 | import QIconPicker from './components/QIconPicker' 2 | 3 | import { version } from './version' 4 | 5 | function install (app) { 6 | app.component(QIconPicker.name, QIconPicker) 7 | } 8 | 9 | export { 10 | version, 11 | QIconPicker, 12 | 13 | install 14 | } 15 | -------------------------------------------------------------------------------- /ui/types/types.d.ts: -------------------------------------------------------------------------------- 1 | export type NumberArray = number[] 2 | export type StringArray = string[] 3 | 4 | export type IconName = { 5 | name : string 6 | } 7 | 8 | export type IconNameArray = IconName[] 9 | 10 | export type Pagination = { 11 | /** 12 | * Page number (1-based) 13 | */ 14 | page? : number 15 | /** 16 | * How many rows per page? 0 means Infinite 17 | */ 18 | rowsPerPage? : number 19 | } 20 | 21 | export type PaginationProps = { 22 | /** 23 | * Minimum page (must be lower than 'max') 24 | */ 25 | min? : number 26 | /** 27 | * Number of last page (must be higher than 'min') 28 | */ 29 | max? : number 30 | /** 31 | * Maximum number of page links to display at a time; 0 means Infinite 32 | */ 33 | maxPages? : number 34 | /** 35 | * Put component in disabled mode 36 | */ 37 | disable? : boolean 38 | /** 39 | * Use an input instead of buttons 40 | */ 41 | input? : boolean 42 | /** 43 | * Icon name following Quasar convention; Make sure you have the icon library installed unless you are using 'img:' prefix 44 | */ 45 | iconPrev? : string 46 | /** 47 | * Icon name following Quasar convention; Make sure you have the icon library installed unless you are using 'img:' prefix 48 | */ 49 | iconNext? : string 50 | /** 51 | * Icon name following Quasar convention; Make sure you have the icon library installed unless you are using 'img:' prefix 52 | */ 53 | iconFirst? : string 54 | /** 55 | * Icon name following Quasar convention; Make sure you have the icon library installed unless you are using 'img:' prefix 56 | */ 57 | iconLast? : string 58 | /** 59 | * Generate link for page buttons; For best performance, reference it from your scope and do not define it inline 60 | */ 61 | toFn? : function 62 | /** 63 | * Show boundary button links 64 | */ 65 | boundaryLinks? : boolean 66 | /** 67 | * Always show first and last page buttons (if not using 'input') 68 | */ 69 | boundaryNumbers? : boolean 70 | /** 71 | * Show direction buttons 72 | */ 73 | directionLinks? : boolean 74 | /** 75 | * Show ellipses (...) when pages are available 76 | */ 77 | ellipsis? : boolean 78 | /** 79 | * Color name for component from the Quasar Color Palette 80 | */ 81 | color? : string 82 | /** 83 | * Overrides text color (if needed); Color name from the Quasar Color Palette 84 | */ 85 | textColor? : string 86 | /** 87 | * Color name for component from the Quasar Color Palette 88 | */ 89 | activeColor? : string 90 | /** 91 | * Overrides text color (if needed); Color name from the Quasar Color Palette 92 | */ 93 | activeTextColor? : string 94 | /** 95 | * Notify the component that the background is a dark color (useful when you are using it along with the 'input' prop) 96 | */ 97 | dark? : boolean 98 | /** 99 | * Style definitions to be attributed to the input (if using one) 100 | */ 101 | inputStyle? : array | string | object 102 | /** 103 | * Class definitions to be attributed to the input (if using one) 104 | */ 105 | inputClass? : array | string | object 106 | /** 107 | * Button size in CSS units, including unit name 108 | */ 109 | size? : string 110 | /** 111 | * Configure buttons material ripple (disable it by setting it to 'false' or supply a config object); Does not applies to boundary and ellipsis buttons 112 | */ 113 | ripple? : boolean | object 114 | /** 115 | * Makes a circle shaped button for all buttons 116 | */ 117 | round? : boolean 118 | /** 119 | * Applies a more prominent border-radius for a squared shape button for all buttons 120 | */ 121 | rounded? : boolean 122 | /** 123 | * Use 'flat' design for current page button 124 | */ 125 | flat? : boolean 126 | /** 127 | * Use 'outline' design for current page button 128 | */ 129 | outline? : boolean 130 | /** 131 | * Remove shadow for current page button 132 | */ 133 | unelevated? : boolean 134 | /** 135 | * Use 'push' design for current page button 136 | */ 137 | push? : boolean 138 | /** 139 | * Applies a glossy effect for all buttons 140 | */ 141 | glossy? : boolean 142 | /** 143 | * Dense mode; occupies less space 144 | */ 145 | dense? : boolean 146 | /** 147 | * Apply custom padding (vertical [horizontal]); Size in CSS units, including unit name or standard size name (none|xs|sm|md|lg|xl); Also removes the min width and height when set 148 | */ 149 | padding? : string 150 | 151 | } 152 | 153 | -------------------------------------------------------------------------------- /ui/umd-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | UMD test 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | quasar-ui-qiconpicker v{{ version }} 22 | 23 | 24 |
Quasar v{{ $q.version }}
25 |
26 |
27 | 28 | 29 | 30 |
31 | 37 | 38 | 45 |
46 |
    47 |
  • In /ui, run: "yarn build"
  • 48 |
  • You need to build & refresh page on each change manually.
  • 49 |
  • Use self-closing tags only!
  • 50 |
  • Example: <my-component></my-component>
  • 51 |
52 |
53 |
54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 82 | 83 | 84 | --------------------------------------------------------------------------------