├── .editorconfig ├── .eslintrc ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ └── feature-request.yml └── workflows │ └── cd.yml ├── .gitignore ├── .huskyrc.json ├── .lintstagedrc.json ├── .npmignore ├── .stylelintrc ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── README_zh-hans.md ├── docs ├── .gitignore ├── README.md ├── app.vue ├── assets │ ├── FiraCode-VariableFont.ttf │ └── index.css ├── components │ ├── Box.vue │ ├── Demobox.vue │ ├── Development.vue │ ├── ItHeader.vue │ ├── LandingComponentsBlock.vue │ ├── NotificationExample.vue │ ├── Prism.ts │ ├── PropsTable.vue │ ├── Sidebar.vue │ └── SponsorsBar.vue ├── data │ ├── components.ts │ └── symbols.ts ├── locales │ ├── README.md │ ├── en.ts │ ├── index.ts │ ├── zh-hans.ts │ └── zh-hant.ts ├── nuxt.config.ts ├── package.json ├── pages │ ├── Contribute │ │ ├── index.vue │ │ └── locale │ │ │ ├── en.ts │ │ │ └── zh-hans.ts │ ├── Directives.vue │ ├── Introduction │ │ ├── index.vue │ │ └── locale │ │ │ ├── en.ts │ │ │ └── zh-hans.ts │ ├── Start │ │ ├── index.vue │ │ └── locale │ │ │ ├── en.ts │ │ │ └── zh-hans.ts │ ├── Support │ │ ├── index.vue │ │ └── locale │ │ │ ├── en.ts │ │ │ └── zh-hans.ts │ ├── Theming │ │ ├── index.vue │ │ └── locale │ │ │ ├── en.ts │ │ │ └── zh-hans.ts │ ├── Transitions.vue │ ├── components │ │ ├── Alert │ │ │ ├── index.vue │ │ │ └── locale │ │ │ │ ├── en.ts │ │ │ │ └── zh-hans.ts │ │ ├── Avatar.vue │ │ ├── Badge.vue │ │ ├── Breadcrumbs.vue │ │ ├── Button.vue │ │ ├── Checkbox.vue │ │ ├── Collapse.vue │ │ ├── Colorpicker.vue │ │ ├── Datepicker.vue │ │ ├── Divider.vue │ │ ├── Drawer.vue │ │ ├── Dropdown.vue │ │ ├── Input.vue │ │ ├── Loadingbar.vue │ │ ├── Modal.vue │ │ ├── Notification.vue │ │ ├── NumberInput.vue │ │ ├── Popover.vue │ │ ├── Progressbar.vue │ │ ├── Radio.vue │ │ ├── Select │ │ │ ├── SectionDemo │ │ │ │ └── index.vue │ │ │ ├── SectionExamples │ │ │ │ └── index.vue │ │ │ ├── SectionSlots │ │ │ │ └── index.vue │ │ │ ├── constants.ts │ │ │ └── index.vue │ │ ├── Slider.vue │ │ ├── Spinner.vue │ │ ├── Steps.vue │ │ ├── Switch.vue │ │ ├── Tabs.vue │ │ ├── Tag.vue │ │ ├── Textarea.vue │ │ ├── Toggle.vue │ │ └── Tooltip.vue │ └── index.vue ├── plugins │ ├── emitter.client.ts │ ├── equal.client.ts │ ├── ga.ts │ └── i18n.client.ts ├── public │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── finally.png │ ├── github-logo.svg │ ├── husky.jpg │ ├── logo.png │ ├── logo.svg │ ├── twitter-logo.svg │ └── twitter.png ├── tailwind.config.js ├── tsconfig.json ├── types.ts └── types │ └── Events.ts ├── favicon.ico ├── index.html ├── package.json ├── postcss.config.js ├── prettier.config.js ├── scripts └── prepareTheme.ts ├── src ├── App.vue ├── components │ ├── alert │ │ ├── ItAlert.vue │ │ └── index.ts │ ├── avatar-group │ │ ├── ItAvatarGroup.vue │ │ ├── hooks.ts │ │ ├── index.ts │ │ └── types.ts │ ├── avatar │ │ ├── ItAvatar.vue │ │ └── index.ts │ ├── badge │ │ ├── ItBadge.vue │ │ ├── constants.ts │ │ └── index.ts │ ├── button-group │ │ ├── ItButtonGroup.vue │ │ └── index.ts │ ├── button │ │ ├── ItButton.vue │ │ └── index.ts │ ├── checkbox │ │ ├── ItCheckbox.vue │ │ └── index.ts │ ├── collapse-item │ │ └── index.ts │ ├── collapse │ │ ├── ItCollapse.vue │ │ ├── ItCollapseItem.vue │ │ └── index.ts │ ├── colorpicker │ │ ├── ItColorpicker.vue │ │ ├── helpers.ts │ │ ├── hooks.ts │ │ ├── hooks │ │ │ ├── alpha.ts │ │ │ ├── hue.ts │ │ │ └── saturation.ts │ │ ├── index.ts │ │ └── subcomponents │ │ │ ├── Alpha.vue │ │ │ ├── Checkboard.vue │ │ │ ├── Hue.vue │ │ │ └── Saturation.vue │ ├── datepicker │ │ ├── ItDatepicker.vue │ │ └── index.ts │ ├── divider │ │ ├── ItDivider.vue │ │ └── index.ts │ ├── drawer │ │ ├── ItDrawer.vue │ │ └── index.ts │ ├── dropdown │ │ ├── ItDropdown.vue │ │ ├── ItDropdownItem.vue │ │ ├── ItDropdownMenu.vue │ │ └── index.ts │ ├── input │ │ ├── ItInput.vue │ │ └── index.ts │ ├── loadingbar │ │ ├── ItLoadingbar.vue │ │ └── index.ts │ ├── modal │ │ ├── ItModal.vue │ │ └── index.ts │ ├── notification │ │ ├── ItNotification.vue │ │ └── index.ts │ ├── numberinput │ │ ├── ItNumberInput.vue │ │ └── index.ts │ ├── popover │ │ ├── ItPopover.vue │ │ └── index.ts │ ├── progressbar │ │ ├── ItProgressbar.vue │ │ └── index.ts │ ├── radio │ │ ├── ItRadio.vue │ │ └── index.ts │ ├── select │ │ ├── ItSelect.vue │ │ ├── constants.ts │ │ ├── helpers.ts │ │ ├── hooks.ts │ │ ├── index.ts │ │ └── types.ts │ ├── slider │ │ ├── ItSlider.vue │ │ ├── constants.ts │ │ ├── helpers.ts │ │ ├── hooks.ts │ │ ├── index.ts │ │ └── types.ts │ ├── spinner │ │ ├── ItSpinner.vue │ │ └── index.ts │ ├── switch │ │ ├── ItSwitch.vue │ │ └── index.ts │ ├── tab │ │ └── index.ts │ ├── tabs │ │ ├── ItTab.vue │ │ ├── ItTabs.vue │ │ └── index.ts │ ├── tag │ │ ├── ItTag.vue │ │ └── index.ts │ ├── textarea │ │ ├── ItTextarea.vue │ │ └── index.ts │ ├── toggle │ │ ├── ItToggle.vue │ │ └── index.ts │ └── tooltip │ │ ├── ItTooltip.vue │ │ ├── TooltipBody.vue │ │ └── index.ts ├── directives │ ├── clickOutside.ts │ ├── index.ts │ └── tooltip.ts ├── helpers │ ├── clamp.ts │ ├── getChildrenVNodesFromSlot.ts │ ├── getUpperFirstLettersWords.ts │ └── getVariantProps.ts ├── hooks │ ├── index.ts │ ├── tests │ │ └── useVariant.test.ts │ ├── useCheckSlot.ts │ ├── usePopover.ts │ └── useVariants.ts ├── index.css ├── index.ts ├── main.ts ├── models │ └── enums │ │ ├── Colors.ts │ │ ├── Components.ts │ │ ├── Directions.ts │ │ ├── Positions.ts │ │ ├── Sizes.ts │ │ └── index.ts ├── shims-vue.d.ts ├── theme │ ├── dark.ts │ ├── full.ts │ └── light.ts └── types │ ├── components │ └── components.ts │ ├── global.ts │ ├── index.d.ts │ ├── index.ts │ └── variant.ts ├── tailwind.config.js ├── tsconfig.json └── vite.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es2021": true, 6 | "node": true 7 | }, 8 | "prettier/prettier": [ 9 | "error", 10 | { 11 | "endOfLine": "auto" 12 | } 13 | ], 14 | "extends": [ 15 | "plugin:vue/vue3-recommended", 16 | "eslint:recommended", 17 | "@vue/typescript/recommended", 18 | "@vue/prettier", 19 | "@vue/prettier/@typescript-eslint" 20 | ], 21 | "parser": "vue-eslint-parser", 22 | "parserOptions": { 23 | "parser": "@typescript-eslint/parser", 24 | "ecmaVersion": 2021 25 | }, 26 | "rules": { 27 | "vue/no-unused-vars": "error", 28 | "vue/no-v-html": "off", 29 | "arrow-parens": ["error", "always"], 30 | "padded-blocks": ["error", "never"], 31 | "import/prefer-default-export": "off", 32 | "@typescript-eslint/no-var-requires": "off", 33 | "vue/component-definition-name-casing": [1, "kebab-case"] 34 | } 35 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: savinov 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 up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 🐛 2 | description: Report a bug for Equal Library 🧬 3 | title: '[ Bug Report ] ' 4 | labels: [ 'bug' ] 5 | body: 6 | 7 | - type: textarea 8 | attributes: 9 | label: Environment 10 | placeholder: | 11 | examples: 12 | - **node**: 13.14.0 13 | - **equal**: 0.77.0 14 | value: | 15 | - **node**: 16 | - **equal**: 17 | render: markdown 18 | validations: 19 | required: true 20 | 21 | - type: textarea 22 | attributes: 23 | label: Current Behavior 24 | description: A concise description of what you're experiencing. 25 | validations: 26 | required: true 27 | 28 | - type: textarea 29 | attributes: 30 | label: Expected Behavior 31 | description: A concise description of what you expected to happen. 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | attributes: 37 | label: Steps To Reproduce 38 | description: Steps to reproduce the behavior. 39 | placeholder: | 40 | 1. In this environment... 41 | 2. With this config... 42 | 3. Run '...' 43 | 4. See error... 44 | validations: 45 | required: true 46 | 47 | - type: textarea 48 | attributes: 49 | label: Anything else? 50 | description: | 51 | Links? References? Anything that will give us more context about the issue you are encountering! 52 | 53 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 54 | validations: 55 | required: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request ✨ 2 | description: Suggest a feature for Equal Library 🧬 3 | title: '[ Feature Request ] <title>' 4 | labels: [ 'feature' ] 5 | body: 6 | 7 | - type: textarea 8 | attributes: 9 | label: Is your feature request related to a problem? Please describe. 10 | description: A clear and concise description of what the problem is. 11 | value: "Ex. I'm always frustrated when [...]" 12 | render: markdown 13 | validations: 14 | required: false 15 | 16 | - type: textarea 17 | attributes: 18 | label: Describe the solution you'd like 19 | description: A clear and concise description of what you want to happen. Adding some code examples would be neat! 20 | render: markdown 21 | validations: 22 | required: true 23 | 24 | - type: textarea 25 | attributes: 26 | label: Describe alternatives you've considered 27 | description: A clear and concise description of any alternative solutions or features you've considered 28 | render: markdown 29 | validations: 30 | required: true 31 | 32 | - type: textarea 33 | attributes: 34 | label: Additional context 35 | description: Add any other context or screenshots about the feature request here. 36 | render: markdown 37 | validations: 38 | required: false 39 | 40 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: cd 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | pull-requests: write 7 | issues: write 8 | repository-projects: write 9 | contents: write 10 | 11 | jobs: 12 | cd: 13 | runs-on: ${{ matrix.os }} 14 | # defaults: 15 | # run: 16 | # working-directory: ./docs 17 | 18 | strategy: 19 | matrix: 20 | os: [ubuntu-latest] 21 | node: [19] 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@master 26 | 27 | - name: Setup node env 28 | uses: actions/setup-node@v3 29 | with: 30 | node-version: 20 31 | 32 | - name: Install dependencies 33 | run: yarn 34 | 35 | - name: Install dependencies of docs 36 | working-directory: ./docs 37 | run: yarn 38 | 39 | - name: Generate 40 | working-directory: ./docs 41 | run: yarn generate 42 | 43 | - name: Deploy 44 | uses: peaceiris/actions-gh-pages@v3 45 | with: 46 | github_token: ${{ secrets.GITHUB_TOKEN }} 47 | publish_dir: ./docs/dist 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | /logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | package-lock.json 10 | yarn.lock 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (https://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env.local 63 | .env.*.local 64 | 65 | # parcel-bundler cache (https://parceljs.org/) 66 | .cache 67 | 68 | # next.js build output 69 | .next 70 | 71 | # nuxt.js build output 72 | .nuxt 73 | 74 | # Nuxt generate 75 | dist 76 | 77 | # vuepress build output 78 | .vuepress/dist 79 | 80 | # Serverless directories 81 | .serverless 82 | 83 | # IDE / Editor 84 | .idea 85 | .vscode 86 | 87 | # Service worker 88 | sw.* 89 | 90 | # macOS 91 | .DS_Store 92 | 93 | # Vim swap files 94 | *.swp 95 | 96 | # Working directory files 97 | draft 98 | *.local 99 | 100 | # Testing files 101 | cypress/screenshots -------------------------------------------------------------------------------- /.huskyrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "lint-staged" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "src/**/*.{ts,vue}": [ 3 | "yarn lint:prettier" 4 | ], 5 | "docs/**/*.{ts,vue}": [ 6 | "yarn lint:prettier" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | public/ 2 | docs/ 3 | tests/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | .travis.yml 8 | *.map 9 | dist/demo.html 10 | 11 | .idea 12 | .vscode/* 13 | !dist/extensions.json 14 | .bitmap 15 | *.suo 16 | *.ntvs* 17 | *.njsproj 18 | *.sln 19 | .github/ -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-recommended", "stylelint-config-standard"], 3 | "ignoreFiles": [ 4 | "node_modules/**/*" 5 | ] 6 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '15' 4 | 5 | cache: 6 | directories: 7 | - 'node_modules' 8 | 9 | branches: 10 | only: 11 | - master 12 | 13 | before_install: 14 | - cp -R ./src ./docs/src/equal 15 | - cd docs 16 | 17 | install: 18 | - npm install 19 | - npm run build_prod 20 | - sh 404.sh 21 | 22 | script: 23 | - echo "Skipping tests" 24 | 25 | deploy: 26 | provider: pages 27 | skip-cleanup: true 28 | github-token: $GITHUB_ACCESS_TOKEN # Set in travis-ci.org dashboard, marked secure https://docs.travis-ci.com/user/deployment/pages/#Setting-the-GitHub-token 29 | target-branch: gh-pages 30 | local-dir: docs/dist 31 | on: 32 | branch: master 33 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at yan.savinov.hire@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 👍🎉 First off, thanks for taking the time to contribute! 🎉👍 4 | 5 | It takes a lot of courage to even visit this section. I sincerely appreciate it. Please follow the guidelines in this document to get you started with the repo and codebase. 6 | 7 | ## Feature Request ✨ 8 | 9 | 1. Make sure there is no body suggested your feature before 10 | 2. Follow the "Feature Request" template 11 | 3. Keep discussing with the team to find the best way to impelement your feature 12 | 13 | ## Bug Report 🐛 14 | 15 | 1. Make sure there is no body suggested your feature before 16 | 2. Follow the "Bug Report" template 17 | 18 | ## Contributing 🛠 19 | 20 | 1. Follow [Feature request](#feature-request) rules to add a feature request ( ex. `[ Feature Request ] Add "party 🎈" feature` ) 21 | 2. Fork the repo 22 | 3. Clone the repo `git clone <your-fork-url>` 23 | 4. Create new branch ( ex. `feat/party` ) for more details follow [gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) rules 24 | 5. Follow the steps of [Development](#development) section 25 | 6. Commit your work linked with the issue ( ex. `close #1` ) 26 | 7. Push the changes to the fork `git push fork feat/add-party` 27 | 8. Create pull request from your branch `feat/party` to our `master` branch 28 | 29 | ## Development 👨‍💻 30 | 31 | 1. Install dependencies: `npm i` or `yarn` 32 | 2. Run the dev server: `npm run dev` or `yarn dev` it will show all components list on `localhost:3000`; For full docs go to `/docs`, run `npm i && npm run dev` 33 | 3. Edit the source code within `/src` 34 | 4. Check changes on `localhost:3000` 35 | 5. Commit your work `git commit -m "feat( fun ): add a party"` for more details check [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 quatrochan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | <p align="center"> 2 | <a href="https://equal-ui.github.io/Equal/"> 3 | <img width="150" src="./docs/public/logo.svg"> 4 | </a> 5 | 6 | <p align="center"> 7 | <img src="https://img.shields.io/npm/v/equal-vue?color=blue"> 8 | <img src="https://img.shields.io/npm/l/equal-vue"> 9 | </p> 10 | </p> 11 | 12 | <h1 align="center"> 13 | Equal UI 14 | </h2> 15 | 16 | <div align="center"> 17 | Equal UI is a Vue 3 hackable components library with 30+ components on top of Tailwindcss 18 | <br> 19 | <a href="https://equal-ui.github.io/Equal/"><strong>Explore Equal UI docs</strong></a> 20 | </div> 21 | 22 | <br> 23 | <div align="center"> 24 | <span><strong>English</strong></span> 25 | | 26 | <a href="./README_zh-hans.md">中文简体</a> 27 | </div> 28 | 29 | # Features 30 | 31 | - 🔥 One of the best visuals in Vue ecosystem 32 | - 🌃 Built-in dark theme 33 | - 🎨 Full customization 34 | - 💬 Have tooltips, notifications, popovers 35 | - 👌 Lightweight: 12KB brotli 36 | - 🔧 Includes 30+ components 37 | - 💅 Uses your Tailwindcss classes 38 | 39 | # Links 40 | 41 | <b> Twitter: </b> [@Yan](https://twitter.com/k0mmsussertod) 42 | 43 | # Install 44 | 45 | You need [Vue.js](https://v3.vuejs.org/) version 3.1+ 46 | 47 | ```bash 48 | # npm 49 | npm install equal-vue 50 | ``` 51 | 52 | ```bash 53 | # yarn 54 | yarn add equal-vue 55 | ``` 56 | 57 | # Usage 58 | 59 | ## All components 60 | 61 | ```js 62 | import { createApp } from 'vue' 63 | import Equal from 'equal-vue' 64 | import Config from 'equal-vue/dist/theme/full' // or light / dark theme 65 | 66 | createApp.use(Equal, Config) 67 | ``` 68 | 69 | ## Or individual components 70 | 71 | ```js 72 | import { createApp } from 'vue' 73 | import { Button, Switch } from 'equal-vue' 74 | import Config from 'equal-vue/dist/theme/full' // or light / dark theme 75 | 76 | createApp.use(Button, Config).use(Switch, Config) 77 | ``` 78 | 79 | # License 80 | 81 | [MIT](https://raw.githubusercontent.com/Equal-UI/Equal/master/LICENSE) 82 | -------------------------------------------------------------------------------- /README_zh-hans.md: -------------------------------------------------------------------------------- 1 | <p align="center"> 2 | <a href="https://equal-ui.github.io/Equal/"> 3 | <img width="150" src="./docs/public/logo.svg"> 4 | </a> 5 | 6 | <p align="center"> 7 | <img src="https://img.shields.io/npm/v/equal-vue?color=blue"> 8 | <img src="https://img.shields.io/npm/l/equal-vue"> 9 | </p> 10 | </p> 11 | 12 | <h1 align="center"> 13 | Equal UI 14 | </h2> 15 | 16 | <div align="center"> 17 | Equal UI 是一个 Vue 3 可拆解的组件库,在 Tailwindcss 之上包含 30+ 个组件 18 | <br> 19 | <a href="https://equal-ui.github.io/Equal/"><strong>探索 Equal UI 文档</strong></a> 20 | </div> 21 | 22 | <br> 23 | <div align="center"> 24 | <a href="./README.md">English</a> 25 | | 26 | <span><strong>中文简体</strong></span> 27 | </div> 28 | 29 | # 特征 30 | 31 | - 🔥 Vue 生态系统中最好的视觉效果之一 32 | - 🌃 内置深色主题 33 | - 🎨 完全定制 34 | - 💬 有工具提示、通知、弹出框 35 | - 👌 轻量级:12KB brotli 36 | - 🔧 包括 30+ 组件 37 | - 💅 使用你的顺风类 38 | 39 | # 链接 40 | 41 | <b> Twitter: </b> [@Yan](https://twitter.com/k0mmsussertod) 42 | 43 | # 安装 44 | 45 | 你需要 [Vue.js](https://v3.vuejs.org/) 版本 3.1+ 46 | 47 | ```bash 48 | # npm 49 | npm install equal-vue 50 | ``` 51 | 52 | ```bash 53 | # yarn 54 | yarn add equal-vue 55 | ``` 56 | 57 | # 用法 58 | 59 | ## 所有组件 60 | 61 | ```js 62 | import { createApp } from 'vue' 63 | import Equal from 'equal-vue' 64 | import Config from 'equal-vue/dist/theme/full' // or light / dark theme 65 | 66 | createApp.use(Equal, Config) 67 | ``` 68 | 69 | ## 或单个组件 70 | 71 | ```js 72 | import { createApp } from 'vue' 73 | import { Button, Switch } from 'equal-vue' 74 | import Config from 'equal-vue/dist/theme/full' // or light / dark theme 75 | 76 | createApp.use(Button, Config).use(Switch, Config) 77 | ``` 78 | 79 | # 许可证 80 | 81 | [MIT](https://raw.githubusercontent.com/Equal-UI/Equal/master/LICENSE) 82 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Nuxt 3 Minimal Starter 2 | 3 | Look at the [nuxt 3 documentation](https://v3.nuxtjs.org) to learn more. 4 | 5 | ## Setup 6 | 7 | Make sure to install the dependencies: 8 | 9 | ```bash 10 | # yarn 11 | yarn install 12 | 13 | # npm 14 | npm install 15 | 16 | # pnpm 17 | pnpm install --shamefully-hoist 18 | ``` 19 | 20 | ## Development Server 21 | 22 | Start the development server on http://localhost:3000 23 | 24 | ```bash 25 | npm run dev 26 | ``` 27 | 28 | ## Production 29 | 30 | Build the application for production: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | Locally preview production build: 37 | 38 | ```bash 39 | npm run preview 40 | ``` 41 | 42 | Checkout the [deployment documentation](https://v3.nuxtjs.org/docs/deployment) for more information. 43 | -------------------------------------------------------------------------------- /docs/app.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="min-h-screen"> 3 | <span v-if="isDev" class="fixed bottom-2 right-2 z-50 dark:text-white"> 4 | fps: {{ fps }} 5 | </span> 6 | <div class="flex dark:bg-neutral-900"> 7 | <ItHeader /> 8 | <Sidebar /> 9 | <div 10 | class="flex h-full min-h-screen max-w-full flex-1 flex-row overflow-hidden bg-white pl-0 dark:bg-zinc-900 dark:text-white lg:ml-60 xl:ml-60" 11 | > 12 | <!-- <img 13 | class="fixed -top-1/2 left-0 w-full opacity-0 dark:opacity-10" 14 | src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGOSURBVHgBvVFLbhNBEH1V3T2emdg4AfxJFO9AoMkKxAFYI3Ens+YEnIMDsEKsWIDIbIgQigSWg+wIz3i+1d00YkMukFq9V6pXVa+K3rx8mw6UOo5EZd65pyB+WCTR8Nf9dH85H3/7OR1/Xs2HX7Ykq++fDkuNODYd9Ahwp6qRx8rSI80YcYOGOgzZ+XogcoWJuc4yVHprYo6I4oh5zK27y8RHda9HVZt0Ukd7bnnetxhzqaJqAta0SFyxIdhCgZRRYrXuxKimZG2v44SMSZXSJhoiDAX0x9msm63LPUlcoQ+1jfbOKvY9MwnMoGd15EPnBO59D6fx4dTWd1Y77v0Vi157RwsvKqjg2VEdwTcHrm8aBEcvguDsDHJ+botY4gtj6R6YOjaYeGIVDrEN7Oug4PVBLu3yNRwBnrIsN8+OF6Owwwm1/kQRDsWSUoYqR3bVS3L5YJNuljl1GiCf5+im03e/n1w8r3aL3Y/wk8hJzZ2NJZn6tlynNfJXEjyDcCP8X07L/zIB+3+IPG4l/gCInrnOZomQAAAAAABJRU5ErkJggg==" 15 | /> --> 16 | <div 17 | class="z-10 flex flex-1 flex-col overflow-hidden px-4 py-24 md:px-14" 18 | > 19 | <NuxtPage /> 20 | </div> 21 | <div class="hidden h-16 w-64 px-4 lg:flex"></div> 22 | <div class="top-18 fixed right-6 mt-16 hidden h-16 w-64 px-4 lg:flex"> 23 | <SponsorsBar /> 24 | </div> 25 | </div> 26 | </div> 27 | </div> 28 | </template> 29 | 30 | <script lang="ts" setup> 31 | import { Emitter } from 'mitt' 32 | import { inject, onMounted, watch, ref } from 'vue' 33 | import { TEvents } from './types/Events' 34 | import { useFps } from '@vueuse/core' 35 | import SponsorsBar from './components/SponsorsBar' 36 | import { useNotification } from '@/' 37 | const isDev = process.env.NODE_ENV === 'development' 38 | 39 | const fps = isDev ? useFps() : 0 40 | 41 | const dark = ref(false) 42 | const emitter = inject<Emitter<TEvents>>('emitter') 43 | const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)') 44 | const themeListener = (e: MediaQueryListEvent) => { 45 | const darkModeOn = e.matches 46 | dark.value = darkModeOn 47 | } 48 | darkModeMediaQuery.addListener(themeListener) 49 | emitter!.on('theme', (theme) => { 50 | if (['dark', 'light'].includes(theme)) { 51 | darkModeMediaQuery.removeEventListener('change', themeListener) 52 | dark.value = theme === 'dark' ? true : false 53 | } 54 | }) 55 | 56 | onMounted(() => { 57 | dark.value = darkModeMediaQuery.matches 58 | emitter?.emit('theme', dark.value ? 'dark' : 'light') 59 | }) 60 | 61 | watch(dark, (newValue, oldValue) => { 62 | if (newValue === true && oldValue !== true) { 63 | document.body.classList.add('dark') 64 | return 65 | } 66 | document.body.classList.remove('dark') 67 | }) 68 | </script> 69 | -------------------------------------------------------------------------------- /docs/assets/FiraCode-VariableFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/assets/FiraCode-VariableFont.ttf -------------------------------------------------------------------------------- /docs/components/Development.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="relative z-0 flex flex-1 flex-col"> 3 | <div class="fancybox"></div> 4 | <div 5 | class="fancy-shadow relative flex-1 items-center justify-center rounded bg-white px-4 py-16 dark:border-black dark:bg-zinc-800" 6 | > 7 | <h1 8 | class="mb-2 bg-gradient-to-r from-rose-400 via-fuchsia-500 to-indigo-500 bg-clip-text text-center text-2xl font-bold text-transparent" 9 | > 10 | Magic happens here 11 | </h1> 12 | <h2 class="text-md text-center text-zinc-400"> 13 | This component is in development 14 | </h2> 15 | <h2 class="text-md text-center text-zinc-400">Coming with 1.0</h2> 16 | </div> 17 | </div> 18 | </template> 19 | -------------------------------------------------------------------------------- /docs/components/NotificationExample.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="flex flex-row items-center justify-center space-x-3"> 3 | <it-badge variant="danger" round point> 4 | <svg 5 | xmlns="http://www.w3.org/2000/svg" 6 | fill="none" 7 | viewBox="0 0 24 24" 8 | stroke-width="1.5" 9 | stroke="currentColor" 10 | class="h-5" 11 | > 12 | <path 13 | stroke-linecap="round" 14 | stroke-linejoin="round" 15 | d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" 16 | /> 17 | </svg> 18 | </it-badge> 19 | <p>You have a new message</p> 20 | </div> 21 | </template> 22 | 23 | <script lang="ts"> 24 | import { defineComponent } from 'vue' 25 | import ItBadge from '@/components/badge/ItBadge.vue' 26 | 27 | export default defineComponent({ 28 | components: { 29 | ItBadge, 30 | }, 31 | props: {}, 32 | }) 33 | </script> 34 | -------------------------------------------------------------------------------- /docs/components/Prism.ts: -------------------------------------------------------------------------------- 1 | import { defineComponent, h } from 'vue' 2 | 3 | function _interopDefault(ex) { 4 | return ex && typeof ex === 'object' && 'default' in ex ? ex.default : ex 5 | } 6 | 7 | import 'prismjs' 8 | import 'prismjs/components/prism-bash.min.js' 9 | import 'prismjs/plugins/autolinker/prism-autolinker.min' 10 | import 'prismjs/plugins/autolinker/prism-autolinker.css' 11 | import 'prismjs/plugins/keep-markup/prism-keep-markup' 12 | 13 | function substrPositions(str, substr) { 14 | const indices = [] 15 | 16 | let indexOccurence = str.indexOf(substr, 0) 17 | 18 | while (indexOccurence >= 0) { 19 | indices.push(indexOccurence) 20 | 21 | indexOccurence = str.indexOf(substr, indexOccurence + 1) 22 | } 23 | return indices 24 | } 25 | 26 | function assign(obj) { 27 | for (let i = 1; i < arguments.length; i++) { 28 | // eslint-disable-next-line guard-for-in, prefer-rest-params 29 | for (const p in arguments[i]) { 30 | obj[p] = arguments[i][p] 31 | } 32 | } 33 | 34 | return obj 35 | } 36 | 37 | function mark(str: string) { 38 | let newstr = str 39 | 40 | while (newstr.includes('<span class="token attr-name">|||</span>')) { 41 | newstr = newstr 42 | .replace( 43 | '<span class="token attr-name">|||</span> ', 44 | '<span class="highlight-range">', 45 | ) 46 | .replace(' <span class="token attr-name">|||</span>', '</span>') 47 | } 48 | while (newstr.includes(' ||| ')) { 49 | newstr = newstr 50 | .replace('||| ', '<span class="highlight-range">') 51 | .replace(' |||', '</span>') 52 | } 53 | return newstr 54 | } 55 | 56 | export default defineComponent({ 57 | name: 'prism', 58 | props: { 59 | code: { 60 | type: String, 61 | }, 62 | inline: { 63 | type: Boolean, 64 | default: false, 65 | }, 66 | language: { 67 | type: String, 68 | default: 'markup', 69 | }, 70 | }, 71 | render: function render(ctx) { 72 | const code = 73 | ctx.$props.code || 74 | (ctx.children && ctx.children.length > 0 ? ctx.children[0].text : '') 75 | const inline = ctx.$props.inline 76 | const language = ctx.$props.language 77 | const prismLanguage = Prism.languages[language] 78 | const className = 'language-'.concat(language) 79 | if (process.env.NODE_ENV === 'development' && !prismLanguage) { 80 | throw new Error( 81 | 'Prism component for language "'.concat( 82 | language, 83 | '" was not found, did you forget to register it? See all available ones: https://cdn.jsdelivr.net/npm/prismjs/components/', 84 | ), 85 | ) 86 | } 87 | 88 | if (inline) { 89 | return h( 90 | 'code', 91 | assign({}, ctx.$data, { 92 | class: [ctx.$data.class, className], 93 | domProps: assign({}, ctx.$data.domProps, { 94 | innerHTML: mark(Prism.highlight(code, prismLanguage)), 95 | }), 96 | }), 97 | ) 98 | } 99 | 100 | return h( 101 | 'pre', 102 | assign({}, ctx.$data, { 103 | class: [ctx.$data.class, className], 104 | }), 105 | [ 106 | h('code', { 107 | class: className, 108 | innerHTML: mark(Prism.highlight(code, prismLanguage)), 109 | }), 110 | ], 111 | ) 112 | }, 113 | }) 114 | -------------------------------------------------------------------------------- /docs/components/SponsorsBar.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div class="flex w-full flex-col"> 3 | <p class="text-sm font-bold">{{ $t('sponsoring.title') }}</p> 4 | <NuxtLink to="/support" class="mt-2 w-full"> 5 | <div 6 | class="flex flex-col items-center justify-center gap-3 rounded-md border border-dashed border-zinc-200 p-2 text-center leading-4 hover:border-zinc-300 dark:border-zinc-600 hover:dark:border-zinc-500" 7 | > 8 | <h5 9 | class="text-md bg-gradient-to-tr from-blue-500 to-violet-600 bg-clip-text font-bold text-transparent" 10 | > 11 | {{ $t('sponsoring.first_sponsor') }} 12 | </h5> 13 | <p class="text-xs leading-4"> 14 | {{ $t('sponsoring.text') }} 15 | </p> 16 | </div> 17 | </NuxtLink> 18 | </div> 19 | </template> 20 | -------------------------------------------------------------------------------- /docs/data/symbols.ts: -------------------------------------------------------------------------------- 1 | export const uiConfig = Symbol.for('uiConfig') 2 | export const initialUIConfig = Symbol.for('initialUIConfig') 3 | -------------------------------------------------------------------------------- /docs/locales/README.md: -------------------------------------------------------------------------------- 1 | # Localizations 2 | 3 | This folder contains the language files for the project. To add a new language or update the existing language files, you can create a Pull Request (PR) with the new or updated files. Please make sure to update all language files with the same changes. 4 | Once your PR is approved, the new language files will be added to the project. 5 | Thank you for contributing to the project! 6 | -------------------------------------------------------------------------------- /docs/locales/index.ts: -------------------------------------------------------------------------------- 1 | import en from './en' 2 | import zhHans from './zh-hans' 3 | import zhHant from './zh-hant' 4 | 5 | export { en, zhHans, zhHant } 6 | -------------------------------------------------------------------------------- /docs/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://v3.nuxtjs.org/api/configuration/nuxt.config 2 | export default defineNuxtConfig({ 3 | app: { 4 | baseURL: '/Equal/', 5 | head: { 6 | title: 'Equal UI', 7 | meta: [ 8 | { 9 | name: 'description', 10 | content: 'Equal is a Vue UI library based on TypeScript', 11 | }, 12 | { name: 'twitter:card', content: 'summary_large_image' }, 13 | { name: 'twitter:site', content: '@EqualVue' }, 14 | { name: 'twitter:creator', content: '@k0mmsussertod' }, 15 | { 16 | name: 'twitter:image', 17 | content: 'https://equal-ui.github.io/Equal/twitter.png', 18 | }, 19 | { 20 | property: 'og:url', 21 | content: 'https://equal-ui.github.io/Equal/Equal/', 22 | }, 23 | { property: 'og:title', content: 'Equal UI' }, 24 | { 25 | property: 'og:description', 26 | content: 27 | 'Equal UI – open-source Vue 3 components system for your next project', 28 | }, 29 | { 30 | property: 'og:image', 31 | content: 'https://equal-ui.github.io/Equal/twitter.png', 32 | }, 33 | ], 34 | link: [ 35 | { rel: 'icon', type: 'image/x-icon', href: '/Equal/favicon.ico' }, 36 | { 37 | rel: 'stylesheet', 38 | href: 'https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined', 39 | }, 40 | { 41 | rel: 'stylesheet', 42 | href: 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;900&display=swap', 43 | }, 44 | { 45 | rel: 'stylesheet', 46 | href: 'https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;900', 47 | }, 48 | ], 49 | }, 50 | }, 51 | target: 'static', 52 | router: { 53 | base: '/Equal/', 54 | }, 55 | css: ['assets/index.css'], 56 | alias: { 57 | '@': '/../src', 58 | }, 59 | postcss: { 60 | plugins: { 61 | tailwindcss: {}, 62 | autoprefixer: {}, 63 | }, 64 | }, 65 | ssr: false, 66 | nitro: { 67 | esbuild: { 68 | options: { 69 | target: 'esnext', 70 | }, 71 | }, 72 | }, 73 | }) 74 | 75 | // alias: { 76 | // '@': '/../src', 77 | // '@floating-ui': './node_modules/@floating-ui', 78 | // '@floating-ui/dom': './node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs', 79 | // '@vueuse/integrations/useFocusTrap': 80 | // './node_modules/@vueuse/integrations/useFocusTrap', 81 | // 'body-scroll-lock': './node_modules/body-scroll-lock', 82 | // colord: './node_modules/colord/index.js', 83 | // }, 84 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "nuxt build", 5 | "dev": "nuxt dev", 6 | "generate": "nuxt generate", 7 | "preview": "nuxt preview" 8 | }, 9 | "devDependencies": { 10 | "@nuxt/postcss8": "^1.1.3", 11 | "autoprefixer": "^10.4.5", 12 | "nuxt": "^3.1.0", 13 | "postcss": "^8.4.12", 14 | "tailwindcss": "^3.1.0", 15 | "vue-i18n": "^9.2.2" 16 | }, 17 | "dependencies": { 18 | "@docsearch/js": "^3.0.0", 19 | "@floating-ui/dom": "^0.5.4", 20 | "@vueuse/core": "^9.3.1", 21 | "@vueuse/integrations": "^5.0.3", 22 | "body-scroll-lock": "^3.1.5", 23 | "colord": "^2.9.2", 24 | "mitt": "^3.0.0", 25 | "prismjs": "^1.28.0", 26 | "tailwind-merge": "^1.13.2", 27 | "vue-gtag": "^2.0.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/pages/Contribute/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold"> 4 | {{ $t('contribute.title') }} 5 | </h1> 6 | <div 7 | class="flex w-full flex-col rounded border bg-white p-8 dark:border-neutral-700 dark:bg-neutral-800" 8 | > 9 | <h2 class="text-lg font-medium"> 10 | {{ $t(`contribute.welcome.title`) }} 11 | </h2> 12 | 13 | <p class="my-4"> 14 | {{ $t(`contribute.welcome.description`) }} 15 | </p> 16 | 17 | <h3 class="text-base font-medium"> 18 | {{ $t(`contribute.contributeWays.title`) }} 19 | </h3> 20 | 21 | <p class="my-4"> 22 | {{ $t(`contribute.contributeWays.description`) }} 23 | </p> 24 | 25 | <ul class="list-inside list-disc"> 26 | <li class="my-2" v-for="index in [1, 2, 3, 4, 5]" :key="index"> 27 | <strong> 28 | {{ $t(`contribute.contributeWays.way${index}.label`) }} 29 | </strong> 30 | {{ $t(`contribute.contributeWays.way${index}.content`) }} 31 | </li> 32 | </ul> 33 | 34 | <h3 class="mt-4 text-base font-semibold"> 35 | {{ $t(`contribute.submissionSteps.title`) }} 36 | </h3> 37 | 38 | <p class="my-4"> 39 | {{ $t(`contribute.submissionSteps.description`) }} 40 | </p> 41 | 42 | <ol class="list-inside list-decimal"> 43 | <li class="my-2" v-for="index in [1, 2, 3, 4, 5]" :key="index"> 44 | <strong> 45 | {{ $t(`contribute.submissionSteps.step${index}.label`) }} 46 | </strong> 47 | {{ $t(`contribute.submissionSteps.step${index}.content`) }} 48 | </li> 49 | </ol> 50 | 51 | <h3 class="mt-4 text-base font-semibold"> 52 | {{ $t(`contribute.codeOfConduct.title`) }} 53 | </h3> 54 | 55 | <p class="my-4"> 56 | {{ $t(`contribute.codeOfConduct.description`) }} 57 | <a 58 | href="https://github.com/Equal-UI/Equal/blob/master/CODE_OF_CONDUCT.md" 59 | target="_blank" 60 | rel="noopener noreferrer" 61 | class="underline" 62 | > 63 | {{ $t(`contribute.codeOfConduct.title`) }} 64 | </a> 65 | </p> 66 | 67 | <h3 class="text-base font-semibold"> 68 | {{ $t(`contribute.contact.title`) }} 69 | </h3> 70 | 71 | <p class="my-4"> 72 | {{ $t(`contribute.contact.description`) }} 73 | </p> 74 | 75 | <p class="mt-6"> 76 | {{ $t(`contribute.thanks`) }} 77 | </p> 78 | </div> 79 | </div> 80 | </template> 81 | -------------------------------------------------------------------------------- /docs/pages/Contribute/locale/en.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | title: 'Contribute', 3 | welcome: { 4 | title: 'Contributing to Equal UI', 5 | description: 6 | "We welcome contributions to Equal UI! If you're interested in helping to improve the project, please take a moment to read through this document to understand how you can get involved.", 7 | }, 8 | contributeWays: { 9 | title: 'Ways to Contribute', 10 | description: 11 | 'There are many ways you can contribute to Equal UI, including:', 12 | way1: { 13 | label: 'Reporting bugs:', 14 | content: 15 | "If you find a bug in the project, please report it by creating an issue in the project's issue tracker. Be sure to include as much information as possible, including the version of the project you're using and any error messages you're receiving.", 16 | }, 17 | way2: { 18 | label: 'Fixing bugs:', 19 | content: 20 | "If you're interested in fixing bugs, take a look at the open issues in the project's issue tracker and see if there's anything you can help with.", 21 | }, 22 | way3: { 23 | label: 'Adding new features:', 24 | content: 25 | 'If you have an idea for a new feature that would be a good addition to the project, please create an issue to discuss it with the project maintainers. If the feature is accepted, feel free to submit a pull request with your implementation.', 26 | }, 27 | way4: { 28 | label: 'Improving documentation:', 29 | content: 30 | 'If you notice that the documentation for the project is lacking or could be improved, please submit a pull request with your changes.', 31 | }, 32 | way5: { 33 | label: 'Providing feedback:', 34 | content: 35 | "If you have feedback on the project (good or bad), please share it by creating an issue in the project's issue tracker.", 36 | }, 37 | }, 38 | submissionSteps: { 39 | title: 'Submitting Changes', 40 | content: 'To submit changes to Equal UI, please follow these steps:', 41 | step1: { 42 | label: 'Fork the repository:', 43 | content: 44 | "Fork the project's repository to your own GitHub account. This will create a copy of the repository that you can make changes to.", 45 | }, 46 | step2: { 47 | label: 'Create a new branch:', 48 | content: 49 | 'Create a new branch on your fork of the repository for your changes. This helps to keep your changes organized and separate from other work being done on the project.', 50 | }, 51 | step3: { 52 | label: 'Make your changes:', 53 | content: 54 | "Make the changes you want to submit to the project. Be sure to follow the project's coding style and conventions, and make sure that your changes are well-documented.", 55 | }, 56 | step4: { 57 | label: 'Commit your changes:', 58 | content: 59 | 'Commit your changes to your new branch. Be sure to write a good commit message that clearly describes your changes.', 60 | }, 61 | step5: { 62 | label: 'Submit a pull request:', 63 | content: 64 | "Submit a pull request to the project's repository. In the pull request, be sure to explain what your changes do and why they're necessary.", 65 | }, 66 | }, 67 | codeOfConduct: { 68 | title: 'Code of Conduct', 69 | description: 70 | "By participating in this project, you agree to abide by the project's", 71 | }, 72 | contact: { 73 | title: 'Contact', 74 | description: 75 | 'If you have any questions or need help getting started, feel free to contact the project maintainers.', 76 | }, 77 | thanks: 'Thanks for your interest in contributing to Equal UI!', 78 | } 79 | -------------------------------------------------------------------------------- /docs/pages/Contribute/locale/zh-hans.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | title: '贡献', 3 | welcome: { 4 | title: '贡献给 Equal UI', 5 | description: 6 | '欢迎为 Equal UI 做出贡献!如果你有兴趣帮助改进该项目,请花点时间阅读本文档,了解如何参与进来。', 7 | }, 8 | contributeWays: { 9 | title: '贡献方式', 10 | description: '有很多方式可以为 Equal UI 做出贡献,包括:', 11 | way1: { 12 | label: '报告错误:', 13 | content: 14 | '如果你在项目中发现了错误,请通过在项目的问题跟踪器中创建一个问题来报告。请确保尽可能提供详细信息,包括你使用的项目版本和你收到的任何错误消息。', 15 | }, 16 | way2: { 17 | label: '修复错误:', 18 | content: 19 | '如果你有兴趣修复错误,请查看项目的问题跟踪器中的开放问题,并查看是否有任何你可以帮助的问题。', 20 | }, 21 | way3: { 22 | label: '添加新功能:', 23 | content: 24 | '如果你有一个对项目有益的新功能的想法,请创建一个问题与项目维护人员讨论。如果该功能被接受,可以随时提交一个带有你的实现的拉取请求。', 25 | }, 26 | way4: { 27 | label: '改进文档:', 28 | content: 29 | '如果你注意到项目的文档不足或可以改进,请提交一个带有你的更改的拉取请求。', 30 | }, 31 | way5: { 32 | label: '提供反馈:', 33 | content: 34 | '如果你对该项目有任何反馈(无论是好的还是坏的),请通过在项目的问题跟踪器中创建一个问题来分享。', 35 | }, 36 | }, 37 | submissionSteps: { 38 | title: '提交更改', 39 | description: '要提交对 Equal UI 的更改,请按照以下步骤操作:', 40 | step1: { 41 | label: 'Fork 该仓库:', 42 | content: 43 | '将该项目的仓库 Fork 到你自己的 GitHub 账户。这将创建一个你可以对其进行更改的仓库副本。', 44 | }, 45 | step2: { 46 | label: '创建一个新分支:', 47 | content: 48 | '在你的仓库分支上创建一个新分支以进行你的更改。这有助于将你的更改组织和与项目中的其他工作分开。', 49 | }, 50 | step3: { 51 | label: '进行你的更改:', 52 | content: 53 | '进行你想要提交给项目的更改。确保遵循项目的编码风格和规范,并确保你的更改有良好的文档。', 54 | }, 55 | step4: { 56 | label: '提交你的更改:', 57 | content: 58 | '将你的更改提交到你的新分支。确保编写一个清晰描述你的更改的良好提交信息。', 59 | }, 60 | step5: { 61 | label: '提交一个拉取请求:', 62 | content: 63 | '提交一个拉取请求到项目的仓库。在拉取请求中,确保解释你的更改是做了什么以及为什么它们是必要的。', 64 | }, 65 | }, 66 | codeOfConduct: { 67 | title: '行为准则', 68 | description: '通过参与这个项目,你同意遵守该项目的', 69 | }, 70 | contact: { 71 | title: '联系方式', 72 | description: '如果你有任何问题或需要帮助入门,请随时联系项目维护人员。', 73 | }, 74 | thanks: '感谢你对 Equal UI 的贡献兴趣!', 75 | } 76 | -------------------------------------------------------------------------------- /docs/pages/Directives.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold"> 4 | Directives 5 | <it-tag variant="warning">This page is WIP</it-tag> 6 | </h1> 7 | <div 8 | class="flex w-full flex-col space-y-4 rounded border bg-white p-8 dark:border-neutral-700 dark:bg-neutral-800" 9 | > 10 | <p> 11 | Equal UI has v-tooltip directive to create tooltips with very specific 12 | content and behavior 13 | </p> 14 | 15 | <prism 16 | language="html" 17 | class="rounded border dark:border-neutral-700" 18 | code="<it-button v-tooltip="{ content: 'Top tooltip' }">Top</it-button> 19 | 20 | // or render you own components with h() function 21 | <it-button v-tooltip="{ content: 'Top tooltip', children: h('YourComponent') }">Top</it-button>" 22 | ></prism> 23 | </div> 24 | </div> 25 | </template> 26 | -------------------------------------------------------------------------------- /docs/pages/Introduction/locale/en.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | title: 'Introduction', 3 | description: 4 | '{0} is a design philosophy that focuses on creating user interfaces that are accessible, intuitive, and easy to use for all users, regardless of their physical abilities or technological expertise. It involves creating user interfaces that are visually and functionally consistent across different devices and platforms, and that are easy to navigate and use for people with disabilities or special needs. Equal UI aims to create a more inclusive and equitable user experience for all users, by designing interfaces that are easy to understand and use for everyone.', 5 | how_works: { 6 | label: 'How it works', 7 | content: 8 | "Every component's template contains tags with variant blocks. This example shows short version of {0} :", 9 | }, 10 | types: { 11 | title: 12 | "There are a single source of styles in Equal UI. It's the file with object containing classes for every component. There are 3 different types:", 13 | type1: { 14 | name: 'Full:', 15 | description: '{0} contains classes for light and dark themes', 16 | }, 17 | type2: { 18 | name: 'Light:', 19 | description: '{0} contains classes for light theme', 20 | }, 21 | type3: { 22 | name: 'Dark:', 23 | description: '{0} contains classes for dark theme', 24 | }, 25 | }, 26 | blocks_title: 'This is how {0} block looks:', 27 | variants: { 28 | title: 29 | '{0} contains entries for every major part of the component and applies permanent classes to them {1} contains entries for every variant of the component. Default variant is applied by default. Classes in chosen variant applies classes on top of the {2}', 30 | result: 'Result:', 31 | usage1: { 32 | title: 33 | 'To apply variant to the component you need to use {0} prop, it works with every Equal UI component', 34 | }, 35 | usage2: { 36 | title: 37 | 'Also you can make inline variants via {0} prop. You can use multiple variants at the same time!', 38 | }, 39 | }, 40 | note: 'Equal UI uses Tailwindcss as a classes provider. But you can use you your own classes or another utility classes provider if you want.', 41 | create_theme: { 42 | title: 'How to create my own theme?', 43 | theme: 'theming', 44 | step1: 'To create your theme please read the {0}', 45 | step2: 46 | "Also, do not hesitate to use Customization feature under every component on it's own page", 47 | }, 48 | next: { 49 | title: "What's next?", 50 | start: 'Getting started', 51 | contribute: 'How to contribute?', 52 | support: 'Support the project', 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /docs/pages/Introduction/locale/zh-hans.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | title: '介绍', 3 | description: 4 | '{0} 是一种注重为所有用户创建可访问、直观和易于使用的用户界面的设计理念,无论用户的身体能力或技术经验如何。它涉及创建在不同设备和平台上视觉和功能一致,并且易于残障人士或特殊需求人士导航和使用的用户界面。Equal UI 的目标是为所有用户创建更具包容性和公平性的用户体验,通过设计易于理解和使用的界面。', 5 | how_works: { 6 | label: '工作原理', 7 | content: 8 | '每个组件的模板都包含带有变体块的标签。这个示例展示了 {0} 的简短版本:', 9 | }, 10 | types: { 11 | title: 12 | 'Equal UI 中有一个样式源。这是一个包含每个组件的类的对象的文件。有 3 种不同的类型:', 13 | type1: { 14 | name: 'Full:', 15 | description: '{0} 包含了浅色和深色主题的类', 16 | }, 17 | type2: { 18 | name: 'Light:', 19 | description: '{0} 包含了浅色主题的类', 20 | }, 21 | type3: { 22 | name: 'Dark:', 23 | description: '{0} 包含了深色主题的类', 24 | }, 25 | }, 26 | blocks_title: '这是块 {0} 的外观:', 27 | variants: { 28 | title: 29 | '{0} 包含了组件的每个主要部分的条目,并对它们应用永久类 {1} 包含了组件的每个变体的条目。默认变体会自动应用。所选变体中的类会在 {2} 的基础上应用类。', 30 | result: '结果:', 31 | usage1: { 32 | title: 33 | '要将变体应用于组件,您需要使用 {0} 属性,它适用于每个 Equal UI 组件。', 34 | }, 35 | usage2: { 36 | title: 37 | '此外,您还可以通过 {0} 属性创建内联变体。您可以同时使用多个变体!', 38 | }, 39 | }, 40 | note: 'Equal UI 使用 Tailwindcss 作为类提供者。但如果您愿意,您可以使用自己的类或其他实用程序类提供者。', 41 | create_theme: { 42 | title: '如何创建自己的主题?', 43 | theme: '主题', 44 | step1: '要创建自己的主题,请阅读 {0}', 45 | step2: '此外,在每个组件的页面上,不要犹豫使用自定义功能', 46 | }, 47 | next: { 48 | title: '接下来是什么?', 49 | start: '开始使用', 50 | contribute: '如何贡献?', 51 | support: '支持项目', 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /docs/pages/Start/locale/en.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | title: 'Getting started', 3 | step1: { 4 | title: '1. Install with NPM or Yarn', 5 | description: '', 6 | }, 7 | step2: { 8 | title: '2. Install Tailwind version 3.2+', 9 | description: 'To install Tailwind follow his official documentation:', 10 | }, 11 | step3: { 12 | title: '3. Add Equal UI theme file to the', 13 | description: '', 14 | }, 15 | step4: { 16 | title: '4. Use all components', 17 | description: '', 18 | }, 19 | step4_1: { 20 | title: '4.1. Or individual components', 21 | description: '', 22 | }, 23 | step5: { 24 | title: '5. Add Inter font', 25 | description: 26 | 'Equal UI uses {0} font by {1}. The simplest way to add it via CDN:', 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /docs/pages/Start/locale/zh-hans.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | title: '入门', 3 | step1: { title: '1. 使用 NPM 或 Yarn 安装', description: '' }, 4 | step2: { 5 | title: '2. 安装 Tailwind 版本 3.2+', 6 | description: '要安装 Tailwind,请按照他的官方文档进行操作:', 7 | }, 8 | step3: { title: '3. 将 Equal UI 主题文件添加到', description: '' }, 9 | step4: { title: '4. 使用所有组件', description: '' }, 10 | step4_1: { title: '4.1. 或者使用单独的组件', description: '' }, 11 | step5: { 12 | title: '5. 添加 Inter 字体', 13 | description: 14 | 'Equal UI 使用 {1} 的字体 {0}。最简单的方法是通过 CDN 添加它:', 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /docs/pages/Support/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold">{{ $t('sidebar.support') }}</h1> 4 | <div 5 | class="flex w-full flex-col rounded border bg-white p-8 dark:border-neutral-700 dark:bg-neutral-800" 6 | > 7 | <p> 8 | {{ $t('support.intro') }} 9 | </p> 10 | 11 | <h3 class="mt-4 mb-2 text-base font-semibold"> 12 | {{ $t('support.ways_to_support_title') }} 13 | </h3> 14 | 15 | <ul class="list-inside list-disc space-y-2"> 16 | <li>{{ $t('support.via_crypto') }}</li> 17 | <li>{{ $t('support.github_star') }}</li> 18 | <li> 19 | {{ $t('support.review') }} 20 | </li> 21 | <li>{{ $t('support.promote') }}</li> 22 | <li> 23 | {{ $t('support.contribute') }} 24 | </li> 25 | </ul> 26 | 27 | <h3 class="mt-4 text-base font-semibold"> 28 | {{ $t('support.donations_title') }} 29 | </h3> 30 | 31 | <p class="my-2"> 32 | {{ $t('support.donations_text') }} 33 | </p> 34 | 35 | <p class="my-2 max-w-full overflow-hidden text-ellipsis"> 36 | {{ $t('support.cardano_wallet') }} 37 | <it-tooltip class="inline-block max-w-full"> 38 | <it-tag 39 | variant="primary" 40 | class="max-w-full truncate" 41 | @click="clickCopyWallet" 42 | > 43 | addr1q9l3hymrwkwqhv7nxvp5qt9u8zke29jndd5pl73fjwxle4gx2x55zutg4scnede3ez303npq8uwgjuvzqyxepfll2tqs5c0482 44 | </it-tag> 45 | <template #content> 46 | {{ copyTextWallet }} 47 | </template> 48 | </it-tooltip> 49 | <it-divider class="my-2" /> 50 | {{ $t('support.eth_wallet') }} 51 | <it-tooltip class="inline-block max-w-full"> 52 | <it-tag 53 | variant="primary" 54 | class="max-w-full truncate" 55 | @click="clickCopyWalletEth" 56 | > 57 | 0x9723d53D1EF5d5C8fccF50e4ADF35dfD3992fE04 58 | </it-tag> 59 | <template #content> 60 | {{ copyTextWalletEth }} 61 | </template> 62 | </it-tooltip> 63 | </p> 64 | 65 | <p class="my-2"> 66 | {{ $t('support.thanks') }} 67 | </p> 68 | <p class="my-2"> 69 | {{ $t('support.contact') }} 70 | <it-tooltip class="inline-block"> 71 | <it-tag variant="primary" @click="clickCopy"> 72 | yan.savinov.hire@gmail.com 73 | </it-tag> 74 | <template #content> 75 | {{ copyText }} 76 | </template> 77 | </it-tooltip> 78 | </p> 79 | </div> 80 | </div> 81 | </template> 82 | 83 | <script setup lang="ts"> 84 | const clickText = 'Click to copy' 85 | const copyText = ref(clickText) 86 | const copyTextWallet = ref(clickText) 87 | const copyTextWalletEth = ref(clickText) 88 | 89 | async function clickCopy() { 90 | copyText.value = 'Copied!' 91 | await navigator.clipboard.writeText('yan.savinov.hire@gmail.com') 92 | } 93 | async function clickCopyWallet() { 94 | copyTextWallet.value = 'Copied!' 95 | await navigator.clipboard.writeText( 96 | 'addr1q9l3hymrwkwqhv7nxvp5qt9u8zke29jndd5pl73fjwxle4gx2x55zutg4scnede3ez303npq8uwgjuvzqyxepfll2tqs5c0482', 97 | ) 98 | } 99 | async function clickCopyWalletEth() { 100 | copyTextWalletEth.value = 'Copied!' 101 | await navigator.clipboard.writeText( 102 | '0x9723d53D1EF5d5C8fccF50e4ADF35dfD3992fE04', 103 | ) 104 | } 105 | </script> 106 | -------------------------------------------------------------------------------- /docs/pages/Support/locale/en.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | intro: 3 | 'We are grateful for your interest in supporting Equal UI! Your support helps us to continue developing and maintaining the project, as well as adding new features and improving documentation.', 4 | ways_to_support_title: 'Ways to Support', 5 | via_crypto: 'Make a financial contribution via crypto.', 6 | github_star: 'Star and share the repository on GitHub.', 7 | promote: 'Promote the project on social media.', 8 | review: 9 | "Leave a positive review on the project's listing in package managers.", 10 | contribute: 11 | 'Contribute to the project by reporting bugs, fixing issues, or implementing new features.', 12 | donations_title: 'Donations', 13 | donations_text: 14 | 'At this moment the only way you can support the author is crypto. All donations go towards maintaining the project, development time, and other expenses.', 15 | cardano_wallet: 'Cardano wallet:', 16 | eth_wallet: 'Ethereum wallet:', 17 | thanks: 18 | 'Thank you for your support of Equal UI! It is greatly appreciated and helps to ensure the continued development and improvement of the project.', 19 | contact: 'For any questions about sponsoring project you can contact', 20 | } 21 | -------------------------------------------------------------------------------- /docs/pages/Support/locale/zh-hans.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | intro: 3 | '我们感谢您对 Equal UI 的支持!您的支持有助于我们继续开发和维护项目,并增加新功能和完善文档。', 4 | ways_to_support_title: '支持的方式', 5 | via_crypto: '通过加密货币赞助。', 6 | github_star: '在GitHub上给项目仓库Star并分享。', 7 | promote: '在社交媒体上推广项目。', 8 | review: '在包管理器的项目列表中留下好评。', 9 | contribute: '通过报告错误,修复问题或实现新功能来为项目做出贡献。', 10 | donations_title: '赞助', 11 | donations_text: 12 | '目前,支持作者的唯一方式就是加密货币。所有捐款都将用于项目维护、开发时间和其他开支。', 13 | cardano_wallet: 'Cardano钱包:', 14 | eth_wallet: '以太坊钱包:', 15 | thanks: 16 | '感谢您对 Equal UI 的支持!我们非常感谢您的支持,这有助于确保项目的持续发展和改进。', 17 | contact: '如果你对赞助项目有任何问题,可以联系我们', 18 | } 19 | -------------------------------------------------------------------------------- /docs/pages/Theming/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 flex flex-row items-center gap-4 text-2xl font-bold"> 4 | {{ $t('sidebar.theming') }} 5 | <it-tag variant="warning">{{ $t('theming.wip') }}</it-tag> 6 | </h1> 7 | <div 8 | class="flex w-full flex-col rounded border bg-white p-8 dark:border-neutral-700 dark:bg-neutral-800" 9 | > 10 | <p> 11 | {{ $t('theming.own_theme_copy') }} 12 | </p> 13 | <ul class="mt-2"> 14 | <li> 15 | <it-button 16 | variant="primary-text" 17 | href="https://github.com/Equal-UI/Equal/blob/master/src/theme/full.ts" 18 | target="_blank" 19 | rel="noopener noreferrer" 20 | class="!inline-block !py-0 !px-1 font-semibold leading-relaxed text-blue-500" 21 | > 22 | <strong>Full:</strong> 23 | {{ $t('theming.full') }} 24 | </it-button> 25 | </li> 26 | <li> 27 | <it-button 28 | variant="primary-text" 29 | href="https://github.com/Equal-UI/Equal/blob/master/src/theme/light.ts" 30 | target="_blank" 31 | rel="noopener noreferrer" 32 | class="!inline-block !py-0 !px-1 font-semibold leading-relaxed text-blue-500" 33 | > 34 | <strong>Light:</strong> 35 | {{ $t('theming.light') }} 36 | </it-button> 37 | </li> 38 | <li> 39 | <it-button 40 | variant="primary-text" 41 | href="https://github.com/Equal-UI/Equal/blob/master/src/theme/dark.ts" 42 | target="_blank" 43 | rel="noopener noreferrer" 44 | class="!inline-block !py-0 !px-1 font-semibold leading-relaxed text-blue-500" 45 | > 46 | <strong>Dark:</strong> 47 | {{ $t('theming.dark') }} 48 | </it-button> 49 | </li> 50 | </ul> 51 | <p>{{ $t('theming.own_theme') }}</p> 52 | </div> 53 | </div> 54 | </template> 55 | -------------------------------------------------------------------------------- /docs/pages/Theming/locale/en.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | wip: 'This page is WIP', 3 | own_theme_copy: 4 | 'To create your own theme you can copy on of the initial theme files and make your changes to them:', 5 | own_theme: 'Or make your own theme file from scratch', 6 | full: 'contains classes for light and dark themes', 7 | light: 'contains classes for light theme', 8 | dark: 'contains classes for dark theme', 9 | } 10 | -------------------------------------------------------------------------------- /docs/pages/Theming/locale/zh-hans.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | wip: '这个页面正在进行中', 3 | own_theme_copy: '要创建自己的主题,可以复制初始主题文件并对其进行修改:', 4 | own_theme: '或者从头开始创建你自己的主题文件', 5 | full: '包含亮色和暗色主题的class', 6 | light: '包含亮色主题的class', 7 | dark: '包含暗色主题的class', 8 | } 9 | -------------------------------------------------------------------------------- /docs/pages/components/Alert/locale/en.ts: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /docs/pages/components/Alert/locale/zh-hans.ts: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /docs/pages/components/Breadcrumbs.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <Development /> 4 | </div> 5 | </template> 6 | 7 | <script setup lang="ts"></script> 8 | -------------------------------------------------------------------------------- /docs/pages/components/Datepicker.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <Development /> 3 | </template> 4 | -------------------------------------------------------------------------------- /docs/pages/components/Divider.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold">Divider</h1> 4 | 5 | <Demobox name="ItDivider"> 6 | <div class="flex w-11/12 justify-center"> 7 | <it-divider :vertical="dividerVertical" /> 8 | </div> 9 | <template #props> 10 | <it-checkbox 11 | variant="primary" 12 | v-model="dividerVertical" 13 | label="Vertical" 14 | /> 15 | </template> 16 | </Demobox> 17 | 18 | <Box :template="codeHorizontal" title="Horizontal"> 19 | <p class="text-sm"> 20 | Not that I wish to imply you have been sleeping on the job. No one is 21 | more deserving of a rest. And all the effort in the world would have 22 | gone to waste until...well, let's just say your hour has come again. 23 | </p> 24 | <it-divider /> 25 | <p class="text-sm"> 26 | Not that I wish to imply you have been sleeping on the job. No one is 27 | more deserving of a rest. And all the effort in the world would have 28 | gone to waste until...well, let's just say your hour has come again. 29 | </p> 30 | <it-divider /> 31 | <p class="text-sm"> 32 | Not that I wish to imply you have been sleeping on the job. No one is 33 | more deserving of a rest. And all the effort in the world would have 34 | gone to waste until...well, let's just say your hour has come again. 35 | </p> 36 | </Box> 37 | 38 | <Box :template="codeVertical" title="Vertical"> 39 | <div class="m-0 text-sm"> 40 | Still 41 | <it-divider vertical /> 42 | Sane 43 | <it-divider vertical /> 44 | Exile 45 | </div> 46 | </Box> 47 | 48 | <props-table :data-sheet="dataSheet" /> 49 | </div> 50 | </template> 51 | 52 | <script lang="ts"> 53 | import { defineComponent } from 'vue' 54 | 55 | export default defineComponent({ 56 | data: () => ({ 57 | dividerVertical: false, 58 | 59 | codeHorizontal: `<p>Not that I wish to imply you have been sleeping on the job. No one is more deserving of a rest. And all the effort in the world would have gone to waste until...well, let's just say your hour has come again.</p> 60 | ||| <it-divider /> ||| 61 | <p>Not that I wish to imply you have been sleeping on the job. No one is more deserving of a rest. And all the effort in the world would have gone to waste until...well, let's just say your hour has come again.</p> 62 | ||| <it-divider /> ||| 63 | <p>Not that I wish to imply you have been sleeping on the job. No one is more deserving of a rest. And all the effort in the world would have gone to waste until...well, let's just say your hour has come again.</p>`, 64 | 65 | codeVertical: `<div> 66 | Still 67 | ||| <it-divider vertical /> ||| 68 | Sane 69 | ||| <it-divider vertical /> ||| 70 | Exile 71 | </div>`, 72 | 73 | dataSheet: [ 74 | { 75 | property: 'vertical', 76 | type: ['Boolean'], 77 | default: false, 78 | values: [], 79 | description: 'Makes divider vertical', 80 | }, 81 | ], 82 | }), 83 | }) 84 | </script> 85 | -------------------------------------------------------------------------------- /docs/pages/components/NumberInput.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold">Number Input</h1> 4 | 5 | <Demobox name="ItNumberInput"> 6 | <it-number-input 7 | v-model="inputValue" 8 | :label-top="inputTopLabel" 9 | :step="inputStep" 10 | :resize-on-write="resizeOnChange" 11 | :min="inputMin" 12 | :max="inputMax" 13 | :hide-controls="controlsDisabled" 14 | :disabled="inputDisabled" 15 | /> 16 | 17 | <template #props> 18 | <it-input v-model="inputTopLabel" label-top="Top label" /> 19 | <it-number-input v-model="inputMin" label-top="Min" /> 20 | <it-number-input v-model="inputMax" label-top="Max" /> 21 | <it-number-input v-model="inputStep" :min="0" label-top="Step" /> 22 | <it-divider /> 23 | <it-checkbox 24 | variant="primary" 25 | v-model="resizeOnChange" 26 | label="Resize on change" 27 | /> 28 | <it-checkbox 29 | variant="primary" 30 | v-model="controlsDisabled" 31 | label="Hide controls" 32 | /> 33 | <it-checkbox 34 | variant="primary" 35 | v-model="inputDisabled" 36 | label="Disabled" 37 | /> 38 | </template> 39 | </Demobox> 40 | <props-table :data-sheet="dataSheet" /> 41 | </div> 42 | </template> 43 | 44 | <script lang="ts"> 45 | import { defineComponent } from 'vue' 46 | export default defineComponent({ 47 | data: () => ({ 48 | inputMin: 0, 49 | inputMax: 100, 50 | inputStep: 1, 51 | inputValue: 0, 52 | inputTopLabel: 'Your input', 53 | inputDisabled: false, 54 | controlsDisabled: false, 55 | resizeOnChange: false, 56 | 57 | dataSheet: [ 58 | { 59 | property: 'min', 60 | type: ['Number'], 61 | default: -Infinity, 62 | values: [], 63 | description: 'Minimal value', 64 | }, 65 | { 66 | property: 'max', 67 | type: ['Number'], 68 | default: Infinity, 69 | values: [], 70 | description: 'Maximal value', 71 | }, 72 | { 73 | property: 'step', 74 | type: ['Number'], 75 | default: '1', 76 | values: [], 77 | description: 'Step value', 78 | }, 79 | { 80 | property: 'label-top', 81 | type: ['String'], 82 | default: '-', 83 | values: [], 84 | description: 'Top label', 85 | }, 86 | { 87 | property: 'value (v-model)', 88 | type: ['Number'], 89 | default: 1, 90 | values: [], 91 | description: 'Number input value', 92 | }, 93 | { 94 | property: 'resize-on-write', 95 | type: ['Boolean'], 96 | default: 'false', 97 | values: [], 98 | description: 'Resizes on input', 99 | }, 100 | { 101 | property: 'hide-controls', 102 | type: ['Boolean'], 103 | default: 'false', 104 | values: [], 105 | description: 'Hides control +/- buttons', 106 | }, 107 | { 108 | property: 'disabled', 109 | type: ['Boolean'], 110 | default: 'false', 111 | values: [], 112 | description: 'Disabled number input', 113 | }, 114 | ], 115 | }), 116 | }) 117 | </script> 118 | -------------------------------------------------------------------------------- /docs/pages/components/Progressbar.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold">Progress Bar</h1> 4 | 5 | <Demobox name="ItProgressBar"> 6 | <div class="w-full px-8"> 7 | <it-progressbar 8 | :show-tooltip="progressShowTooltip" 9 | :height="progressHeight" 10 | :progress="progressValue" 11 | :tooltip="progressTooltip" 12 | /> 13 | </div> 14 | 15 | <template #props> 16 | <it-slider v-model="progressValue" label-top="Progress" /> 17 | <it-number-input 18 | v-model="progressHeight" 19 | :min="1" 20 | label-top="Progress bar height" 21 | /> 22 | <it-checkbox 23 | variant="primary" 24 | v-model="progressShowTooltip" 25 | label="Show tooltip" 26 | /> 27 | <it-select 28 | v-model="progressTooltip" 29 | placeholder="Select tooltip" 30 | label-top="Tooltip position" 31 | :disabled="!progressShowTooltip" 32 | :options="tooltipTypes" 33 | ></it-select> 34 | </template> 35 | </Demobox> 36 | <Box :template="infiniteCode" title="Infinite"> 37 | <div class="flex w-full flex-col gap-3"> 38 | <it-progressbar infinite /> 39 | </div> 40 | </Box> 41 | <Box :template="tooltipCode" title="Tooltip position"> 42 | <div class="flex w-full flex-col gap-3"> 43 | <it-progressbar :progress="progressValue42" /> 44 | <it-progressbar :progress="progressValue42" tooltip="bottom" /> 45 | </div> 46 | </Box> 47 | <props-table :data-sheet="dataSheet" /> 48 | </div> 49 | </template> 50 | 51 | <script lang="ts"> 52 | import { defineComponent } from 'vue' 53 | 54 | export default defineComponent({ 55 | data: () => ({ 56 | progressValue: 42, 57 | progressHeight: 7, 58 | tooltipTypes: ['top', 'bottom'], 59 | progressTooltip: 'top', 60 | progressShowTooltip: true, 61 | progressValue42: 42, 62 | 63 | infiniteCode: `<it-progressbar ||| infinite ||| />`, 64 | 65 | tooltipCode: `<it-progressbar :progress="progressValue" /> 66 | <it-progressbar :progress="progressValue" ||| tooltip="bottom" ||| />`, 67 | 68 | dataSheet: [ 69 | { 70 | property: 'progress', 71 | type: ['Number', 'String'], 72 | default: '0', 73 | values: ['0-100'], 74 | description: 'Progress value', 75 | }, 76 | { 77 | property: 'infinite', 78 | type: ['Boolean'], 79 | default: 'false', 80 | values: [], 81 | description: 'Makes progress infinite', 82 | }, 83 | { 84 | property: 'height', 85 | type: ['Number', 'String'], 86 | default: '7', 87 | values: [], 88 | description: 'Height of the progressbar', 89 | }, 90 | { 91 | property: 'tooltip', 92 | type: ['String'], 93 | default: 'top', 94 | values: ['top', 'bottom'], 95 | description: 'Position of the tooltip', 96 | }, 97 | { 98 | property: 'show-tooltip', 99 | type: ['Boolean'], 100 | default: 'true', 101 | values: [], 102 | description: 'Show tooltip', 103 | }, 104 | ], 105 | }), 106 | }) 107 | </script> 108 | -------------------------------------------------------------------------------- /docs/pages/components/Select/SectionDemo/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <Demobox> 3 | <div class="w-3/4"> 4 | <it-select 5 | v-model="selectValue" 6 | :placeholder="selectPlaceholder" 7 | :disabled="selectDisabled" 8 | :placement="selectPlacement" 9 | :label-top="selectLabel" 10 | :divided="selectDivided" 11 | :options="firstSelectOptions" 12 | :multiselect="multiselect" 13 | /> 14 | </div> 15 | <template #props> 16 | <it-input v-model="selectLabel" label-top="Select label" /> 17 | <it-input v-model="selectPlaceholder" label-top="Select placeholder" /> 18 | <it-select 19 | v-model="selectPlacement" 20 | placeholder="Placement" 21 | label-top="Placement" 22 | :options="placementOptions" 23 | /> 24 | <it-checkbox v-model="multiselect" label="Multiselect" /> 25 | <it-checkbox v-model="selectDivided" label="Divided" /> 26 | <it-checkbox v-model="selectDisabled" label="Disabled" /> 27 | </template> 28 | </Demobox> 29 | </template> 30 | 31 | <script lang="ts"> 32 | import { defineComponent } from 'vue' 33 | import { ALLOWED_POSITION } from '@/components/select/constants' 34 | 35 | export default defineComponent({ 36 | name: 'SectionDemo', 37 | data: () => ({ 38 | selectValue: '', 39 | multiselect: false, 40 | selectLabel: 'Select me', 41 | selectPlaceholder: 'Select me', 42 | selectDisabled: false, 43 | selectDivided: false, 44 | selectPlacement: null, 45 | placementOptions: ALLOWED_POSITION, 46 | firstSelectOptions: [ 47 | 'Lorem ipsum dolor sit amet consectetur', 48 | 'Dolor', 49 | 'Lorem ipsum', 50 | 'Lorem ipsum 1', 51 | 'Lorem ipsum 2', 52 | 'Lorem ipsum 3', 53 | 'Lorem ipsum 4', 54 | 'Lorem ipsum 5', 55 | 'Lorem ipsum 1223', 56 | 'Lorem ipsum wef3', 57 | ], 58 | }), 59 | }) 60 | </script> 61 | -------------------------------------------------------------------------------- /docs/pages/components/Select/SectionSlots/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <Box :template="codeSectionExamples" title="Slots"> 3 | <it-select v-model="exampleValue" :options="exampleOptions"> 4 | <template v-slot:label-top="{ props }"> 5 | Placement prop: {{ props.placement }} 6 | </template> 7 | <template v-slot:placeholder="{ props }"> 8 | <div class="items-center" :style="{ display: 'flex' }"> 9 | <span>{{ props.placeholder }} - custom</span> 10 | </div> 11 | </template> 12 | <template v-slot:selected-option="{ props }"> 13 | Selected value: {{ props.modelValue.value }} 14 | </template> 15 | <template v-slot:option="{ props, option }"> 16 | <div class="items-center" :style="{ display: 'flex' }"> 17 | <img src="/github-logo.svg" class="mr-2 h-4" alt srcset /> 18 | {{ option.name }} 19 | </div> 20 | </template> 21 | <template v-slot:icon> 22 | <img src="/twitter-logo.svg" class="h-3" alt srcset /> 23 | </template> 24 | </it-select> 25 | </Box> 26 | </template> 27 | 28 | <script lang="ts"> 29 | import { defineComponent } from 'vue' 30 | 31 | const exampleOptions = [ 32 | { name: 'New York', value: 'nwrk' }, 33 | { name: 'Paris', value: 'prs' }, 34 | { name: 'Moscow', value: 'mscw' }, 35 | ] 36 | 37 | export default defineComponent({ 38 | name: 'SectionSlots', 39 | data: () => ({ 40 | exampleValue: null, 41 | exampleOptions: exampleOptions, 42 | codeSectionExamples: ` 43 | <template> 44 | <it-select 45 | v-model="exampleValue" 46 | :options="exampleOptions" 47 | > 48 | <template v-slot:label-top="{ props }"> 49 | Placement prop: {{ props.placement }} 50 | </template> 51 | <template v-slot:placeholder="{ props }"> 52 | <div class="items-center" :style="{ display: 'flex' }"> 53 | <span>{{ props.placeholder }} - custom</span> 54 | </div> 55 | </template> 56 | <template v-slot:selected-option="{ props }"> 57 | Selected value: {{ props.modelValue.value }} 58 | </template> 59 | <template v-slot:option="{ props, option }"> 60 | <div class="items-center" :style="{ display: 'flex' }"> 61 | <img src="/github-logo.svg" class="mr-2 h-4" alt srcset /> 62 | {{ option.name }} 63 | </div> 64 | </template> 65 | <template v-slot:icon> 66 | <img src="/twitter-logo.svg" class="h-3 mr-2" alt srcset /> 67 | </template> 68 | </it-select> 69 | </template> 70 | 71 | export default { 72 | data: () => ({ 73 | exampleValue: null, 74 | exampleOptions: [${exampleOptions.map((a) => JSON.stringify(a))}], 75 | }) 76 | } 77 | `, 78 | }), 79 | }) 80 | </script> 81 | -------------------------------------------------------------------------------- /docs/pages/components/Select/constants.ts: -------------------------------------------------------------------------------- 1 | import { ALLOWED_POSITION } from '@/components/select/constants' 2 | 3 | export const DATA_SHEET = [ 4 | { 5 | property: 'label-top', 6 | type: ['String'], 7 | default: '-', 8 | values: [], 9 | description: 'Top label', 10 | }, 11 | { 12 | property: 'options', 13 | type: ['Array', 'Object[]'], 14 | default: '-', 15 | values: [], 16 | description: 17 | 'Array of options, or array of option object used with index prop', 18 | }, 19 | { 20 | property: 'track-by', 21 | type: ['String'], 22 | default: 'value', 23 | values: [], 24 | description: 'Field for track', 25 | }, 26 | { 27 | property: 'index', 28 | type: ['String'], 29 | default: '-', 30 | values: [], 31 | description: 'Index of the object key', 32 | }, 33 | { 34 | property: 'placeholder', 35 | type: ['String'], 36 | default: '-', 37 | values: [], 38 | description: 'Select area placeholder', 39 | }, 40 | { 41 | property: 'placement', 42 | type: ['String'], 43 | default: 'bottom', 44 | values: ALLOWED_POSITION, 45 | description: 'Select list position', 46 | }, 47 | { 48 | property: 'divided', 49 | type: ['Boolean'], 50 | default: 'false', 51 | values: [], 52 | description: 'Makes select options divided by line', 53 | }, 54 | { 55 | property: 'disabled', 56 | type: ['Boolean'], 57 | default: 'false', 58 | values: [], 59 | description: 'Makes select disabled', 60 | }, 61 | ] 62 | 63 | export const SLOT_SHEET = [ 64 | { 65 | property: 'dropdown-header', 66 | description: 'Dropdown top slot', 67 | }, 68 | { 69 | property: 'dropdown-footer', 70 | description: 'Dropdown footer slot', 71 | }, 72 | { 73 | property: 'label-top', 74 | description: 'Label top text', 75 | }, 76 | { 77 | property: 'selected-option', 78 | description: 'Selected option', 79 | }, 80 | { 81 | property: 'placeholder', 82 | description: 'Placeholder text', 83 | }, 84 | { 85 | property: 'option', 86 | description: 'Option', 87 | }, 88 | { 89 | property: 'icon', 90 | description: 'Icon', 91 | }, 92 | ] 93 | -------------------------------------------------------------------------------- /docs/pages/components/Select/index.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1>Select</h1> 4 | <section-demo /> 5 | <section-examples /> 6 | <section-slots /> 7 | <props-table 8 | tag-name="it-select" 9 | :data-sheet="dataSheet" 10 | :slot-sheet="slotSheet" 11 | /> 12 | </div> 13 | </template> 14 | 15 | <script lang="ts"> 16 | import { defineComponent } from 'vue' 17 | import SectionDemo from './SectionDemo/index.vue' 18 | import SectionExamples from './SectionExamples/index.vue' 19 | import SectionSlots from './SectionSlots/index.vue' 20 | import { DATA_SHEET, SLOT_SHEET } from './constants' 21 | 22 | export default defineComponent({ 23 | components: { 24 | SectionDemo, 25 | SectionExamples, 26 | SectionSlots, 27 | }, 28 | setup() { 29 | return { 30 | dataSheet: DATA_SHEET, 31 | slotSheet: SLOT_SHEET, 32 | } 33 | }, 34 | }) 35 | </script> 36 | -------------------------------------------------------------------------------- /docs/pages/components/Spinner.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold">Spinner</h1> 4 | 5 | <Box :template="spinnerCode" title="Spinner colors"> 6 | <it-spinner /> 7 | <it-spinner 8 | variant="red" 9 | :variants="{ red: { root: '!border-r-red-500' } }" 10 | /> 11 | <it-spinner 12 | variant="blue" 13 | :variants="{ blue: { root: '!border-r-blue-600' } }" 14 | /> 15 | <it-spinner 16 | variant="yellow" 17 | :variants="{ yellow: { root: '!border-r-yellow-500' } }" 18 | /> 19 | </Box> 20 | <props-table :data-sheet="dataSheet" /> 21 | </div> 22 | </template> 23 | 24 | <script lang="ts"> 25 | import { defineComponent } from 'vue' 26 | 27 | export default defineComponent({ 28 | data: () => ({ 29 | spinnerCode: `<it-spinner /> 30 | <it-spinner 31 | variant="red" 32 | :variants="{ red: { root: '!border-r-red-500' } }" 33 | /> 34 | <it-spinner 35 | variant="blue" 36 | :variants="{ blue: { root: '!border-r-blue-600' } }" 37 | /> 38 | <it-spinner 39 | variant="yellow" 40 | :variants="{ yellow: { root: '!border-r-yellow-500' } }" 41 | />`, 42 | 43 | dataSheet: [], 44 | }), 45 | }) 46 | </script> 47 | -------------------------------------------------------------------------------- /docs/pages/components/Steps.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <Development /> 4 | </div> 5 | </template> 6 | 7 | <script setup lang="ts"></script> 8 | -------------------------------------------------------------------------------- /docs/pages/components/Tag.vue: -------------------------------------------------------------------------------- 1 | <template> 2 | <div> 3 | <h1 class="mb-4 text-2xl font-bold">Tag</h1> 4 | 5 | <Demobox name="ItTag"> 6 | <it-tag 7 | v-show="show" 8 | :filled="tagFilled" 9 | :closable="tagClosable" 10 | :variant="tagvariant" 11 | @close="onClose" 12 | > 13 | <span>{{ tagText }}</span> 14 | </it-tag> 15 | 16 | <template #props> 17 | <it-select 18 | v-model="tagvariant" 19 | placeholder="Select variant" 20 | label-top="Tag variant" 21 | :options="tagvariants" 22 | ></it-select> 23 | <it-input v-model="tagText" label-top="Tag text" /> 24 | <it-checkbox variant="primary" v-model="tagFilled" label="Filled" /> 25 | <it-checkbox variant="primary" v-model="tagClosable" label="Closable" /> 26 | </template> 27 | </Demobox> 28 | <Box :template="variantsCode" title="variants"> 29 | <it-tag>Neutral</it-tag> 30 | <it-tag variant="primary">Primary</it-tag> 31 | <it-tag variant="success">Success</it-tag> 32 | <it-tag variant="danger">Danger</it-tag> 33 | <it-tag variant="warning">Warning</it-tag> 34 | </Box> 35 | <Box :template="filledCode" title="Filled"> 36 | <it-tag filled>Neutral</it-tag> 37 | <it-tag variant="primary" filled>Primary</it-tag> 38 | <it-tag variant="success" filled>Success</it-tag> 39 | <it-tag variant="danger" filled>Danger</it-tag> 40 | <it-tag variant="warning" filled>Warning</it-tag> 41 | </Box> 42 | <props-table :data-sheet="dataSheet" :event-sheet="eventSheet" /> 43 | </div> 44 | </template> 45 | 46 | <script lang="ts"> 47 | import { defineComponent } from 'vue' 48 | 49 | export default defineComponent({ 50 | data: () => ({ 51 | show: true, 52 | 53 | tagText: 'Tag', 54 | tagClosable: false, 55 | tagFilled: false, 56 | tagvariant: 'default', 57 | tagvariants: ['primary', 'success', 'danger', 'warning', 'default'], 58 | 59 | variantsCode: `<it-tag>Neutral</it-tag> 60 | <it-tag ||| variant="primary" |||>Primary</it-tag> 61 | <it-tag ||| variant="success" |||>Success</it-tag> 62 | <it-tag ||| variant="danger" |||>Danger</it-tag> 63 | <it-tag ||| variant="warning" |||>Warning</it-tag>`, 64 | 65 | filledCode: `<it-tag ||| filled |||>Neutral</it-tag> 66 | <it-tag variant="primary" ||| filled |||>Primary</it-tag> 67 | <it-tag variant="success" ||| filled |||>Success</it-tag> 68 | <it-tag variant="danger" ||| filled |||>Danger</it-tag> 69 | <it-tag variant="warning" ||| filled |||>Warning</it-tag> 70 | `, 71 | 72 | eventSheet: [ 73 | { 74 | event: '@close', 75 | description: 76 | 'The event function triggered when user clicks on close icon', 77 | arguments: 'function(e: Event)', 78 | }, 79 | ], 80 | 81 | dataSheet: [ 82 | { 83 | property: 'variant', 84 | type: ['String'], 85 | default: 'neutral', 86 | values: ['primary', 'success', 'danger', 'warning', 'neutral'], 87 | description: 'variant of the tag', 88 | }, 89 | { 90 | property: 'filled', 91 | type: ['Boolean'], 92 | default: 'false', 93 | values: [], 94 | description: 'Makes tag filled', 95 | }, 96 | { 97 | property: 'closable', 98 | type: ['Boolean'], 99 | default: 'false', 100 | values: [], 101 | description: 'Makes tag closable', 102 | }, 103 | ], 104 | }), 105 | methods: { 106 | onClose() { 107 | this.show = false 108 | }, 109 | }, 110 | }) 111 | </script> 112 | -------------------------------------------------------------------------------- /docs/plugins/emitter.client.ts: -------------------------------------------------------------------------------- 1 | import mitt from 'mitt' 2 | 3 | const emitter = mitt() 4 | 5 | export default defineNuxtPlugin((nuxtApp) => { 6 | nuxtApp.vueApp.provide('emitter', emitter) 7 | }) 8 | -------------------------------------------------------------------------------- /docs/plugins/equal.client.ts: -------------------------------------------------------------------------------- 1 | import Equal from '@' 2 | import equalConfig from '@/theme/full' 3 | import { uiConfig } from '../data/symbols' 4 | 5 | const flattenDeepArray = (obj: Record<string, any>) => { 6 | for (const key in obj) { 7 | const element = obj[key] 8 | if ( 9 | typeof element === 'object' && 10 | element !== null && 11 | !Array.isArray(element) 12 | ) { 13 | flattenDeepArray(element) 14 | } else if (Array.isArray(element)) { 15 | obj[key] = element.join(' ') 16 | } 17 | } 18 | } 19 | 20 | // Used to show arrays as one string in demobox UI changer 21 | flattenDeepArray(equalConfig) 22 | 23 | export default defineNuxtPlugin((nuxtApp) => { 24 | const reactiveConfig = reactive(JSON.parse(JSON.stringify(equalConfig))) // TODO: use structured clone function when >90% browsers support https://caniuse.com/?search=structuredClone 25 | nuxtApp.vueApp.use(Equal, reactiveConfig) 26 | nuxtApp.vueApp.provide(uiConfig, reactiveConfig) 27 | }) 28 | -------------------------------------------------------------------------------- /docs/plugins/ga.ts: -------------------------------------------------------------------------------- 1 | import VueGtag from 'vue-gtag' 2 | 3 | export default defineNuxtPlugin((nuxtApp) => { 4 | nuxtApp.vueApp.use( 5 | VueGtag, 6 | { 7 | config: { 8 | id: 'UA-65564432-3', 9 | }, 10 | }, 11 | nuxtApp.$router, 12 | ) 13 | }) 14 | -------------------------------------------------------------------------------- /docs/plugins/i18n.client.ts: -------------------------------------------------------------------------------- 1 | import { createI18n } from 'vue-i18n' 2 | import { en, zhHans, zhHant } from '../locales' 3 | 4 | // @ts-ignore 5 | export default defineNuxtPlugin(({ vueApp }) => { 6 | const i18n = createI18n({ 7 | legacy: false, 8 | globalInjection: true, 9 | locale: window.navigator.language, 10 | fallbackLocale: 'en', 11 | messages: { 12 | en, 13 | 'zh-Hans': zhHans, 14 | 'zh-Hant': zhHant, 15 | }, 16 | }) 17 | 18 | vueApp.use(i18n) 19 | }) 20 | -------------------------------------------------------------------------------- /docs/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/public/favicon-16x16.png -------------------------------------------------------------------------------- /docs/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/public/favicon-32x32.png -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/finally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/public/finally.png -------------------------------------------------------------------------------- /docs/public/github-logo.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="iso-8859-1"?> 2 | <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 4 | <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 5 | width="438.549px" height="438.549px" viewBox="0 0 438.549 438.549" style="enable-background:new 0 0 438.549 438.549;" 6 | xml:space="preserve"> 7 | <g> 8 | <path d="M409.132,114.573c-19.608-33.596-46.205-60.194-79.798-79.8C295.736,15.166,259.057,5.365,219.271,5.365 9 | c-39.781,0-76.472,9.804-110.063,29.408c-33.596,19.605-60.192,46.204-79.8,79.8C9.803,148.168,0,184.854,0,224.63 10 | c0,47.78,13.94,90.745,41.827,128.906c27.884,38.164,63.906,64.572,108.063,79.227c5.14,0.954,8.945,0.283,11.419-1.996 11 | c2.475-2.282,3.711-5.14,3.711-8.562c0-0.571-0.049-5.708-0.144-15.417c-0.098-9.709-0.144-18.179-0.144-25.406l-6.567,1.136 12 | c-4.187,0.767-9.469,1.092-15.846,1c-6.374-0.089-12.991-0.757-19.842-1.999c-6.854-1.231-13.229-4.086-19.13-8.559 13 | c-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559 14 | c-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-0.951-2.568-2.098-3.711-3.429c-1.142-1.331-1.997-2.663-2.568-3.997 15 | c-0.572-1.335-0.098-2.43,1.427-3.289c1.525-0.859,4.281-1.276,8.28-1.276l5.708,0.853c3.807,0.763,8.516,3.042,14.133,6.851 16 | c5.614,3.806,10.229,8.754,13.846,14.842c4.38,7.806,9.657,13.754,15.846,17.847c6.184,4.093,12.419,6.136,18.699,6.136 17 | c6.28,0,11.704-0.476,16.274-1.423c4.565-0.952,8.848-2.383,12.847-4.285c1.713-12.758,6.377-22.559,13.988-29.41 18 | c-10.848-1.14-20.601-2.857-29.264-5.14c-8.658-2.286-17.605-5.996-26.835-11.14c-9.235-5.137-16.896-11.516-22.985-19.126 19 | c-6.09-7.614-11.088-17.61-14.987-29.979c-3.901-12.374-5.852-26.648-5.852-42.826c0-23.035,7.52-42.637,22.557-58.817 20 | c-7.044-17.318-6.379-36.732,1.997-58.24c5.52-1.715,13.706-0.428,24.554,3.853c10.85,4.283,18.794,7.952,23.84,10.994 21 | c5.046,3.041,9.089,5.618,12.135,7.708c17.705-4.947,35.976-7.421,54.818-7.421s37.117,2.474,54.823,7.421l10.849-6.849 22 | c7.419-4.57,16.18-8.758,26.262-12.565c10.088-3.805,17.802-4.853,23.134-3.138c8.562,21.509,9.325,40.922,2.279,58.24 23 | c15.036,16.18,22.559,35.787,22.559,58.817c0,16.178-1.958,30.497-5.853,42.966c-3.9,12.471-8.941,22.457-15.125,29.979 24 | c-6.191,7.521-13.901,13.85-23.131,18.986c-9.232,5.14-18.182,8.85-26.84,11.136c-8.662,2.286-18.415,4.004-29.263,5.146 25 | c9.894,8.562,14.842,22.077,14.842,40.539v60.237c0,3.422,1.19,6.279,3.572,8.562c2.379,2.279,6.136,2.95,11.276,1.995 26 | c44.163-14.653,80.185-41.062,108.068-79.226c27.88-38.161,41.825-81.126,41.825-128.906 27 | C438.536,184.851,428.728,148.168,409.132,114.573z"/> 28 | </g> 29 | <g> 30 | </g> 31 | <g> 32 | </g> 33 | <g> 34 | </g> 35 | <g> 36 | </g> 37 | <g> 38 | </g> 39 | <g> 40 | </g> 41 | <g> 42 | </g> 43 | <g> 44 | </g> 45 | <g> 46 | </g> 47 | <g> 48 | </g> 49 | <g> 50 | </g> 51 | <g> 52 | </g> 53 | <g> 54 | </g> 55 | <g> 56 | </g> 57 | <g> 58 | </g> 59 | </svg> 60 | -------------------------------------------------------------------------------- /docs/public/husky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/public/husky.jpg -------------------------------------------------------------------------------- /docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/public/logo.png -------------------------------------------------------------------------------- /docs/public/twitter-logo.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 3 | <!-- Creator: CorelDRAW X6 --> 4 | <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="70.5556mm" height="57.3391mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" 5 | viewBox="0 0 6701 5446" 6 | xmlns:xlink="http://www.w3.org/1999/xlink"> 7 | <defs> 8 | <style type="text/css"> 9 | <![CDATA[ 10 | .fil0 {fill:#41ABE1} 11 | ]]> 12 | </style> 13 | </defs> 14 | <g id="Livello_x0020_1"> 15 | <metadata id="CorelCorpID_0Corel-Layer"/> 16 | <path class="fil0" d="M6701 645c-247,109 -512,183 -790,216 284,-170 502,-440 604,-761 -266,158 -560,272 -873,334 -251,-267 -608,-434 -1004,-434 -759,0 -1375,616 -1375,1375 0,108 12,213 36,313 -1143,-57 -2156,-605 -2834,-1437 -118,203 -186,439 -186,691 0,477 243,898 612,1144 -225,-7 -437,-69 -623,-172 0,6 0,11 0,17 0,666 474,1222 1103,1348 -115,31 -237,48 -362,48 -89,0 -175,-9 -259,-25 175,546 683,944 1284,955 -471,369 -1063,589 -1708,589 -111,0 -220,-7 -328,-19 608,390 1331,618 2108,618 2529,0 3912,-2095 3912,-3912 0,-60 -1,-119 -4,-178 269,-194 502,-436 686,-712z"/> 17 | </g> 18 | </svg> 19 | -------------------------------------------------------------------------------- /docs/public/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/docs/public/twitter.png -------------------------------------------------------------------------------- /docs/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: 'jit', 3 | content: [ 4 | './components/**/*.{js,vue,ts}', 5 | '../src/**/*.{js,vue,ts}', 6 | './layouts/**/*.vue', 7 | './pages/**/*.vue', 8 | './pages/*.vue', 9 | './plugins/**/*.{js,ts}', 10 | './*.vue', 11 | ], 12 | theme: { 13 | fontFamily: { 14 | sans: ['inter', 'system-ui'], 15 | }, 16 | extend: {}, 17 | }, 18 | safelist: process.env.NODE_ENV === 'production' ? [{ pattern: /./ }] : [], 19 | plugins: [], 20 | darkMode: 'class', 21 | } 22 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://v3.nuxtjs.org/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /docs/types.ts: -------------------------------------------------------------------------------- 1 | export enum componentGroup { 2 | General = 'General', 3 | Base = 'Base', 4 | Form = 'Form', 5 | Feedback = 'Feedback', 6 | DataDisplay = 'Data Display', 7 | Navigation = 'Navigation', 8 | Other = 'Other', 9 | } 10 | 11 | export interface IComponentListItem { 12 | name: string 13 | icon: string 14 | icon_outlined?: boolean 15 | route: string 16 | group: componentGroup 17 | examples?: number 18 | coming_soon?: boolean 19 | } 20 | -------------------------------------------------------------------------------- /docs/types/Events.ts: -------------------------------------------------------------------------------- 1 | // Events for mitt 2 | 3 | export type TTheme = 'dark' | 'light' | 'system' 4 | 5 | export type TEvents = { 6 | theme: TTheme 7 | sidebar: boolean 8 | } 9 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/favicon.ico -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en"> 3 | <head> 4 | <meta charset="UTF-8" /> 5 | <link rel="icon" href="/favicon.ico" /> 6 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 | <title>Equal UI 8 | 12 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "equal-vue", 3 | "version": "0.93.0", 4 | "homepage": "https://equal-ui.github.io/Equal/", 5 | "description": "Equal is a Vue 3 hackable UI library empowered by tailwindcss", 6 | "author": { 7 | "name": "Yan Savinov", 8 | "email": "yan.savinov.hire@gmail.com" 9 | }, 10 | "main": "./dist/equal-vue.umd.js", 11 | "module": "./dist/equal-vue.es.js", 12 | "exports": { 13 | ".": { 14 | "import": "./dist/equal-vue.es.js", 15 | "require": "./dist/equal-vue.umd.js" 16 | }, 17 | "./dist/theme/dark": "./dist/theme/dark", 18 | "./dist/theme/light": "./dist/theme/light", 19 | "./dist/theme/full": "./dist/theme/full" 20 | }, 21 | "unpkg": "dist/equal.umd.min.js", 22 | "types": "./dist/index.d.ts", 23 | "license": "MIT", 24 | "bugs": "https://github.com/Equal-UI/Equal/issues", 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/Equal-UI/Equal" 28 | }, 29 | "files": [ 30 | "src", 31 | "dist" 32 | ], 33 | "keywords": [ 34 | "equal", 35 | "vue", 36 | "vue3", 37 | "vuejs", 38 | "typescript", 39 | "vue-components", 40 | "ui", 41 | "tailwindcss", 42 | "tailwind", 43 | "framework" 44 | ], 45 | "scripts": { 46 | "dev": "vite", 47 | "build": "vite build && npm run build:theme", 48 | "build:theme": "ts-node ./scripts/prepareTheme.ts", 49 | "serve": "vite serve", 50 | "test": "vitest run", 51 | "test:dev": "vitest", 52 | "lint:eslint": "eslint src/**/*.{ts,vue} docs/**/*.{ts,vue}", 53 | "lint:prettier": "prettier -w -u src/**/*.{ts,vue} docs/**/*.{ts,vue}", 54 | "lint:stylelint": "stylelint **/*.{less,vue} --syntax less" 55 | }, 56 | "devDependencies": { 57 | "@rollup/plugin-babel": "^5.2.1", 58 | "@rollup/plugin-commonjs": "^13.0.0", 59 | "@rollup/plugin-node-resolve": "^7.1.3", 60 | "@types/body-scroll-lock": "^2.6.1", 61 | "@typescript-eslint/eslint-plugin": "^4.15.1", 62 | "@typescript-eslint/parser": "^4.15.1", 63 | "@vitejs/plugin-vue": "^4.0.0", 64 | "@vue/babel-preset-app": "^4.5.6", 65 | "@vue/babel-preset-jsx": "^1.1.2", 66 | "@vue/compiler-sfc": "^3.0.5", 67 | "@vue/eslint-config-prettier": "^6.0.0", 68 | "@vue/eslint-config-typescript": "^7.0.0", 69 | "autoprefixer": "^10.4.2", 70 | "babel-plugin-pure-calls-annotation": "^0.3.1", 71 | "babel-plugin-typescript-iife-enum": "^0.2.1", 72 | "clean-css": "^4.2.3", 73 | "core-js": "^3.6.5", 74 | "eslint": "^7.20.0", 75 | "eslint-plugin-prettier": "^3.3.1", 76 | "eslint-plugin-vue": "^7.6.0", 77 | "husky": "^4.3.8", 78 | "less": "^3.12.2", 79 | "lint-staged": "^10.5.4", 80 | "postcss": "^8.4.6", 81 | "prettier": "^2.2.1", 82 | "prettier-plugin-tailwindcss": "^0.1.8", 83 | "stylelint": "^16.10.0", 84 | "stylelint-config-recommended": "^3.0.0", 85 | "stylelint-config-standard": "^20.0.0", 86 | "tailwindcss": "^3.1.0", 87 | "ts-node": "^10.9.1", 88 | "typescript": "^4.9.4", 89 | "vite": "^5.4.10" 90 | }, 91 | "dependencies": { 92 | "@floating-ui/dom": "^0.5.4", 93 | "@vueuse/core": "^5.0.3", 94 | "@vueuse/integrations": "^11.1.0", 95 | "body-scroll-lock": "^3.1.5", 96 | "colord": "^2.9.2", 97 | "focus-trap": "^7.6.0", 98 | "tailwind-merge": "^1.13.2", 99 | "vite-plugin-dts": "^4.3.0", 100 | "vue": "^3.0.5" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'all', 3 | singleQuote: true, 4 | endOfLine: 'auto', 5 | htmlWhitespaceSensitivity: 'ignore', 6 | semi: false, 7 | plugins: [require('prettier-plugin-tailwindcss')] 8 | } 9 | -------------------------------------------------------------------------------- /scripts/prepareTheme.ts: -------------------------------------------------------------------------------- 1 | // import full from '../src/theme/full' 2 | // import light from '../src/theme/light' 3 | // import dark from '../src/theme/dark' 4 | import fs from 'fs' 5 | 6 | fs.mkdirSync('./dist/theme', { recursive: true }) 7 | fs.copyFileSync('./src/theme/full.ts', './dist/theme/full.ts') 8 | fs.copyFileSync('./src/theme/full.ts', './dist/theme/full.js') 9 | fs.copyFileSync('./src/theme/light.ts', './dist/theme/light.ts') 10 | fs.copyFileSync('./src/theme/light.ts', './dist/theme/light.js') 11 | fs.copyFileSync('./src/theme/dark.ts', './dist/theme/dark.ts') 12 | fs.copyFileSync('./src/theme/dark.ts', './dist/theme/dark.js') 13 | 14 | // fs.writeFileSync('./dist/theme/full.json', JSON.stringify(full, null, 2)) 15 | // fs.writeFileSync('./dist/theme/light.json', JSON.stringify(light, null, 2)) 16 | // fs.writeFileSync('./dist/theme/dark.json', JSON.stringify(dark, null, 2)) 17 | -------------------------------------------------------------------------------- /src/components/alert/ItAlert.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 63 | -------------------------------------------------------------------------------- /src/components/alert/index.ts: -------------------------------------------------------------------------------- 1 | import Alert from './ItAlert.vue' 2 | import { App } from 'vue' 3 | 4 | Alert.install = (Vue: App) => { 5 | Vue.component(Alert.name, Alert) 6 | } 7 | 8 | export default Alert 9 | -------------------------------------------------------------------------------- /src/components/avatar-group/ItAvatarGroup.vue: -------------------------------------------------------------------------------- 1 | 66 | -------------------------------------------------------------------------------- /src/components/avatar-group/hooks.ts: -------------------------------------------------------------------------------- 1 | import { Slots, computed, onUpdated, ref } from 'vue' 2 | import { getChildrenVNodesFromSlot } from '@/helpers/getChildrenVNodesFromSlot' 3 | import { TUseAvatarGroup } from '@/components/avatar-group/types' 4 | 5 | export const useAvatarGroup = ( 6 | props: { max: number | null }, 7 | slots: Slots, 8 | ): TUseAvatarGroup => { 9 | const childrenVNodes = ref( 10 | slots.default ? getChildrenVNodesFromSlot(slots.default) : [], 11 | ) 12 | 13 | onUpdated(() => { 14 | const newAvatars = slots.default 15 | ? getChildrenVNodesFromSlot(slots.default) 16 | : [] 17 | if (newAvatars.length !== childrenVNodes.value.length) { 18 | childrenVNodes.value = newAvatars 19 | } 20 | }) 21 | 22 | const totalChildrenVNodes = computed(() => 23 | childrenVNodes.value.slice(0, props.max || childrenVNodes.value.length), 24 | ) 25 | 26 | const label = computed(() => ({ 27 | show: props.max ? childrenVNodes.value.length > props.max : false, 28 | count: props.max ? childrenVNodes.value.length - props.max : 0, 29 | })) 30 | 31 | return { 32 | totalChildrenVNodes, 33 | label, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/components/avatar-group/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import AvatarGroup from './ItAvatarGroup.vue' 3 | 4 | AvatarGroup.install = (Vue: App) => { 5 | Vue.component(AvatarGroup.name, AvatarGroup) 6 | } 7 | 8 | export default AvatarGroup 9 | -------------------------------------------------------------------------------- /src/components/avatar-group/types.ts: -------------------------------------------------------------------------------- 1 | import { VNode, ComputedRef } from 'vue' 2 | 3 | export type TUseAvatarGroup = { 4 | totalChildrenVNodes: ComputedRef 5 | label: ComputedRef<{ 6 | show: boolean 7 | count: number 8 | }> 9 | } 10 | -------------------------------------------------------------------------------- /src/components/avatar/ItAvatar.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 62 | -------------------------------------------------------------------------------- /src/components/avatar/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Avatar from './ItAvatar.vue' 3 | 4 | Avatar.install = (Vue: App) => { 5 | Vue.component(Avatar.name, Avatar) 6 | } 7 | 8 | export default Avatar 9 | -------------------------------------------------------------------------------- /src/components/badge/ItBadge.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 63 | -------------------------------------------------------------------------------- /src/components/badge/constants.ts: -------------------------------------------------------------------------------- 1 | import { Positions } from '@/models/enums' 2 | 3 | export const ALLOWED_POSITIONS = [ 4 | Positions.TL, 5 | Positions.TR, 6 | Positions.BL, 7 | Positions.BR, 8 | ] 9 | -------------------------------------------------------------------------------- /src/components/badge/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Badge from './ItBadge.vue' 3 | 4 | Badge.install = (Vue: App) => { 5 | Vue.component(Badge.name, Badge) 6 | } 7 | 8 | export default Badge 9 | -------------------------------------------------------------------------------- /src/components/button-group/ItButtonGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 41 | -------------------------------------------------------------------------------- /src/components/button-group/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import ButtonGroup from './ItButtonGroup.vue' 3 | 4 | ButtonGroup.install = (Vue: App) => { 5 | Vue.component(ButtonGroup.name, ButtonGroup) 6 | } 7 | 8 | export default ButtonGroup 9 | -------------------------------------------------------------------------------- /src/components/button/ItButton.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 95 | -------------------------------------------------------------------------------- /src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Button from './ItButton.vue' 3 | 4 | Button.install = (Vue: App) => { 5 | Vue.component(Button.name, Button) 6 | } 7 | 8 | export default Button 9 | -------------------------------------------------------------------------------- /src/components/checkbox/ItCheckbox.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 98 | -------------------------------------------------------------------------------- /src/components/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Checkbox from './ItCheckbox.vue' 3 | 4 | Checkbox.install = (Vue: App) => { 5 | Vue.component(Checkbox.name, Checkbox) 6 | } 7 | 8 | export default Checkbox 9 | -------------------------------------------------------------------------------- /src/components/collapse-item/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import CollapseItem from '@/components/collapse/ItCollapseItem.vue' 3 | 4 | CollapseItem.install = (Vue: App) => { 5 | Vue.component(CollapseItem.name, CollapseItem) 6 | } 7 | 8 | export default CollapseItem 9 | -------------------------------------------------------------------------------- /src/components/collapse/ItCollapse.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | -------------------------------------------------------------------------------- /src/components/collapse/ItCollapseItem.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 63 | -------------------------------------------------------------------------------- /src/components/collapse/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Collapse from './ItCollapse.vue' 3 | 4 | Collapse.install = (Vue: App) => { 5 | Vue.component(Collapse.name, Collapse) 6 | } 7 | 8 | export default Collapse 9 | -------------------------------------------------------------------------------- /src/components/colorpicker/ItColorpicker.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 72 | -------------------------------------------------------------------------------- /src/components/colorpicker/helpers.ts: -------------------------------------------------------------------------------- 1 | // // import tinycolor from 'tinycolor2' 2 | // import { TColorData } from './types' 3 | 4 | // export function _colorChange(data: any): TColorData { 5 | // const alpha = data && data.a 6 | // // const color = tinycolor(data) 7 | 8 | // if (color && (color.getAlpha() === undefined || color.getAlpha() === null)) { 9 | // color.setAlpha(alpha || 1) 10 | // } 11 | 12 | // const hsl = color.toHsl() 13 | // const hsv = color.toHsv() 14 | 15 | // // prevents color change when cursor is on max left position 16 | // if (hsl.s === 0) { 17 | // hsv.h = hsl.h = data.h || (data.hsl && data.hsl.h) || 0 18 | // } 19 | 20 | // // prevents color change when cursor is on max bottom position 21 | // if (hsv.v < 0.0164) { 22 | // hsv.h = data.h || (data.hsv && data.hsv.h) || 0 23 | // hsv.s = data.s || (data.hsv && data.hsv.s) || 0 24 | // } 25 | 26 | // if (hsl.l < 0.01) { 27 | // hsl.h = data.h || (data.hsl && data.hsl.h) || 0 28 | // hsl.s = data.s || (data.hsl && data.hsl.s) || 0 29 | // } 30 | 31 | // return { 32 | // hsl, 33 | // hex: color.toHexString().toUpperCase(), 34 | // hex8: color.toHex8String().toUpperCase(), 35 | // rgba: color.toRgb(), 36 | // hsv, 37 | // a: data.a || color.getAlpha(), 38 | // } 39 | // } 40 | -------------------------------------------------------------------------------- /src/components/colorpicker/hooks.ts: -------------------------------------------------------------------------------- 1 | import { computed, ref } from 'vue' 2 | import { colord } from 'colord' 3 | 4 | export const colorpicker = ( 5 | props: { [key: string]: any }, 6 | emit: (name: string, prop: any) => void, 7 | ) => { 8 | const val = ref(colord(props.value)) 9 | const colors = computed({ 10 | get: () => { 11 | return val.value 12 | }, 13 | set: (newVal) => { 14 | val.value = newVal 15 | emit('change', newVal) 16 | }, 17 | }) 18 | 19 | const hue = ref(colord(props.value).toHsl().h) 20 | 21 | function colorChange(data?: any) { 22 | colors.value = colord({ 23 | ...(data ? data : colors.value.toHsv()), 24 | h: hue.value, 25 | }) 26 | } 27 | 28 | function changeHue(val: number) { 29 | hue.value = val 30 | if (colors.value.toHsv().s !== 0) { 31 | colorChange() 32 | } 33 | } 34 | 35 | return { 36 | val, 37 | colors, 38 | hue, 39 | colorChange, 40 | changeHue, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/colorpicker/hooks/alpha.ts: -------------------------------------------------------------------------------- 1 | import { clamp } from '@/helpers/clamp' 2 | import { Positions } from '@/models/enums/Positions' 3 | import { computed, ref } from 'vue' 4 | 5 | export const alpha = ( 6 | props: { [key: string]: any }, 7 | emit: (name: string, prop: any) => void, 8 | ) => { 9 | const colors = computed(() => props.modelValue) 10 | const container = ref(null) 11 | 12 | function handleChange(e: TouchEvent & MouseEvent, skip) { 13 | !skip && e.preventDefault() 14 | if (!container.value) { 15 | return 16 | } 17 | const containerWidth = container.value!.clientWidth 18 | 19 | const xOffset = 20 | container.value!.getBoundingClientRect().left + window.pageXOffset 21 | const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0) 22 | const left = pageX - xOffset 23 | 24 | let a 25 | if (left < 0) { 26 | a = 0 27 | } else if (left > containerWidth) { 28 | a = 1 29 | } else { 30 | a = Math.round((left * 100) / containerWidth) / 100 31 | } 32 | 33 | if (colors.value.a !== a) { 34 | const HSValue = colors.value.toHsv() 35 | emit('change', { 36 | h: HSValue.h, 37 | s: HSValue.s, 38 | v: HSValue.v, 39 | a, 40 | }) 41 | } 42 | } 43 | 44 | function toKeyHandler(side: Positions.L | Positions.R, e: KeyboardEvent) { 45 | let newAlpha = colors.value.toHsv().a 46 | const amount = e.shiftKey ? 0.075 : 0.025 47 | switch (side) { 48 | case Positions.L: 49 | newAlpha -= amount 50 | break 51 | case Positions.R: 52 | newAlpha += amount 53 | break 54 | default: 55 | return 56 | } 57 | 58 | const clampedValue = clamp(newAlpha, 0, 1) 59 | if (colors.value.a !== clampedValue) { 60 | const HSValue = colors.value.toHsv() 61 | emit('change', { 62 | h: HSValue.h, 63 | s: HSValue.s, 64 | v: HSValue.v, 65 | a: clampedValue, 66 | }) 67 | } 68 | } 69 | 70 | function handleMouseDown(e: MouseEvent & TouchEvent) { 71 | handleChange(e, true) 72 | window.addEventListener('mousemove', handleChange) 73 | window.addEventListener('mouseup', handleMouseUp) 74 | } 75 | function handleMouseUp() { 76 | unbindEventListeners() 77 | } 78 | function unbindEventListeners() { 79 | window.removeEventListener('mousemove', handleChange) 80 | window.removeEventListener('mouseup', handleMouseUp) 81 | } 82 | 83 | return { 84 | colors, 85 | container, 86 | handleChange, 87 | handleMouseDown, 88 | toKeyHandler, 89 | handleMouseUp, 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/components/colorpicker/hooks/hue.ts: -------------------------------------------------------------------------------- 1 | import { clamp } from '@/helpers/clamp' 2 | import { Positions } from '@/models/enums/Positions' 3 | import { ref } from 'vue' 4 | 5 | export const hue = ( 6 | props: { [key: string]: any }, 7 | emit: (name: string, prop: any) => void, 8 | ) => { 9 | const oldHue = ref(0) 10 | const pullDirection = ref(Positions.R) 11 | const container = ref(null) 12 | // const colors = computed(() => { 13 | // const h = props.hue 14 | // if (h - oldHue.value > 0) pullDirection.value = Positions.R 15 | // if (h - oldHue.value < 0) pullDirection.value = Positions.L 16 | // oldHue.value = h 17 | 18 | // return props.hue 19 | // }) 20 | function handleChange(e: TouchEvent & MouseEvent, skip: any) { 21 | !skip && e.preventDefault() 22 | 23 | if (!container.value) { 24 | return 25 | } 26 | const containerWidth = container.value!.clientWidth 27 | 28 | const xOffset = 29 | container.value!.getBoundingClientRect().left + window.pageXOffset 30 | const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0) 31 | const left = pageX - xOffset 32 | 33 | // tslint:disable-next-line: one-variable-per-declaration 34 | let h, percent 35 | 36 | if (left < 0) { 37 | h = 0 38 | } else if (left > containerWidth) { 39 | h = 360 40 | } else { 41 | percent = (left * 100) / containerWidth 42 | h = (360 * percent) / 100 43 | } 44 | 45 | if (props.hue !== h) { 46 | emit('change', h) 47 | } 48 | } 49 | 50 | function toKeyHandler(side: Positions.L | Positions.R, e: KeyboardEvent) { 51 | let newHue = props.hue 52 | const amount = e.shiftKey ? 15 : 5 53 | switch (side) { 54 | case Positions.L: 55 | newHue -= amount 56 | break 57 | case Positions.R: 58 | newHue += amount 59 | break 60 | default: 61 | return 62 | } 63 | 64 | if (props.hue !== newHue) { 65 | emit('change', clamp(newHue, 0, 360)) 66 | } 67 | } 68 | 69 | function handleMouseDown(e) { 70 | handleChange(e, true) 71 | window.addEventListener('mousemove', handleChange) 72 | window.addEventListener('mouseup', handleMouseUp) 73 | } 74 | function handleMouseUp(e) { 75 | unbindEventListeners() 76 | } 77 | function unbindEventListeners() { 78 | window.removeEventListener('mousemove', handleChange) 79 | window.removeEventListener('mouseup', handleMouseUp) 80 | } 81 | 82 | return { 83 | container, 84 | // colors, 85 | pullDirection, 86 | toKeyHandler, 87 | handleChange, 88 | handleMouseDown, 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/components/colorpicker/hooks/saturation.ts: -------------------------------------------------------------------------------- 1 | import { clamp } from '@/helpers/clamp' 2 | import { Colord } from 'colord' 3 | import { computed, ref } from 'vue' 4 | 5 | export const saturation = ( 6 | props: { [key: string]: any }, 7 | emit: (name: string, prop: any) => void, 8 | ) => { 9 | const showTooltip = ref(false) 10 | const colors = computed(() => props.modelValue) 11 | const container = ref(null) 12 | 13 | const pointerTop = computed(() => -colors.value.toHsv().v + 100) 14 | const pointerLeft = computed(() => colors.value.toHsv().s) 15 | 16 | function handleChange(e: MouseEvent & TouchEvent, skip: boolean) { 17 | !skip && e.preventDefault() 18 | if (!container.value) { 19 | return 20 | } 21 | 22 | if (props.tooltip && !showTooltip.value) { 23 | showTooltip.value = true 24 | } 25 | 26 | const { clientWidth, clientHeight } = container.value! 27 | 28 | const xOffset = 29 | container.value!.getBoundingClientRect().left + window.pageXOffset 30 | const yOffset = 31 | container.value!.getBoundingClientRect().top + window.pageYOffset 32 | const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0) 33 | const pageY = e.pageY || (e.touches ? e.touches[0].pageY : 0) 34 | const left = clamp(pageX - xOffset, 0, clientWidth) 35 | const top = clamp(pageY - yOffset, 0, clientHeight) 36 | const saturation = (left / clientWidth) * 100 37 | const bright = clamp((-(top / clientHeight) + 1) * 100, 0.001, 100) 38 | 39 | const { h, a } = colors.value.toHsv() 40 | emit('change', { 41 | h, 42 | s: saturation, 43 | v: bright, 44 | a, 45 | }) 46 | } 47 | 48 | function toKeyHandler( 49 | side: 'up' | 'right' | 'down' | 'left', 50 | e: KeyboardEvent, 51 | ) { 52 | const { h, s, v, a } = colors.value.toHsv() 53 | const amount = e.shiftKey ? 15 : 5 54 | let newS = s 55 | let newV = v 56 | switch (side) { 57 | case 'up': 58 | newV += amount 59 | break 60 | case 'down': 61 | newV -= amount 62 | break 63 | case 'left': 64 | newS -= amount 65 | break 66 | case 'right': 67 | newS += amount 68 | break 69 | 70 | default: 71 | return 72 | break 73 | } 74 | emit('change', { 75 | h, 76 | s: clamp(newS, 0, 100), 77 | v: clamp(newV, 0.001, 100), 78 | a, 79 | }) 80 | } 81 | 82 | function handleMouseDown() { 83 | window.addEventListener('mousemove', handleChange) 84 | window.addEventListener('mouseup', handleChange) 85 | window.addEventListener('touchstart', handleChange) 86 | window.addEventListener('mouseup', handleMouseUp) 87 | } 88 | function handleMouseUp() { 89 | unbindEventListeners() 90 | showTooltip.value = false 91 | } 92 | function unbindEventListeners() { 93 | window.removeEventListener('mousemove', handleChange) 94 | window.removeEventListener('mouseup', handleChange) 95 | window.removeEventListener('mouseup', handleMouseUp) 96 | } 97 | 98 | return { 99 | showTooltip, 100 | colors, 101 | container, 102 | pointerTop, 103 | pointerLeft, 104 | handleChange, 105 | handleMouseDown, 106 | handleMouseUp, 107 | toKeyHandler, 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/components/colorpicker/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Colorpicker from './ItColorpicker.vue' 3 | 4 | // @ts-ignore 5 | Colorpicker.install = (Vue: App) => { 6 | Vue.component(Colorpicker.name, Colorpicker) 7 | } 8 | 9 | export default Colorpicker 10 | -------------------------------------------------------------------------------- /src/components/colorpicker/subcomponents/Alpha.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 88 | -------------------------------------------------------------------------------- /src/components/colorpicker/subcomponents/Checkboard.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /src/components/colorpicker/subcomponents/Hue.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 81 | -------------------------------------------------------------------------------- /src/components/colorpicker/subcomponents/Saturation.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 96 | -------------------------------------------------------------------------------- /src/components/datepicker/ItDatepicker.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | -------------------------------------------------------------------------------- /src/components/datepicker/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Datepicker from './ItDatepicker.vue' 3 | 4 | // @ts-ignore 5 | Datepicker.install = (Vue: App) => { 6 | Vue.component(Datepicker.name, Datepicker) 7 | } 8 | 9 | export default Datepicker 10 | -------------------------------------------------------------------------------- /src/components/divider/ItDivider.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 35 | -------------------------------------------------------------------------------- /src/components/divider/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Divider from './ItDivider.vue' 3 | 4 | // @ts-ignore 5 | Divider.install = (Vue: App) => { 6 | Vue.component(Divider.name, Divider) 7 | } 8 | 9 | export default Divider 10 | -------------------------------------------------------------------------------- /src/components/drawer/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Drawer from './ItDrawer.vue' 3 | 4 | Drawer.install = (Vue: App) => { 5 | Vue.component(Drawer.name, Drawer) 6 | } 7 | 8 | export default Drawer 9 | -------------------------------------------------------------------------------- /src/components/dropdown/ItDropdown.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 118 | -------------------------------------------------------------------------------- /src/components/dropdown/ItDropdownItem.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 54 | -------------------------------------------------------------------------------- /src/components/dropdown/ItDropdownMenu.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 26 | -------------------------------------------------------------------------------- /src/components/dropdown/index.ts: -------------------------------------------------------------------------------- 1 | import Dropdown from './ItDropdown.vue' 2 | import DropdownMenu from './ItDropdownMenu.vue' 3 | import DropdownItem from './ItDropdownItem.vue' 4 | import { App, DefineComponent } from 'vue' 5 | 6 | const dropdown = { 7 | Dropdown, 8 | DropdownMenu, 9 | DropdownItem, 10 | } 11 | 12 | for (const elem in dropdown) { 13 | if (dropdown.hasOwnProperty(elem)) { 14 | // @ts-ignore 15 | const element = dropdown[elem] 16 | element.install = (Vue: App) => { 17 | Vue.component(element.name, element) 18 | } 19 | } 20 | } 21 | 22 | export default dropdown 23 | -------------------------------------------------------------------------------- /src/components/input/ItInput.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 93 | -------------------------------------------------------------------------------- /src/components/input/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Input from './ItInput.vue' 3 | 4 | Input.install = (Vue: App) => { 5 | Vue.component(Input.name, Input) 6 | } 7 | 8 | export default Input 9 | -------------------------------------------------------------------------------- /src/components/loadingbar/ItLoadingbar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 89 | 90 | 106 | -------------------------------------------------------------------------------- /src/components/loadingbar/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Loadingbar from './ItLoadingbar.vue' 3 | 4 | Loadingbar.install = (Vue: App) => { 5 | Vue.component(Loadingbar.name, Loadingbar) 6 | } 7 | 8 | export default Loadingbar 9 | -------------------------------------------------------------------------------- /src/components/modal/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Modal from './ItModal.vue' 3 | 4 | Modal.install = (Vue: App) => { 5 | Vue.component(Modal.name, Modal) 6 | } 7 | 8 | export default Modal 9 | -------------------------------------------------------------------------------- /src/components/numberinput/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import NumberInput from './ItNumberInput.vue' 3 | 4 | NumberInput.install = (Vue: App) => { 5 | Vue.component(NumberInput.name, NumberInput) 6 | } 7 | 8 | export default NumberInput 9 | -------------------------------------------------------------------------------- /src/components/popover/ItPopover.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 73 | -------------------------------------------------------------------------------- /src/components/popover/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Popover from './ItPopover.vue' 3 | 4 | Popover.install = (Vue: App) => { 5 | Vue.component(Popover.name, Popover) 6 | } 7 | 8 | export default Popover 9 | -------------------------------------------------------------------------------- /src/components/progressbar/ItProgressbar.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 68 | 69 | 87 | -------------------------------------------------------------------------------- /src/components/progressbar/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Progressbar from './ItProgressbar.vue' 3 | 4 | Progressbar.install = (Vue: App) => { 5 | Vue.component(Progressbar.name, Progressbar) 6 | } 7 | 8 | export default Progressbar 9 | -------------------------------------------------------------------------------- /src/components/radio/ItRadio.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 83 | -------------------------------------------------------------------------------- /src/components/radio/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Radio from './ItRadio.vue' 3 | 4 | Radio.install = (Vue: App) => { 5 | Vue.component(Radio.name, Radio) 6 | } 7 | 8 | export default Radio 9 | -------------------------------------------------------------------------------- /src/components/select/constants.ts: -------------------------------------------------------------------------------- 1 | import { Positions } from '@/models/enums' 2 | 3 | export const ALLOWED_POSITION = [ 4 | Positions.T, 5 | Positions.B, 6 | Positions.L, 7 | Positions.R, 8 | Positions.TL, 9 | Positions.TR, 10 | Positions.BL, 11 | Positions.BR, 12 | ] 13 | 14 | export const CLASS_SELECTED_OPTION = 'it-select-option--focused' 15 | -------------------------------------------------------------------------------- /src/components/select/helpers.ts: -------------------------------------------------------------------------------- 1 | import { EDirections } from '@/models/enums' 2 | 3 | type Props = { 4 | direction: EDirections 5 | array: [] 6 | curIndex: number 7 | } 8 | 9 | export const getArrayIndexByDirection = ({ 10 | direction, 11 | array, 12 | curIndex, 13 | }: Props): number => { 14 | const resultMap = { 15 | [EDirections.UP]: curIndex <= 0 ? array.length - 1 : curIndex - 1, 16 | [EDirections.DOWN]: curIndex === array.length - 1 ? 0 : curIndex + 1, 17 | } 18 | return resultMap[direction] 19 | } 20 | -------------------------------------------------------------------------------- /src/components/select/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Select from './ItSelect.vue' 3 | 4 | Select.install = (Vue: App) => { 5 | Vue.component(Select.name, Select) 6 | } 7 | 8 | export default Select 9 | -------------------------------------------------------------------------------- /src/components/select/types.ts: -------------------------------------------------------------------------------- 1 | import { Ref, ComputedRef } from 'vue' 2 | import { EDirections } from '@/models/enums' 3 | 4 | export type TOption = 5 | | string 6 | | number 7 | | { 8 | [trackBy: string]: string | number 9 | name: string | number 10 | } 11 | 12 | export type TSelectProps = { 13 | multiselect: boolean 14 | modelValue: TOption | null 15 | disabled: boolean 16 | options: TOption[] 17 | trackBy: string 18 | } 19 | 20 | export type TSelect = { 21 | wrappedValue: ComputedRef 22 | getOptionName: (option: TOption) => string | number 23 | getOptionValue: (option: TOption) => string | number 24 | setOptionRef: (el: HTMLElement, i: number) => void 25 | indexFocusedOption: Ref 26 | optionsRefs: Ref 27 | show: Ref 28 | handleEnterKey: () => void 29 | remove: () => void 30 | setOpen: (state: boolean) => void 31 | toggleDropdown: () => void 32 | selectOption: (optionIndex: number) => void 33 | setSelectListRef: (dropdown: HTMLElement) => void 34 | handleKey: (type: EDirections) => void 35 | } 36 | -------------------------------------------------------------------------------- /src/components/slider/constants.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_STEP_POINT_HEIGHT = 8 2 | export const DEFAULT_PROPS = { 3 | MIN: 0, 4 | MAX: 100, 5 | STEP: 1, 6 | VALUE: 0, 7 | } 8 | -------------------------------------------------------------------------------- /src/components/slider/helpers.ts: -------------------------------------------------------------------------------- 1 | import { TTotalValuePosition } from '@/components/slider/types' 2 | 3 | export const getTotalPosition = ({ 4 | value, 5 | min, 6 | max, 7 | }: TTotalValuePosition): number => ((value - min) * 100) / (max - min) 8 | 9 | export const getCoordsByEvent = ({ 10 | changedTouches, 11 | clientX, 12 | clientY, 13 | }: MouseEvent & TouchEvent): { clientX: number; clientY: number } => { 14 | const firstTouch = changedTouches ? changedTouches[0] : null 15 | return firstTouch 16 | ? { clientX: firstTouch.clientX, clientY: firstTouch.clientY } 17 | : { clientX, clientY } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/slider/hooks.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_PROPS } from './constants' 2 | import { clamp } from './../../helpers/clamp' 3 | import { computed, ref, Ref, ComputedRef } from 'vue' 4 | import { 5 | TDataByPreparedStepList, 6 | TResultUseValuePosition, 7 | TStepItem, 8 | TTotalValuePosition, 9 | } from '@/components/slider/types' 10 | import { getTotalPosition } from './helpers' 11 | 12 | export const useStepsPoints = ( 13 | startValue: TStepItem[], 14 | { max, min, step, valuePosition }: TDataByPreparedStepList, 15 | ): ComputedRef => 16 | computed(() => { 17 | const resultStepsPoints: TStepItem[] = [...startValue] 18 | const countPoints = (max - min) / step 19 | let accumulatedLeft = 0 20 | const distanceBetweenPoints = 100 / (max / step) 21 | 22 | for (let i = 0; i < countPoints; i++) { 23 | accumulatedLeft += distanceBetweenPoints 24 | const active = accumulatedLeft <= valuePosition.value 25 | resultStepsPoints.push({ left: accumulatedLeft, active }) 26 | } 27 | 28 | return resultStepsPoints 29 | }) 30 | 31 | export const useValuePosition = ( 32 | props: { [key: string]: any }, 33 | emit: (name: string, prop: any) => void, 34 | ): TResultUseValuePosition => { 35 | const startValue = getTotalPosition({ 36 | value: props.modelValue, 37 | min: props.min, 38 | max: props.max, 39 | } as TTotalValuePosition) 40 | const valuePosition: Ref = ref(startValue) 41 | 42 | const setValuePosition = (newValue: number) => { 43 | newValue = clamp(newValue, DEFAULT_PROPS.MIN, DEFAULT_PROPS.MAX) 44 | 45 | const lengthPerStep = 100 / ((props.max - props.min) / props.step) 46 | const steps = Math.round(newValue / lengthPerStep) 47 | 48 | let totalValue = 49 | steps * lengthPerStep * (props.max - props.min) * 0.01 + props.min 50 | totalValue = parseFloat(totalValue.toFixed(0)) 51 | totalValue = totalValue > props.max ? props.max : totalValue 52 | 53 | emit('update:modelValue', totalValue) 54 | valuePosition.value = getTotalPosition({ 55 | value: totalValue, 56 | min: props.min, 57 | max: props.max, 58 | }) 59 | } 60 | 61 | return [valuePosition, setValuePosition] 62 | } 63 | -------------------------------------------------------------------------------- /src/components/slider/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Slider from './ItSlider.vue' 3 | 4 | Slider.install = (Vue: App) => { 5 | Vue.component(Slider.name, Slider) 6 | } 7 | 8 | export default Slider 9 | -------------------------------------------------------------------------------- /src/components/slider/types.ts: -------------------------------------------------------------------------------- 1 | import { Ref } from 'vue' 2 | import { Positions } from '@/models/enums' 3 | 4 | export type TTotalValuePosition = { 5 | value: number 6 | min: number 7 | max: number 8 | } 9 | 10 | export type TStepItem = { 11 | left: number 12 | active: boolean 13 | } 14 | 15 | export type TDataByPreparedStepList = { 16 | max: number 17 | min: number 18 | step: number 19 | valuePosition: Ref 20 | } 21 | 22 | export type TKeyEvents = Positions.T | Positions.R | Positions.B | Positions.L 23 | 24 | export type TResultUseValuePosition = [Ref, (newValue: number) => void] 25 | -------------------------------------------------------------------------------- /src/components/spinner/ItSpinner.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 30 | -------------------------------------------------------------------------------- /src/components/spinner/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Spinner from './ItSpinner.vue' 3 | 4 | Spinner.install = (Vue: App) => { 5 | Vue.component(Spinner.name, Spinner) 6 | } 7 | 8 | export default Spinner 9 | -------------------------------------------------------------------------------- /src/components/switch/ItSwitch.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 75 | -------------------------------------------------------------------------------- /src/components/switch/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Switch from './ItSwitch.vue' 3 | 4 | Switch.install = (Vue: App) => { 5 | Vue.component(Switch.name, Switch) 6 | } 7 | 8 | export default Switch 9 | -------------------------------------------------------------------------------- /src/components/tab/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Tab from '@/components/tabs/ItTab.vue' 3 | 4 | Tab.install = (Vue: App) => { 5 | Vue.component(Tab.name, Tab) 6 | } 7 | 8 | export default Tab 9 | -------------------------------------------------------------------------------- /src/components/tabs/ItTab.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 37 | -------------------------------------------------------------------------------- /src/components/tabs/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Tabs from './ItTabs.vue' 3 | 4 | Tabs.install = (Vue: App) => { 5 | Vue.component(Tabs.name, Tabs) 6 | } 7 | 8 | export default Tabs 9 | -------------------------------------------------------------------------------- /src/components/tag/ItTag.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 61 | -------------------------------------------------------------------------------- /src/components/tag/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Tag from './ItTag.vue' 3 | 4 | Tag.install = (Vue: App) => { 5 | Vue.component(Tag.name, Tag) 6 | } 7 | 8 | export default Tag 9 | -------------------------------------------------------------------------------- /src/components/textarea/ItTextarea.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 87 | -------------------------------------------------------------------------------- /src/components/textarea/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Textarea from './ItTextarea.vue' 3 | 4 | Textarea.install = (Vue: App) => { 5 | Vue.component(Textarea.name, Textarea) 6 | } 7 | 8 | export default Textarea 9 | -------------------------------------------------------------------------------- /src/components/toggle/ItToggle.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 105 | -------------------------------------------------------------------------------- /src/components/toggle/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Toggle from './ItToggle.vue' 3 | 4 | Toggle.install = (Vue: App) => { 5 | Vue.component(Toggle.name, Toggle) 6 | } 7 | 8 | export default Toggle 9 | -------------------------------------------------------------------------------- /src/components/tooltip/ItTooltip.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 127 | -------------------------------------------------------------------------------- /src/components/tooltip/TooltipBody.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 46 | -------------------------------------------------------------------------------- /src/components/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import Tooltip from './ItTooltip.vue' 3 | 4 | Tooltip.install = (Vue: App) => { 5 | Vue.component(Tooltip.name, Tooltip) 6 | } 7 | 8 | export default Tooltip 9 | -------------------------------------------------------------------------------- /src/directives/clickOutside.ts: -------------------------------------------------------------------------------- 1 | import { Directive } from 'vue' 2 | 3 | export const clickOutside: Directive = { 4 | beforeMount(elem, binding) { 5 | // Used to prevent clickOutsideHandle to fire if mousedown started on element 6 | let startedSource = false 7 | 8 | elem.clickStarted = (e: Event) => { 9 | if (elem.contains(e.target)) { 10 | startedSource = true 11 | } 12 | } 13 | 14 | elem.clickOutsideHandler = (e: Event) => { 15 | if (!elem.contains(e.target) && binding.value && !startedSource) { 16 | binding.value(e) 17 | } 18 | startedSource = false 19 | } 20 | 21 | document.addEventListener('mousedown', elem.clickStarted) 22 | document.addEventListener('mouseup', elem.clickOutsideHandler) 23 | }, 24 | unmounted(elem) { 25 | document.removeEventListener('mouseup', elem.clickOutsideHandler) 26 | document.removeEventListener('mousedown', elem.clickOutsideHandler) 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /src/directives/index.ts: -------------------------------------------------------------------------------- 1 | export { clickOutside } from './clickOutside' 2 | -------------------------------------------------------------------------------- /src/directives/tooltip.ts: -------------------------------------------------------------------------------- 1 | import TooltipBody from '@/components/tooltip/TooltipBody.vue' 2 | import { usePopover } from '@/hooks/usePopover' 3 | import { Positions } from '@/models/enums/Positions' 4 | import { EqualUIConfiguration } from '@/types/variant' 5 | import { autoUpdate } from '@floating-ui/dom' 6 | import { createApp, Directive, h, reactive, ref, unref, watch } from 'vue' 7 | 8 | export const tooltip = (theme: EqualUIConfiguration): Directive => ({ 9 | mounted(elem, binding) { 10 | const { 11 | show, 12 | popover, 13 | trigger, 14 | placement, 15 | handleMouseEnter, 16 | handleMouseLeave, 17 | setPopoverPosition, 18 | permanent, 19 | disabled, 20 | } = usePopover({}) 21 | 22 | const mountEl = document.createElement('div') 23 | 24 | // https://github.com/vuejs/core/issues/4874#issuecomment-959008724 25 | const myTooltip = createApp({ 26 | render: () => 27 | h( 28 | TooltipBody, 29 | reactive({ 30 | placement, 31 | show, 32 | content: binding.value.content, 33 | }), 34 | () => binding.value.children, 35 | ), 36 | }) 37 | myTooltip.provide('config', theme) 38 | 39 | placement.value = unref(binding.value.position) || placement.value 40 | 41 | watch( 42 | ref(binding.value.disabled), 43 | (val) => { 44 | disabled.value = unref(val) 45 | }, 46 | { immediate: true }, 47 | ) 48 | 49 | watch( 50 | ref(binding.value.permanent), 51 | (val) => { 52 | permanent.value = !!unref(val) 53 | }, 54 | { immediate: true }, 55 | ) 56 | watch(ref(binding.value.content), setPopoverPosition) 57 | watch(ref(binding.value.position), (val: Positions) => { 58 | if (!val) { 59 | return 60 | } 61 | placement.value = unref(val) 62 | setPopoverPosition() 63 | }) 64 | 65 | // mount tooltip El 66 | const comp = myTooltip.mount(mountEl) 67 | document.body.appendChild(mountEl) 68 | 69 | // set $refs 70 | trigger.value = elem 71 | popover.value = comp.$el 72 | 73 | elem.myTooltip = myTooltip 74 | elem.mountEl = mountEl 75 | 76 | elem.handleMouseEnter = handleMouseEnter 77 | elem.handleMouseLeave = handleMouseLeave 78 | 79 | if (binding.value.autoUpdate) { 80 | const cleanup = autoUpdate(trigger.value, popover.value, () => { 81 | setPopoverPosition() 82 | }) 83 | 84 | elem.cleanup = cleanup || (() => {}) 85 | } 86 | 87 | elem.addEventListener('mouseenter', elem.handleMouseEnter) 88 | elem.addEventListener('mouseleave', elem.handleMouseLeave) 89 | elem.addEventListener('focus', elem.handleMouseEnter) 90 | elem.addEventListener('blur', elem.handleMouseLeave) 91 | }, 92 | updated(elem) {}, 93 | unmounted(elem) { 94 | elem.removeEventListener('mouseenter', elem.handleMouseEnter) 95 | elem.removeEventListener('mouseleave', elem.handleMouseLeave) 96 | elem.removeEventListener('focus', elem.handleMouseEnter) 97 | elem.removeEventListener('blur', elem.handleMouseLeave) 98 | 99 | elem.cleanup && elem.cleanup() 100 | elem.myTooltip.unmount() 101 | elem.mountEl.parentNode.removeChild(elem.mountEl) 102 | }, 103 | }) 104 | -------------------------------------------------------------------------------- /src/helpers/clamp.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable-next-line: variable-name 2 | export const clamp = (number: number, min = 0, max = 1): number => { 3 | return number > max ? max : number < min ? min : number 4 | } 5 | -------------------------------------------------------------------------------- /src/helpers/getChildrenVNodesFromSlot.ts: -------------------------------------------------------------------------------- 1 | import { VNode, Slot } from 'vue' 2 | 3 | export const getChildrenVNodesFromSlot = (slot: Slot): VNode[] => { 4 | return slot().reduce((list: VNode[], child) => { 5 | const resultChildren: VNode[] = child.children?.length 6 | ? (child.children as VNode[]) 7 | : [child] 8 | return [...list, ...resultChildren] 9 | }, []) 10 | } 11 | -------------------------------------------------------------------------------- /src/helpers/getUpperFirstLettersWords.ts: -------------------------------------------------------------------------------- 1 | export const getUpperFirstLettersWords = (text = '', wordCount = 1): string => { 2 | if (!text) return '' 3 | const words = text.split(' ') 4 | return words 5 | .splice(0, wordCount) 6 | .reduce((str, word) => (str += word[0]), '') 7 | .toUpperCase() 8 | } 9 | -------------------------------------------------------------------------------- /src/helpers/getVariantProps.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CSSClassesList, 3 | CSSRawClassesList, 4 | WithVariantProps, 5 | } from '@/types/variant' 6 | import { PropType } from 'vue' 7 | 8 | export type VariantJSWithClassesListProps = { 9 | classes?: { 10 | type: PropType> 11 | default: undefined 12 | } 13 | base?: { 14 | type: PropType> 15 | default: undefined 16 | } 17 | variants?: { 18 | type: PropType> 19 | default: undefined 20 | } 21 | variant?: { 22 | type: PropType 23 | default?: string 24 | } 25 | } 26 | 27 | declare type ObjectWithClassesList = { 28 | classesList?: CSSClassesList 29 | } 30 | 31 | export declare const parseVariantWithClassesList: < 32 | P extends ObjectWithClassesList, 33 | >() => P 34 | 35 | export const getVariantPropsWithClassesList = < 36 | ClassesKeys extends Record, 37 | >(): VariantJSWithClassesListProps => ({ 38 | classes: { 39 | type: Object as PropType>, 40 | default: undefined, 41 | }, 42 | base: { 43 | type: Object as PropType>, 44 | default: undefined, 45 | }, 46 | variants: { 47 | type: Object as PropType>, 48 | default: undefined, 49 | }, 50 | variant: { 51 | type: [String, Array] as PropType, 52 | default: undefined, 53 | }, 54 | }) 55 | -------------------------------------------------------------------------------- /src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useCheckSlot } from './useCheckSlot' 2 | export { usePopover } from './usePopover' 3 | -------------------------------------------------------------------------------- /src/hooks/tests/useVariant.test.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Equal-UI/Equal/a0df345b0d5eccf880941a5e40cd73b4059f0012/src/hooks/tests/useVariant.test.ts -------------------------------------------------------------------------------- /src/hooks/useCheckSlot.ts: -------------------------------------------------------------------------------- 1 | import { ref, Ref, Slots } from 'vue' 2 | 3 | export const useCheckSlot = (slots: Slots, name: string): Ref | null => { 4 | return name in slots ? ref(slots[name]) : null 5 | } 6 | -------------------------------------------------------------------------------- /src/hooks/usePopover.ts: -------------------------------------------------------------------------------- 1 | import { Positions } from '@/models/enums' 2 | import { 3 | computePosition, 4 | offset, 5 | shift, 6 | Placement, 7 | flip, 8 | } from '@floating-ui/dom' 9 | import { computed, nextTick, ref, Ref, watch } from 'vue' 10 | 11 | export const usePopover = (props: any) => { 12 | const show = ref(false) 13 | const placement: Ref = ref( 14 | props.placement || Positions.T, 15 | ) 16 | const disabled = ref(false || props.disabled) 17 | const clickable = ref(false || props.hoverable) 18 | const transition = computed(() => `fade-${placement.value.split('-')[0]}`) 19 | const visionTimer = ref(null) 20 | const permanent = ref(false || props.permanent) 21 | // const autoPosition = ref(props.autoposition) apply shift + flip or not 22 | const elOffset = ref(props.offset || 8) 23 | 24 | // Template Refs 25 | const popover = ref(props.popoverEl ?? null) 26 | const trigger = ref(props.triggerEl ?? null) 27 | 28 | watch(permanent, (value) => { 29 | if (value) { 30 | if (trigger.value) { 31 | setTimeout(() => { 32 | setPopoverPosition() 33 | show.value = true 34 | }, 100) 35 | } 36 | } 37 | }) 38 | 39 | watch(disabled, (value) => { 40 | if (value) { 41 | hidePopover() 42 | } else if (permanent) { 43 | showPopover() 44 | } 45 | }) 46 | 47 | function handleMouseEnter(e: Event) { 48 | if (disabled.value) { 49 | return 50 | } 51 | 52 | if ( 53 | (e.target as HTMLElement).isSameNode(popover.value as HTMLElement) && 54 | !clickable.value 55 | ) { 56 | return 57 | } 58 | 59 | showPopover() 60 | clearTimeout(visionTimer.value!) 61 | } 62 | 63 | function handleMouseLeave() { 64 | if (!permanent.value) { 65 | visionTimer.value = setTimeout(() => { 66 | hidePopover() 67 | }, 150) 68 | } 69 | } 70 | 71 | function hidePopover() { 72 | show.value = false 73 | } 74 | 75 | function showPopover() { 76 | if (!show.value && !disabled.value) { 77 | setPopoverPosition() 78 | show.value = true 79 | } 80 | } 81 | 82 | async function setPopoverPosition() { 83 | await nextTick() 84 | const popoverTemp = popover.value as HTMLElement 85 | const triggerTemp = trigger.value as HTMLElement 86 | 87 | if (!popoverTemp || !triggerTemp) { 88 | return 89 | } 90 | 91 | const { 92 | x, 93 | y, 94 | placement: extPlacement, 95 | } = await computePosition(triggerTemp, popoverTemp, { 96 | middleware: [offset(elOffset.value), flip(), shift()], 97 | placement: placement.value as Placement, 98 | }) 99 | 100 | Object.assign(popoverTemp.style, { 101 | position: 'absolute', 102 | left: `${x}px`, 103 | top: `${y}px`, 104 | }) 105 | } 106 | 107 | return { 108 | show, 109 | placement, 110 | disabled, 111 | clickable, 112 | transition, 113 | visionTimer, 114 | popover, 115 | trigger, 116 | permanent, 117 | elOffset, 118 | handleMouseEnter, 119 | handleMouseLeave, 120 | hidePopover, 121 | showPopover, 122 | setPopoverPosition, 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/hooks/useVariants.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CSSClass, 3 | CSSClasses, 4 | CSSClassKeyValuePair, 5 | CSSRawClassesList, 6 | } from './../types/variant' 7 | import { EqualUIConfiguration } from '@/types/variant' 8 | import { inject } from 'vue' 9 | import { Components } from '@/models/enums' 10 | import { VariantJSWithClassesListProps } from '@/helpers/getVariantProps' 11 | import { twMerge } from 'tailwind-merge' 12 | 13 | export const selectClasses = ( 14 | classesObject: CSSClassKeyValuePair, 15 | ): CSSClasses => 16 | Object.keys(classesObject).filter( 17 | (className: string) => !!classesObject[className], 18 | ) 19 | 20 | const mergeClasses = (...classes: CSSClasses): string => 21 | classes 22 | .map((className: CSSClass): string => { 23 | if (typeof className === 'string' || className === undefined) { 24 | return className || '' 25 | } 26 | 27 | if (Array.isArray(className)) { 28 | return mergeClasses(...className) 29 | } 30 | 31 | return mergeClasses(...selectClasses(className)) 32 | }) 33 | .join(' ') 34 | .replace(/ +/g, ' ') 35 | .trim() 36 | 37 | export const useVariants = ( 38 | name: Components, 39 | props: VariantJSWithClassesListProps = {}, 40 | ): { 41 | transitions?: Record> 42 | } & CSSRawClassesList => { 43 | const config = inject( 44 | 'config', 45 | {} as EqualUIConfiguration, 46 | ) 47 | const globalVariant = config && config[name] // FIXME: Not gonna work with nuxt? 48 | 49 | let finalResult: { 50 | transitions?: Record> 51 | } & CSSRawClassesList = {} 52 | 53 | if (globalVariant) { 54 | for (let [key, value] of Object.entries(globalVariant.base || {})) { 55 | // @ts-ignore 56 | const result = props.base?.[key] 57 | ? // @ts-ignore 58 | [props.base[key]] 59 | : [value] 60 | 61 | const variant = props.variant || 'default' 62 | result.push( 63 | Array.isArray(variant) 64 | ? variant.map( 65 | (el) => 66 | // @ts-ignore 67 | props.variants?.[el]?.[key] || 68 | globalVariant?.variants?.[el]?.[key], 69 | ) 70 | : // @ts-ignore 71 | props.variants?.[variant]?.[key] || 72 | // @ts-ignore 73 | globalVariant?.variants?.[variant]?.[key], 74 | ) 75 | 76 | // @ts-ignore 77 | finalResult[key as keyof T] = result.filter((el) => !!el) 78 | } 79 | } 80 | 81 | for (let [key, value] of Object.entries(finalResult)) { 82 | // @ts-ignore 83 | finalResult[key] = twMerge(mergeClasses(value)) 84 | } 85 | 86 | finalResult.transitions = config?.transitions || {} 87 | 88 | return finalResult 89 | } 90 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import Equal from './index' 4 | import lightTheme from './theme/light' 5 | import './index.css' 6 | 7 | const app = createApp(App) 8 | 9 | app.use(Equal, lightTheme) 10 | app.mount('#app') 11 | -------------------------------------------------------------------------------- /src/models/enums/Colors.ts: -------------------------------------------------------------------------------- 1 | export enum Colors { 2 | NEUTRAL = 'neutral', 3 | PRIMARY = 'primary', 4 | SUCCESS = 'success', 5 | DANGER = 'danger', 6 | WARNING = 'warning', 7 | BLACK = 'black', 8 | } 9 | -------------------------------------------------------------------------------- /src/models/enums/Components.ts: -------------------------------------------------------------------------------- 1 | export enum Components { 2 | ITAlert = 'ItAlert', 3 | ITAvatar = 'ItAvatar', 4 | ITAvatarGroup = 'ItAvatarGroup', 5 | ITTag = 'ItTag', 6 | ITCheckbox = 'ItCheckbox', 7 | ITColorpicker = 'ItColorpicker', 8 | ITDivider = 'ItDivider', 9 | ITDropdown = 'ItDropdown', 10 | ITDrawer = 'ItDrawer', 11 | ITBadge = 'ItBadge', 12 | ITButton = 'ItButton', 13 | ITButtonGroup = 'ItButtonGroup', 14 | ITLoadingbar = 'ItLoadingBar', 15 | ITSpinner = 'ItSpinner', 16 | ITSelect = 'ItSelect', 17 | ITSlider = 'ItSlider', 18 | ITSwitch = 'ItSwitch', 19 | ITMessage = 'ItMessage', 20 | ITModal = 'ItModal', 21 | ITNotification = 'ItNotification', 22 | ITCollapse = 'ItCollapse', 23 | ITCollapseItem = 'ItCollapseItem', 24 | ITTabs = 'ItTabs', 25 | ITTextarea = 'ItTextarea', 26 | ITTooltip = 'ItTooltip', 27 | ITToggle = 'ItToggle', 28 | ITRadio = 'ItRadio', 29 | ITProgressbar = 'ItProgressbar', 30 | ITInput = 'ItInput', 31 | ITNumberInput = 'ItNumberInput', 32 | ITPopover = 'ItPopover', 33 | } 34 | -------------------------------------------------------------------------------- /src/models/enums/Directions.ts: -------------------------------------------------------------------------------- 1 | export enum EDirections { 2 | UP = 'up', 3 | DOWN = 'down', 4 | } 5 | -------------------------------------------------------------------------------- /src/models/enums/Positions.ts: -------------------------------------------------------------------------------- 1 | export enum Positions { 2 | B = 'bottom', 3 | BL = 'bottom-left', 4 | BR = 'bottom-right', 5 | L = 'left', 6 | LT = 'left-top', 7 | LB = 'left-bottom', 8 | R = 'right', 9 | RT = 'right-top', 10 | RB = 'right-bottom', 11 | T = 'top', 12 | TL = 'top-left', 13 | TR = 'top-right', 14 | } 15 | -------------------------------------------------------------------------------- /src/models/enums/Sizes.ts: -------------------------------------------------------------------------------- 1 | export enum Sizes { 2 | BIG = 'big', 3 | NORMAL = 'normal', 4 | SMALL = 'small', 5 | } 6 | -------------------------------------------------------------------------------- /src/models/enums/index.ts: -------------------------------------------------------------------------------- 1 | export { Colors } from './Colors' 2 | export { Positions } from './Positions' 3 | export { Sizes } from './Sizes' 4 | export { EDirections } from './Directions' 5 | export { Components } from './Components' 6 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { defineComponent } from 'vue' 3 | const Component: ReturnType 4 | export default Component 5 | } 6 | -------------------------------------------------------------------------------- /src/types/global.ts: -------------------------------------------------------------------------------- 1 | import { Ref } from 'vue' 2 | export type TEmit = (event: string, ...args: unknown[]) => void 3 | export type TProps = { [key: string]: any } 4 | 5 | export interface IEqual { 6 | drawers: Ref[] 7 | modals: Ref[] 8 | } 9 | -------------------------------------------------------------------------------- /src/types/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'equal-vue' 2 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | export { TEmit, TProps } from './global' 2 | -------------------------------------------------------------------------------- /src/types/variant.ts: -------------------------------------------------------------------------------- 1 | import { Components } from '@/models/enums' 2 | import { 3 | ITTagVariants, 4 | ITAvatarVariants, 5 | ITAlertVariants, 6 | ITDividerVariants, 7 | ITBadgeVariants, 8 | ITButtonVariants, 9 | ITSpinnerVariants, 10 | ITCollapseVariants, 11 | ITCollapseItemVariants, 12 | ITTextareaVariants, 13 | ITRadioVariants, 14 | ITButtonGroupVariants, 15 | ITAvatarGroupVariants, 16 | ITDrawerVariants, 17 | ITInputVariants, 18 | ITNumberInputVariants, 19 | ITSliderVariants, 20 | ITSwitchVariants, 21 | ITToggleVariants, 22 | ITTabsVariants, 23 | ITLoadingbarVariants, 24 | ITColorpickerVariants, 25 | ITTooltipVariants, 26 | ITProgressBarVariants, 27 | ITSelectVariants, 28 | ITModalVariants, 29 | ITMessageVariants, 30 | } from './components/components' 31 | 32 | export declare type CSSClassKeyValuePair = { 33 | [key: string]: any 34 | } 35 | export declare type CSSClasses = CSSClass[] 36 | export declare type CSSClass = 37 | | CSSClassKeyValuePair 38 | | string 39 | | CSSClasses 40 | | undefined 41 | 42 | export declare type CSSClassesList = { 43 | [key in ClassesKeys]?: CSSClass 44 | } 45 | 46 | export declare type CSSRawClassesList = { 47 | [T in keyof ClassesKeys]?: CSSClass 48 | } 49 | 50 | export type WithVariantProps

= { 51 | base?: CSSRawClassesList

52 | variants?: Variants

53 | } & P 54 | 55 | export interface Variants

{ 56 | [key: string]: CSSRawClassesList

| undefined 57 | } 58 | 59 | export interface EqualUIConfiguration { 60 | transitions: Record> 61 | [Components.ITAlert]?: ITAlertVariants 62 | [Components.ITAvatar]?: ITAvatarVariants 63 | [Components.ITAvatarGroup]?: ITAvatarGroupVariants 64 | [Components.ITTabs]?: ITTabsVariants 65 | [Components.ITTag]?: ITTagVariants 66 | [Components.ITCollapse]?: ITCollapseVariants 67 | [Components.ITCollapseItem]?: ITCollapseItemVariants 68 | [Components.ITColorpicker]?: ITColorpickerVariants 69 | [Components.ITLoadingbar]?: ITLoadingbarVariants 70 | [Components.ITProgressbar]?: ITProgressBarVariants 71 | [Components.ITTooltip]?: ITTooltipVariants 72 | [Components.ITCheckbox]?: ITTagVariants 73 | [Components.ITCheckbox]?: ITTagVariants 74 | [Components.ITDivider]?: ITDividerVariants 75 | [Components.ITDrawer]?: ITDrawerVariants 76 | [Components.ITBadge]?: ITBadgeVariants 77 | [Components.ITButton]?: ITButtonVariants 78 | [Components.ITButtonGroup]?: ITButtonGroupVariants 79 | [Components.ITSpinner]?: ITSpinnerVariants 80 | [Components.ITSlider]?: ITSliderVariants 81 | [Components.ITModal]?: ITModalVariants 82 | [Components.ITMessage]?: ITMessageVariants 83 | [Components.ITSwitch]?: ITSwitchVariants 84 | [Components.ITTextarea]?: ITTextareaVariants 85 | [Components.ITToggle]?: ITToggleVariants 86 | [Components.ITRadio]?: ITRadioVariants 87 | [Components.ITSelect]?: ITSelectVariants 88 | [Components.ITInput]?: ITInputVariants 89 | [Components.ITNumberInput]?: ITNumberInputVariants 90 | } 91 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: 'jit', 3 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 4 | theme: { 5 | fontFamily: { 6 | 'sans': ['inter', 'system-ui'], 7 | }, 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | darkMode: 'class' 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "ts-node": { 3 | // these options are overrides used only by ts-node 4 | "compilerOptions": { 5 | "module": "commonjs" 6 | } 7 | }, 8 | "compilerOptions": { 9 | "target": "es2018", 10 | "module": "esnext", 11 | "strict": true, 12 | "declaration": true, 13 | "jsx": "preserve", 14 | "importHelpers": true, 15 | "moduleResolution": "node", 16 | "experimentalDecorators": true, 17 | "isolatedModules": true, 18 | "esModuleInterop": true, 19 | "allowSyntheticDefaultImports": true, 20 | "sourceMap": true, 21 | "baseUrl": ".", 22 | "paths": { 23 | "@/*": ["src/*"] 24 | }, 25 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 26 | }, 27 | "include": ["src/**/*.ts", "src/**/*.vue"], 28 | "exclude": ["node_modules", "dist", "**/*.js"] 29 | } 30 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import type { UserConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import dts from 'vite-plugin-dts' 4 | const path = require('path') 5 | 6 | const config: UserConfig = { 7 | resolve: { 8 | alias: [ 9 | { 10 | find: '@', 11 | replacement: path.resolve(__dirname, 'src'), 12 | }, 13 | ], 14 | }, 15 | plugins: [ 16 | vue(), 17 | dts({ 18 | insertTypesEntry: true, 19 | }), 20 | ], 21 | build: { 22 | lib: { 23 | entry: path.resolve(__dirname, 'src/index.ts'), 24 | name: 'Equal', 25 | }, 26 | rollupOptions: { 27 | // make sure to externalize deps that shouldn't be bundled 28 | // into your library 29 | external: ['vue'], 30 | output: { 31 | // Provide global variables to use in the UMD build 32 | // for externalized deps 33 | globals: { 34 | vue: 'Vue', 35 | }, 36 | }, 37 | }, 38 | }, 39 | server: { 40 | port: 3000, 41 | }, 42 | } 43 | 44 | export default config 45 | --------------------------------------------------------------------------------