├── .gitignore
├── .storybook
├── addons.js
├── config.js
├── manager-head.html
├── preview-head.html
└── webpack.config.js
├── .tx
└── config
├── LICENSE.md
├── README.md
├── babel.config.js
├── package.json
├── src
├── components
│ ├── Account.vue
│ ├── AccountDetails.vue
│ ├── AccountList.vue
│ ├── AccountRing.vue
│ ├── AccountSelector.vue
│ ├── AddressDisplay.vue
│ ├── AddressInput.vue
│ ├── Amount.vue
│ ├── AmountInput.vue
│ ├── AmountWithFee.vue
│ ├── BottomOverlay.vue
│ ├── Carousel.vue
│ ├── CircleSpinner.vue
│ ├── CloseButton.vue
│ ├── Copyable.vue
│ ├── CopyableField.vue
│ ├── FiatAmount.vue
│ ├── Icons.ts
│ ├── Identicon.vue
│ ├── LabelInput.vue
│ ├── LanguageSelector.vue
│ ├── LoadingSpinner.vue
│ ├── LongPressButton.vue
│ ├── PageBody.vue
│ ├── PageFooter.vue
│ ├── PageHeader.vue
│ ├── PaymentInfoLine.vue
│ ├── QrCode.vue
│ ├── QrScanner.vue
│ ├── SelectBar.vue
│ ├── SliderToggle.vue
│ ├── SmallPage.vue
│ ├── Timer.vue
│ ├── Tooltip.vue
│ └── Wallet.vue
├── i18n
│ ├── I18n.vue
│ ├── I18nMixin.ts
│ ├── de.po
│ ├── en.po
│ ├── es.po
│ ├── fr.po
│ ├── nl.po
│ ├── pt.po
│ ├── ru.po
│ ├── uk.po
│ └── zh.po
├── main.ts
└── stories
│ └── index.stories.js
├── tsconfig.json
├── tslint.json
├── types
├── index.d.ts
└── svg.d.ts
├── vue.config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist
4 | dist-storybook
5 |
6 | # generated json language files
7 | src/i18n/**/*.json
8 |
9 | # local env files
10 | .env.local
11 | .env.*.local
12 |
13 | # Log files
14 | npm-debug.log*
15 | yarn-debug.log*
16 | yarn-error.log*
17 |
18 | # Editor directories and files
19 | .idea
20 | .vscode
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw*
26 | *.iml
27 |
--------------------------------------------------------------------------------
/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | import '@storybook/addon-knobs/register';
2 | import "@storybook/addon-actions/register";
3 | import "@storybook/addon-links/register";
4 | import '@storybook/addon-viewport/register';
5 |
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from "@storybook/vue";
2 |
3 | const req = require.context("../src/stories", true, /.stories.(js|ts)$/);
4 |
5 | function loadStories() {
6 | req.keys().forEach(filename => req(filename));
7 | }
8 |
9 | configure(loadStories, module);
10 |
--------------------------------------------------------------------------------
/.storybook/manager-head.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nimiq/vue-components/e64b89ba0b4377c56510aad6744808352b4fa747/.storybook/manager-head.html
--------------------------------------------------------------------------------
/.storybook/preview-head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/.storybook/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // Fix build for Node version with OpenSSL 3
4 | const crypto = require('crypto');
5 | const origCreateHash = crypto.createHash;
6 | crypto.createHash = (alg, opts) => {
7 | return origCreateHash(alg === 'md4' ? 'md5' : alg, opts);
8 | };
9 |
10 | // Process source files and specified dependencies by babel to be able to use more modern js syntax than supported by
11 | // our Webpack version. Should be kept in sync with transpileDependencies in vue.config.js
12 | const transpileDependencies = ['@nimiq/utils'];
13 | const babel = {
14 | loader: require.resolve('babel-loader'),
15 | // By default, options from babel.config.js are used. If you're encountering issues with some syntax not being
16 | // transpiled sufficiently, experiment with different @vue/babel-preset-app or @babel/preset-env options. As this is
17 | // only for a demo page, the resulting file size by code being transpiled too aggressively or too many polyfills
18 | // being included, doesn't really matter.
19 | // options: {
20 | // presets: [
21 | // ['@babel/preset-env', {
22 | // targets: { node: 14 },
23 | // // useBuiltIns: 'usage',
24 | // // corejs: '3.37',
25 | // // include: ["@babel/plugin-transform-logical-assignment-operators"],
26 | // debug: true,
27 | // }]
28 | // ],
29 | // },
30 | };
31 |
32 | module.exports = (storybookBaseConfig, env, config) => {
33 | // Save and remove default SVG rule to add a custom one below
34 | const svgRule = config.module.rules.find(rule => rule.test.toString().includes('svg'));
35 | config.module.rules = config.module.rules.filter(rule => !rule.test.toString().includes('svg'));
36 |
37 | return {
38 | ...config,
39 | plugins: [...config.plugins, new (require('vue-loader/lib/plugin'))()],
40 | module: {
41 | ...config.module,
42 | rules: [...config.module.rules, {
43 | test: /\.tsx?$/,
44 | use: [babel, {
45 | loader: require.resolve('ts-loader'),
46 | options: {
47 | appendTsSuffixTo: [/\.vue$/],
48 | transpileOnly: true
49 | }
50 | }]
51 | }, {
52 | test: svgRule.test,
53 | oneOf: [{
54 | // Add new icon SVG rule
55 | test: /icons/,
56 | loader: 'vue-svg-loader',
57 | options: { svgo: false }
58 | }, {
59 | // Re-add default SVG rule
60 | loader: svgRule.loader,
61 | options: svgRule.options
62 | }],
63 | }, {
64 | test: /\.(?:js|mjs|cjs)$/,
65 | include: [
66 | 'src', // Process js files in src, basically index.stories.js
67 | ...transpileDependencies.map((dependency) => path.join('node_modules', dependency)),
68 | ].map((dependency) => path.join(__dirname, '..', dependency)),
69 | ...babel,
70 | }]
71 | },
72 | resolve: {
73 | ...config.resolve,
74 | extensions: [...config.resolve.extensions, '.ts', '.tsx']
75 | }
76 | };
77 | };
78 |
--------------------------------------------------------------------------------
/.tx/config:
--------------------------------------------------------------------------------
1 | [main]
2 | host = https://www.transifex.com
3 |
4 | [o:nimiq-foundation:p:nimiq-vue-components:r:en-po]
5 | file_filter = src/i18n/.po
6 | source_file = src/i18n/en.po
7 | source_lang = en
8 | type = PO
9 | minimum_perc = 95
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nimiq vue-components
2 |
3 | This component library provides components written for the [Vue frontend framework](https://vuejs.org/) for use in Nimiq
4 | Ecosystem apps. Have a look at the [demo page](https://nimiq.github.io/vue-components/) for an overview of included
5 | components.
6 |
7 | ## Installation
8 |
9 | ```bash
10 | yarn add github:nimiq/vue-components#build/master
11 | ```
12 |
13 | This will install the complete component collection. To install only a subset for reduced bundle size, see section
14 | [Advanced setup](#advanced-setup).
15 |
16 | Some components require additional lazy-loaded assets which have to be copied over to your project. Specifically, these
17 | are translation files (if you want to support other languages than English), the Identicon svg asset and the QR scanner
18 | worker.
19 |
20 | If your project has been created with the
21 | [vue-cli](https://cli.vuejs.org/) / gets bundled via [webpack](https://webpack.js.org/), this can be conveniently done
22 | with the [CopyWebpackPlugin](https://webpack.js.org/plugins/copy-webpack-plugin/):
23 |
24 | ```js
25 | const CopyWebpackPlugin = require('copy-webpack-plugin');
26 |
27 | const plugins = [
28 | new CopyWebpackPlugin([
29 | // for translation files and additional, unnamed js chunks (currently only the qr scanner worker)
30 | {
31 | from: 'node_modules/@nimiq/vue-components/dist/NimiqVueComponents.umd.min.+(lang-*|[0-9]).js',
32 | to: './',
33 | flatten: true,
34 | transformPath(path) {
35 | // If you are bundling a non-minified build of the components (for later minification in your build
36 | // process; the default) it tries to also load the the non-minified language files, but we want
37 | // to load the minified files instead, so we rename them.
38 | return path.replace('.min', '');
39 | },
40 | },
41 | // for the identicons
42 | {
43 | from: 'node_modules/@nimiq/vue-components/dist/iqons.min.*.svg',
44 | to: './',
45 | flatten: true,
46 | },
47 | ]),
48 | ...
49 | ];
50 |
51 | // webpack.config.js:
52 | module.exports = {
53 | plugins,
54 | ...
55 | };
56 |
57 | // Or for projects created via vue-cli:
58 | module.exports = {
59 | configureWebpack: {
60 | plugins,
61 | },
62 | ...
63 | };
64 | ```
65 |
66 | By default, these assets are resolved relatively to the importing script's location (the importing script's
67 | currentScript src) as base path. Alternatively, you can also specify a custom path:
68 |
69 | ```js
70 | import { setAssetPublicPath } from '@nimiq/vue-components';
71 |
72 | setAssetPublicPath('/my-path/');
73 |
74 | // Useful for projects setup via vue-cli to apply the app's public path to the vue-component assets
75 | setAssetPublicPath(process.env.BASE_URL);
76 |
77 | // You can also specify a separate folder for image assets
78 | setAssetPublicPath('/js', '/img');
79 | ```
80 |
81 | ## Updating
82 |
83 | ```bash
84 | yarn upgrade @nimiq/vue-components
85 | ```
86 |
87 | ## Usage
88 |
89 | Import the components you want to use in your Vue component and define them as child `components`, for example:
90 |
91 | ```js
92 | import { LoadingSpinner } from '@nimiq/vue-components';
93 |
94 | Vue.component('my-component', {
95 | components: { LoadingSpinner },
96 | template: `
97 |
98 | Loading stuff...
99 |
100 |
101 | `,
102 | });
103 | ```
104 |
105 | ## Advanced Setup
106 |
107 | As this component library is built with webpack which does unfortunately currently not support outputting a
108 | tree-shakeable es6 module yet, we currently do not provide a package that supports tree-shaking and
109 | dead-code-elimination. To fix this, we will either wait for
110 | [es6 module output support to be added to webpack](https://github.com/webpack/webpack/issues/2933), switch to
111 | [building with rollup](https://github.com/nimiq/vue-components/issues/8) or release each component as separate package.
112 |
113 | Until then, you have two options for including only a subset of the components in your code to reduce your bundle size:
114 |
115 | 1. Import the unprocessed `.vue` single file components directly, for example `import LoadingSpinner from
116 | '@nimiq/vue-components/src/components/LoadingSpinner.vue'`. Note that for this to work, you need a bundler and build
117 | process that can handle `.vue` single file components and typescript. Also note that for some components additional
118 | setup might be required, for example for icon components imported from
119 | [Icons.ts](https://github.com/nimiq/vue-components/blob/master/src/components/Icons.ts) (see
120 | [vue.config.js](https://github.com/nimiq/vue-components/blob/master/vue.config.js)).
121 |
122 | 2. Create a custom build of the vue-components that only includes the components you need. To do this, follow these
123 | steps:
124 | 1. Fork this repository and `git clone` the fork to your computer.
125 | 2. Comment-out all components and icons in
126 | [main.ts](https://github.com/nimiq/vue-components/blob/master/src/main.ts) and
127 | [Icons.ts](https://github.com/nimiq/vue-components/blob/master/src/components/Icons.ts) that you do not need.
128 | 3. Build the source code via `yarn && yarn build`.
129 | 4. Remove `dist` from [.gitignore](https://github.com/nimiq/vue-components/blob/master/.gitignore), then `git add
130 | dist .gitignore` to add the build output to your repository.
131 | 5. Create a `git commit` and `git push` it to your fork respository.
132 | 6. In your project, include the vue components from your fork, i.e. `yarn add github:/vue-components`
134 |
135 | ## Development and testing
136 |
137 | To install dependencies run:
138 | ```bash
139 | yarn
140 | ```
141 |
142 | To run the demo page locally with hot-reloading on changes to the code base:
143 | ```bash
144 | yarn storybook
145 | ```
146 |
147 | To check for linting errors:
148 | ```bash
149 | yarn lint
150 | ```
151 |
152 | To build the component library:
153 | ```bash
154 | yarn build
155 | ```
156 |
157 | ## Internationalization
158 |
159 | First of all, a big thank you to all translators!
160 |
161 | The Nimiq Vue-components are fully internationalized and ready for the community to add translations in different languages.
162 |
163 | To help translate Vue-components, the procedure is as follows:
164 | - Clone this repository.
165 |
166 | - The translations are located in the `src/i18n` folder. A translation file for a language is named as the language's
167 | two letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) plus file extension `.po`. For
168 | example, for French with two letter code `fr` the translations are located at `src/i18n/fr.po`. If that file doesn't
169 | exist yet, i.e. you're starting a new translation, please duplicate `en.po` as starting point, rename it
170 | accordingly and then add the language to the `SUPPORTED_LANGUAGES` in `I18nMixin.ts`.
171 |
172 | - In the language files, the source strings to be translated are between double quotes after the word `msgid`.
173 | For Example:
174 | ```
175 | msgid "Account Created"
176 | ```
177 | The translations of these must be provided in the same way, following the word `msgstr`. For Example:
178 | ```
179 | msgid "Account Created"
180 | msgstr "Compte Créé"
181 | ```
182 | Please only edit the translations, not the source strings.
183 |
184 | - Please also don't change the `.json` language files as these are auto-generated. Only edit the `.po` language files.
185 |
186 | - You can test your translations locally by running the demo page as described in section
187 | [Development and testing](#development-and-testing) and then setting a language cookie in the served page. To do so,
188 | open your browser's developer console (ctrl + shift + c) and input `document.cookie = 'lang='` where ``
189 | should be replaced by the two letter language code of the language you want to test, for example `document.cookie =
190 | 'lang=fr'`. After reloading the page, the components should be displayed in your chosen language. Note that the demos
191 | themselves are not translated, only the components. If you struggle setting up the local demo you can ask us to setup
192 | an online demo for you after opening a pull request.
193 |
194 | - Once the file has been fully translated or you are done updating an existing language file, you can open a pull
195 | request here in github.
196 |
197 | - The pull request will then be reviewed and, if all goes well, merged into the master branch and published asap.
198 |
199 | #### Additional information
200 |
201 | - Multiline translations are possible by inserting line breaks as `\n`. For example:
202 | ```
203 | msgid ""
204 | "Imagine if paying with\n"
205 | "crypto was easy"
206 | msgstr ""
207 | "Imaginez si payer avec\n"
208 | "de la crypto était facile."
209 | ```
210 | Please only insert line breaks into translations for source strings which already include a line break. Otherwise,
211 | they might break the layout of the component or not work as intended.
212 |
213 | - Words between curly brackets are variables which must not be translated nor edited. They will be replaced by a value
214 | during app runtime. The name of the variable should be obvious enough for you to understand what it will be replaced
215 | by so you can place it at the right position in the translated string. For example:
216 | ```
217 | msgid "Cancel {payment}"
218 | msgstr "Annuler {payment}"
219 | ```
220 |
221 | - If you're a transifex collaborator, and need some information about how to get started, here are two links for you:
222 | - How to get started as a translator: https://docs.transifex.com/getting-started-1/translators
223 | - How translate using the web editor: https://docs.transifex.com/translation/translating-with-the-web-editor
224 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nimiq/vue-components",
3 | "version": "0.1.0",
4 | "author": "Nimiq",
5 | "scripts": {
6 | "build": "yarn i18n:extract && yarn i18n:lib && vue-cli-service build --target lib --name NimiqVueComponents src/main.ts",
7 | "lint": "vue-cli-service lint",
8 | "storybook": "yarn i18n:extract && yarn i18n:lib && start-storybook -p 6006 -c .storybook -s .",
9 | "build-storybook": "build-storybook -c .storybook -o dist-storybook",
10 | "update-browserslist": "yarn update-browserslist-db",
11 | "i18n:extract": "node ./node_modules/webpack-i18n-tools/index.js ./src/i18n/en.po",
12 | "i18n:pull": "tx pull --force --all",
13 | "i18n:push": "tx push --source",
14 | "i18n:lib": "rimraf src/i18n/?? ; node node_modules/webpack-i18n-tools/tools/convertToJsonLib.js 'src/i18n/!(en).po'",
15 | "i18n:sync": "yarn i18n:extract && yarn i18n:push && yarn i18n:pull && yarn i18n:lib"
16 | },
17 | "main": "dist/NimiqVueComponents.common.js",
18 | "module": "dist/NimiqVueComponents.umd.js",
19 | "files": [
20 | "dist/**/*",
21 | "types/**/*"
22 | ],
23 | "dependencies": {
24 | "@nimiq/iqons": "^1.6.0",
25 | "@nimiq/style": "^0.8.5",
26 | "@nimiq/utils": "^0.11.1",
27 | "big-integer": "^1.6.44",
28 | "input-format": "^0.2.8",
29 | "js-sha3": "^0.8.0",
30 | "qr-creator": "^1.0.0",
31 | "qr-scanner": "^1.4.2",
32 | "vue": "^2.6.11",
33 | "vue-property-decorator": "^8.4.0"
34 | },
35 | "devDependencies": {
36 | "@storybook/addon-actions": "^4.0.0-alpha.14",
37 | "@storybook/addon-knobs": "^4.0.0-alpha.14",
38 | "@storybook/addon-links": "^4.0.0-alpha.14",
39 | "@storybook/addon-viewport": "^4.0.0-alpha.14",
40 | "@storybook/vue": "^4.0.0-alpha.14",
41 | "@vue/cli-plugin-babel": "~4.5.19",
42 | "@vue/cli-plugin-typescript": "~4.5.19",
43 | "@vue/cli-service": "~4.5.19",
44 | "@vue/compiler-dom": "^3.2.45",
45 | "core-js": "^3.37.1",
46 | "file-loader": "^3.0.1",
47 | "moment": "^2.29.4",
48 | "rimraf": "^3.0.2",
49 | "typescript": "~3.7.5",
50 | "vue-cli-plugin-ts-bundler": "^0.0.3",
51 | "vue-svg-loader": "^0.12.0",
52 | "vue-template-compiler": "^2.6.11",
53 | "webpack-i18n-tools": "https://github.com/nimiq/webpack-i18n-tools#master"
54 | },
55 | "eslintConfig": {
56 | "root": true,
57 | "env": {
58 | "node": true
59 | },
60 | "extends": [
61 | "plugin:vue/essential",
62 | "eslint:recommended"
63 | ],
64 | "rules": {},
65 | "parserOptions": {
66 | "parser": "babel-eslint"
67 | }
68 | },
69 | "postcss": {
70 | "plugins": {
71 | "autoprefixer": {}
72 | }
73 | },
74 | "browserslist": [
75 | "> 1%",
76 | "last 2 versions",
77 | "not ie <= 10"
78 | ],
79 | "license": "Apache-2.0",
80 | "types": "types/index.d.ts",
81 | "packageManager": "yarn@1.22.19"
82 | }
83 |
--------------------------------------------------------------------------------
/src/components/Account.vue:
--------------------------------------------------------------------------------
1 |
2 |