mirror of
https://github.com/SomboChea/ui
synced 2026-01-18 09:06:14 +07:00
Compare commits
13 Commits
feat-dark-
...
v1.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
feae7c8300 | ||
|
|
cdad5cf70d | ||
|
|
91434cc814 | ||
|
|
4071e272af | ||
|
|
f81c1984da | ||
|
|
b2255fca88 | ||
|
|
8c2800e156 | ||
|
|
a5f06cb3af | ||
|
|
e27d59bff7 | ||
|
|
0abe1ef41c | ||
|
|
7428384b55 | ||
|
|
8d4b3cee7e | ||
|
|
d41ba981d2 |
@@ -37,4 +37,4 @@
|
|||||||
],
|
],
|
||||||
"results": {},
|
"results": {},
|
||||||
"version": "0.12.4"
|
"version": "0.12.4"
|
||||||
}
|
}
|
||||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -2,6 +2,24 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.1.0](https://github.com/verdaccio/ui/compare/v1.0.4...v1.1.0) (2020-04-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **style:** added dark mode ([#446](https://github.com/verdaccio/ui/issues/446)) ([cdad5cf](https://github.com/verdaccio/ui/commit/cdad5cf70d69b7bb045fce461a32108def81721d))
|
||||||
|
|
||||||
|
### [1.0.4](https://github.com/verdaccio/ui/compare/v1.0.0...v1.0.4) (2020-03-17)
|
||||||
|
|
||||||
|
## [1.0.0](https://github.com/verdaccio/ui/compare/v0.3.13...v1.0.0) (2020-03-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **de-translations:** added de-DE translations to the UI ([#441](https://github.com/verdaccio/ui/issues/441)) ([e27d59b](https://github.com/verdaccio/ui/commit/e27d59bff7039473e566090fa0f825f7e462aa4e))
|
||||||
|
* spanish translations to UI ([#440](https://github.com/verdaccio/ui/issues/440)) ([0abe1ef](https://github.com/verdaccio/ui/commit/0abe1ef41ca93b900ddda72e2d873ee52078221c))
|
||||||
|
* **i18n:** added i18next for user interface translations ([#432](https://github.com/verdaccio/ui/issues/432)) ([7428384](https://github.com/verdaccio/ui/commit/7428384b55e6089dbe45e6b216eee0b670dff576))
|
||||||
|
|
||||||
### [0.3.13](https://github.com/verdaccio/ui/compare/v0.3.12...v0.3.13) (2020-02-02)
|
### [0.3.13](https://github.com/verdaccio/ui/compare/v0.3.12...v0.3.13) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ If you have any issue you can try the following options, do no desist to ask or
|
|||||||
|
|
||||||
* [Blog](https://medium.com/verdaccio)
|
* [Blog](https://medium.com/verdaccio)
|
||||||
* [Donations](https://opencollective.com/verdaccio)
|
* [Donations](https://opencollective.com/verdaccio)
|
||||||
* [Roadmaps](https://github.com/verdaccio/verdaccio/projects)
|
* [Roadmaps](https://github.com/verdaccio/ui/projects)
|
||||||
* [Reporting an issue](https://github.com/verdaccio/verdaccio/blob/master/CONTRIBUTING.md#reporting-a-bug)
|
* [Reporting an issue](https://github.com/verdaccio/verdaccio/blob/master/CONTRIBUTING.md#reporting-a-bug)
|
||||||
* [Running discussions](https://github.com/verdaccio/verdaccio/issues?q=is%3Aissue+is%3Aopen+label%3Adiscuss)
|
* [Running discussions](https://github.com/verdaccio/verdaccio/issues?q=is%3Aissue+is%3Aopen+label%3Adiscuss)
|
||||||
* [Chat](http://chat.verdaccio.org/)
|
* [Chat](http://chat.verdaccio.org/)
|
||||||
@@ -101,6 +101,10 @@ If you have any issue you can try the following options, do no desist to ask or
|
|||||||
* [FAQ](https://github.com/verdaccio/verdaccio/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Aquestion%20)
|
* [FAQ](https://github.com/verdaccio/verdaccio/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Aquestion%20)
|
||||||
* [Docker Examples](https://github.com/verdaccio/docker-examples)
|
* [Docker Examples](https://github.com/verdaccio/docker-examples)
|
||||||
|
|
||||||
|
### Translations
|
||||||
|
|
||||||
|
Translations are handled locally. I18n files can be found in the folder ```i18n/translations/*``` of this repository. We would love to provide translations from other languages, embracing all our users, but unfortunately we cannot do this without your help. Would you like to help us? Please feel **super welcome** to add a locale by opening a pull request.
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
||||||
Verdaccio is [MIT licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)
|
Verdaccio is [MIT licensed](https://github.com/verdaccio/verdaccio/blob/master/LICENSE)
|
||||||
|
|||||||
40
i18n/config.ts
Normal file
40
i18n/config.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import i18n from 'i18next';
|
||||||
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
|
||||||
|
import translationEN from './translations/en-US.json';
|
||||||
|
import translationPT from './translations/pt-BR.json';
|
||||||
|
import translationES from './translations/es-ES.json';
|
||||||
|
import translationDE from './translations/de-DE.json';
|
||||||
|
|
||||||
|
i18n
|
||||||
|
// pass the i18n instance to react-i18next.
|
||||||
|
.use(initReactI18next)
|
||||||
|
// init i18next
|
||||||
|
// for all options read: https://www.i18next.com/overview/configuration-options
|
||||||
|
.init({
|
||||||
|
// in case window.VEDACCIO_LANGUAGE is undefined,it will fall back to 'en-US'
|
||||||
|
lng: window?.__VERDACCIO_BASENAME_UI_OPTIONS?.language,
|
||||||
|
fallbackLng: 'en-US',
|
||||||
|
whitelist: ['en-US', 'pt-BR', 'es-ES', 'de-DE'],
|
||||||
|
load: 'currentOnly',
|
||||||
|
resources: {
|
||||||
|
'en-US': {
|
||||||
|
translation: translationEN,
|
||||||
|
},
|
||||||
|
'pt-BR': {
|
||||||
|
translation: translationPT,
|
||||||
|
},
|
||||||
|
'es-ES': {
|
||||||
|
translation: translationES,
|
||||||
|
},
|
||||||
|
'de-DE': {
|
||||||
|
translation: translationDE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
debug: false,
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false, // react already safes from xss
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default i18n;
|
||||||
139
i18n/translations/de-DE.json
Normal file
139
i18n/translations/de-DE.json
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
{
|
||||||
|
"copy-to-clipboard": "In die Zwischenablage kopieren",
|
||||||
|
"author-anonymous": "Anonymus",
|
||||||
|
"action-bar-action": {
|
||||||
|
"visit-home-page": "Zur Homepage",
|
||||||
|
"open-an-issue": "Einen Fehler melden",
|
||||||
|
"download-tarball": "Archiv (Tarball) herunterladen"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"registry-info": {
|
||||||
|
"title": "Registrierungsinformationen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"documentation": "Dokumentation",
|
||||||
|
"registry-info": "Registrierungsinformationen",
|
||||||
|
"greetings": "Hallo "
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"packages": "Pakete suchen"
|
||||||
|
},
|
||||||
|
"auto-complete": {
|
||||||
|
"loading": "wird geladen...",
|
||||||
|
"no-results-found": "Kein Ergebnis gefunden"
|
||||||
|
},
|
||||||
|
"tab": {
|
||||||
|
"uplinks": "Uplinks",
|
||||||
|
"versions": "Versionen",
|
||||||
|
"dependencies": "Abhängigkeiten",
|
||||||
|
"readme": "Liesmich"
|
||||||
|
},
|
||||||
|
"uplinks": {
|
||||||
|
"title": "Uplinks",
|
||||||
|
"no-items": "{{name}} hat keine Uplinks."
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"current-tags": "Aktuelle Tags",
|
||||||
|
"version-history": "Versionsgeschichte",
|
||||||
|
"not-available": "Nicht verfĂĽgbar"
|
||||||
|
},
|
||||||
|
"package": {
|
||||||
|
"published-on": "Veröffentlicht am {{time}} •",
|
||||||
|
"version": "v{{version}}",
|
||||||
|
"visit-home-page": "Zur Homepage",
|
||||||
|
"homepage": "Homepage",
|
||||||
|
"open-an-issue": "Einen Fehler melden",
|
||||||
|
"bugs": "Fehler",
|
||||||
|
"download": "{{what}} herunterladen",
|
||||||
|
"the-tar-file": "die tar-Datei",
|
||||||
|
"tarball": "Archiv (Tarball)"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"has-no-dependencies": "{{package}} hat keine Abhängigkeiten",
|
||||||
|
"dependency-block": "{{package}}@{{version}}"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"username": "Benutzername",
|
||||||
|
"password": "Passwort"
|
||||||
|
},
|
||||||
|
"form-placeholder": {
|
||||||
|
"username": "Dein Benutzername",
|
||||||
|
"password": "Dein sicheres Passwort"
|
||||||
|
},
|
||||||
|
"form-validation": {
|
||||||
|
"required-field": "Dieses Feld ist erforderlich",
|
||||||
|
"required-min-length": "Dieses Feld erfordert eine Mindestlänge von {{length}}",
|
||||||
|
"unable-to-sign-in": "Anmeldung nicht möglich",
|
||||||
|
"username-or-password-cant-be-empty": "Benutzername und Passwort dĂĽrfen nicht leer sein!"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "Noch kein Paket publiziert.",
|
||||||
|
"sub-title": "Um dein erstes Paket einfach zu publizieren:",
|
||||||
|
"first-step": "1. Einloggen",
|
||||||
|
"first-step-command-line": "npm adduser --registry {{registryUrl}}",
|
||||||
|
"second-step": "2. Publizieren",
|
||||||
|
"second-step-command-line": "npm publish --registry {{registryUrl}}",
|
||||||
|
"third-step": "3. Diese Seite aktualisieren."
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"detail": {
|
||||||
|
"latest-version": "Letzte v{{version}}",
|
||||||
|
"version": "v{{version}}"
|
||||||
|
},
|
||||||
|
"installation": {
|
||||||
|
"title": "Installierung",
|
||||||
|
"install-using-yarn": "Mit yarn installieren",
|
||||||
|
"install-using-yarn-command": "yarn add {{packageName}}",
|
||||||
|
"install-using-npm": "Mit npm installieren",
|
||||||
|
"install-using-npm-command": "npm install {{packageName}}",
|
||||||
|
"install-using-pnpm": "Mit pnpm installieren",
|
||||||
|
"install-using-pnpm-command": "pnpm install {{packageName}}"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"title": "Repository"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"title": "Autor(in)"
|
||||||
|
},
|
||||||
|
"distribution": {
|
||||||
|
"title": "Neueste Distribution",
|
||||||
|
"license": "Lizenz",
|
||||||
|
"size": "Größe",
|
||||||
|
"file-count": "Anzahl der Dateien"
|
||||||
|
},
|
||||||
|
"maintainers": {
|
||||||
|
"title": "Maintainer"
|
||||||
|
},
|
||||||
|
"contributors": {
|
||||||
|
"title": "Contributor"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"npm-version": "NPM Version",
|
||||||
|
"node-js": "NODE JS"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"powered-by": "UnterstĂĽtzt von",
|
||||||
|
"made-with-love-on": "Gemacht mit <0>♥</0> in"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"close": "SchlieĂźen",
|
||||||
|
"cancel": "Abbrechen",
|
||||||
|
"login": "Einloggen",
|
||||||
|
"logout": "Ausloggen",
|
||||||
|
"go-to-the-home-page": "Zur Homepage",
|
||||||
|
"learn-more": "Mehr erfahren",
|
||||||
|
"fund-this-package": "Dieses Paket <0>finanzieren</0>"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"unspecific": "Etwas ist schief gelaufen.",
|
||||||
|
"404": {
|
||||||
|
"page-not-found": "404 - Seite nicht gefunden",
|
||||||
|
"sorry-we-could-not-find-it": "Entschuldigung, wir konnten es nicht finden..."
|
||||||
|
},
|
||||||
|
"app-context-not-correct-used": "Der App-Kontext wurde nicht korrekt verwendet",
|
||||||
|
"theme-context-not-correct-used": "Der Theme-Kontext wurde nicht korrekt verwendet",
|
||||||
|
"package-meta-is-required-at-detail-context": "packageMeta wird bei DetailContext benötigt"
|
||||||
|
}
|
||||||
|
}
|
||||||
139
i18n/translations/en-US.json
Normal file
139
i18n/translations/en-US.json
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
{
|
||||||
|
"copy-to-clipboard": "Copy to clipboard",
|
||||||
|
"author-anonymous": "Anonymous",
|
||||||
|
"action-bar-action": {
|
||||||
|
"visit-home-page": "Visit homepage",
|
||||||
|
"open-an-issue": "Open an issue",
|
||||||
|
"download-tarball": "Download tarball"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"registry-info": {
|
||||||
|
"title": "Register Info"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"documentation": "Documentation",
|
||||||
|
"registry-info": "Registry Information",
|
||||||
|
"greetings": "Hi "
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"packages": "Search Packages"
|
||||||
|
},
|
||||||
|
"auto-complete": {
|
||||||
|
"loading": "Loading...",
|
||||||
|
"no-results-found": "No results found"
|
||||||
|
},
|
||||||
|
"tab": {
|
||||||
|
"uplinks": "Uplinks",
|
||||||
|
"versions": "Versions",
|
||||||
|
"dependencies": "Dependencies",
|
||||||
|
"readme": "Readme"
|
||||||
|
},
|
||||||
|
"uplinks": {
|
||||||
|
"title": "Uplinks",
|
||||||
|
"no-items": "{{name}} has no uplinks."
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"current-tags": "Current Tags",
|
||||||
|
"version-history": "Version history",
|
||||||
|
"not-available": "Not available"
|
||||||
|
},
|
||||||
|
"package": {
|
||||||
|
"published-on": "Published on {{time}} •",
|
||||||
|
"version": "v{{version}}",
|
||||||
|
"visit-home-page": "Visit homepage",
|
||||||
|
"homepage": "Homepage",
|
||||||
|
"open-an-issue": "Open an issue",
|
||||||
|
"bugs": "Bugs",
|
||||||
|
"download": "Download {{what}}",
|
||||||
|
"the-tar-file": "the tar file",
|
||||||
|
"tarball": "Tarball"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"has-no-dependencies": "{{package}} has no dependencies.",
|
||||||
|
"dependency-block": "{{package}}@{{version}}"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"username": "Username",
|
||||||
|
"password": "Password"
|
||||||
|
},
|
||||||
|
"form-placeholder": {
|
||||||
|
"username": "Your username",
|
||||||
|
"password": "Your strong password"
|
||||||
|
},
|
||||||
|
"form-validation": {
|
||||||
|
"required-field": "This field is required",
|
||||||
|
"required-min-length": "This field required the min length of {{length}}",
|
||||||
|
"unable-to-sign-in": "Unable to sign in",
|
||||||
|
"username-or-password-cant-be-empty": "Username or password can't be empty!"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "No Package Published Yet.",
|
||||||
|
"sub-title": "To publish your first package just:",
|
||||||
|
"first-step": "1. Login",
|
||||||
|
"first-step-command-line": "npm adduser --registry {{registryUrl}}",
|
||||||
|
"second-step": "2. Publish",
|
||||||
|
"second-step-command-line": "npm publish --registry {{registryUrl}}",
|
||||||
|
"third-step": "3. Refresh this page."
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"detail": {
|
||||||
|
"latest-version": "Latest v{{version}}",
|
||||||
|
"version": "v{{version}}"
|
||||||
|
},
|
||||||
|
"installation": {
|
||||||
|
"title": "Installation",
|
||||||
|
"install-using-yarn": "Install using yarn",
|
||||||
|
"install-using-yarn-command": "yarn add {{packageName}}",
|
||||||
|
"install-using-npm": "Install using npm",
|
||||||
|
"install-using-npm-command": "npm install {{packageName}}",
|
||||||
|
"install-using-pnpm": "Install using pnpm",
|
||||||
|
"install-using-pnpm-command": "pnpm install {{packageName}}"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"title": "Repository"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"title": "Author"
|
||||||
|
},
|
||||||
|
"distribution": {
|
||||||
|
"title": "Latest Distribution",
|
||||||
|
"license": "License",
|
||||||
|
"size": "Size",
|
||||||
|
"file-count": "file count"
|
||||||
|
},
|
||||||
|
"maintainers": {
|
||||||
|
"title": "Maintainers"
|
||||||
|
},
|
||||||
|
"contributors": {
|
||||||
|
"title": "Contributors"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"npm-version": "NPM Version",
|
||||||
|
"node-js": "NODE JS"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"powered-by": "Powered by",
|
||||||
|
"made-with-love-on": "Made with <0>♥</0> on"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"close": "Close",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"login": "Login",
|
||||||
|
"logout": "Logout",
|
||||||
|
"go-to-the-home-page": "Go to the home page",
|
||||||
|
"learn-more": "Learn More",
|
||||||
|
"fund-this-package": "<0>Fund</0> this package"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"unspecific": "Something went wrong.",
|
||||||
|
"404": {
|
||||||
|
"page-not-found": "404 - Page not found",
|
||||||
|
"sorry-we-could-not-find-it": "Sorry, we couldn't find it..."
|
||||||
|
},
|
||||||
|
"app-context-not-correct-used": "The app context was not correct used",
|
||||||
|
"theme-context-not-correct-used": "The theme context was not correct used",
|
||||||
|
"package-meta-is-required-at-detail-context": "packageMeta is required at DetailContext"
|
||||||
|
}
|
||||||
|
}
|
||||||
139
i18n/translations/es-ES.json
Normal file
139
i18n/translations/es-ES.json
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
{
|
||||||
|
"copy-to-clipboard": "Copiar al portapapeles",
|
||||||
|
"author-anonymous": "AnĂłnimo",
|
||||||
|
"action-bar-action": {
|
||||||
|
"visit-home-page": "Visitar página principal",
|
||||||
|
"open-an-issue": "Reportar un error",
|
||||||
|
"download-tarball": "Descargar libreria"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"registry-info": {
|
||||||
|
"title": "InformaciĂłn del Registro"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"documentation": "DocumentaciĂłn",
|
||||||
|
"registry-info": "InformaciĂłn del Registro",
|
||||||
|
"greetings": "Hola "
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"packages": "Buscar paquetes"
|
||||||
|
},
|
||||||
|
"auto-complete": {
|
||||||
|
"loading": "Cargando...",
|
||||||
|
"no-results-found": "Sin resultados encontrados"
|
||||||
|
},
|
||||||
|
"tab": {
|
||||||
|
"uplinks": "Remoto",
|
||||||
|
"versions": "Versiones",
|
||||||
|
"dependencies": "Dependencias",
|
||||||
|
"readme": "Léeme"
|
||||||
|
},
|
||||||
|
"uplinks": {
|
||||||
|
"title": "Remoto",
|
||||||
|
"no-items": "{{name}} not tiene remotos."
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"current-tags": "Etiquetas actuales",
|
||||||
|
"version-history": "Historial de versiones",
|
||||||
|
"not-available": "No disponible"
|
||||||
|
},
|
||||||
|
"package": {
|
||||||
|
"published-on": "Publicado en {{time}} •",
|
||||||
|
"version": "v{{version}}",
|
||||||
|
"visit-home-page": "Ir a la página principal",
|
||||||
|
"homepage": "Página pricinpal",
|
||||||
|
"open-an-issue": "Reportar un problema",
|
||||||
|
"bugs": "Errores",
|
||||||
|
"download": "Descargar {{what}}",
|
||||||
|
"the-tar-file": "el archivo tar",
|
||||||
|
"tarball": "Libreria"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"has-no-dependencies": "{{package}} no tiene dependencias.",
|
||||||
|
"dependency-block": "{{package}}@{{version}}"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"username": "Usuario",
|
||||||
|
"password": "Contraseña"
|
||||||
|
},
|
||||||
|
"form-placeholder": {
|
||||||
|
"username": "Tu usuario",
|
||||||
|
"password": "Tu fuerte conntraseña"
|
||||||
|
},
|
||||||
|
"form-validation": {
|
||||||
|
"required-field": "Este campo es requerido",
|
||||||
|
"required-min-length": "Este campo es requerido y la mĂnima longitud es {{length}}",
|
||||||
|
"unable-to-sign-in": "No se ha podido iniciar sesiĂłn",
|
||||||
|
"username-or-password-cant-be-empty": "Nombre de usuario o contraseña no puede estar vacio!"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "NingĂşn paquete ha sido publicado aun.",
|
||||||
|
"sub-title": "Para publicar tu primer paquete:",
|
||||||
|
"first-step": "1. Inicia sesiĂłn",
|
||||||
|
"first-step-command-line": "npm adduser --registry {{registryUrl}}",
|
||||||
|
"second-step": "2. Publica",
|
||||||
|
"second-step-command-line": "npm publish --registry {{registryUrl}}",
|
||||||
|
"third-step": "3. Refresca la página."
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"detail": {
|
||||||
|
"latest-version": "Ăšltima v{{version}}",
|
||||||
|
"version": "v{{version}}"
|
||||||
|
},
|
||||||
|
"installation": {
|
||||||
|
"title": "InstalaciĂłn",
|
||||||
|
"install-using-yarn": "Instala usando yarn",
|
||||||
|
"install-using-yarn-command": "yarn add {{packageName}}",
|
||||||
|
"install-using-npm": "Instala usando npm",
|
||||||
|
"install-using-npm-command": "npm install {{packageName}}",
|
||||||
|
"install-using-pnpm": "Instala usando pnpm",
|
||||||
|
"install-using-pnpm-command": "pnpm install {{packageName}}"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"title": "Repositorio"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"title": "Autor"
|
||||||
|
},
|
||||||
|
"distribution": {
|
||||||
|
"title": "Ăšltima distribuciĂłn",
|
||||||
|
"license": "Licencia",
|
||||||
|
"size": "Tamaño",
|
||||||
|
"file-count": "archivo cuenta"
|
||||||
|
},
|
||||||
|
"maintainers": {
|
||||||
|
"title": "Mantenedores"
|
||||||
|
},
|
||||||
|
"contributors": {
|
||||||
|
"title": "Colaboradores"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"npm-version": "Version NPM",
|
||||||
|
"node-js": "NODE JS"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"powered-by": "Hecho con",
|
||||||
|
"made-with-love-on": "Hecho con <0>♥</0> on"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"close": "Cerrar",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"login": "Iniciar sesiĂłn",
|
||||||
|
"logout": "Cerrar sesiĂłn",
|
||||||
|
"go-to-the-home-page": "Ir a la página principal",
|
||||||
|
"learn-more": "Aprender más",
|
||||||
|
"fund-this-package": "<0>Donar</0> a este paquete"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"unspecific": "Algo ha salido mal.",
|
||||||
|
"404": {
|
||||||
|
"page-not-found": "404 - Paquete no encontrado",
|
||||||
|
"sorry-we-could-not-find-it": "Lo siento, no hemos podido encontrarlo..."
|
||||||
|
},
|
||||||
|
"app-context-not-correct-used": "El contexto de la aplicaciĂłn no fue correctamente usado",
|
||||||
|
"theme-context-not-correct-used": "El contexto del tema no fue correctamente usado",
|
||||||
|
"package-meta-is-required-at-detail-context": "packageMeta es requerido en DetailContext"
|
||||||
|
}
|
||||||
|
}
|
||||||
139
i18n/translations/pt-BR.json
Normal file
139
i18n/translations/pt-BR.json
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
{
|
||||||
|
"copy-to-clipboard": "Copiar para área de transferência",
|
||||||
|
"author-anonymous": "AnĂ´nimo(a)",
|
||||||
|
"action-bar-action": {
|
||||||
|
"visit-home-page": "Visitar a página inicial",
|
||||||
|
"open-an-issue": "Criar um incidente",
|
||||||
|
"download-tarball": "Baixar Tarball"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"registry-info": {
|
||||||
|
"title": "Informações do Registro"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"documentation": "Documentação",
|
||||||
|
"registry-info": "Informações do Registro",
|
||||||
|
"greetings": "Oi "
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"packages": "Pesquisar Pacotes"
|
||||||
|
},
|
||||||
|
"auto-complete": {
|
||||||
|
"loading": "Carregando...",
|
||||||
|
"no-results-found": "Nenhum resultado encontrado"
|
||||||
|
},
|
||||||
|
"tab": {
|
||||||
|
"uplinks": "Uplinks",
|
||||||
|
"versions": "Versões",
|
||||||
|
"dependencies": "DependĂŞncias",
|
||||||
|
"readme": "Leia-me"
|
||||||
|
},
|
||||||
|
"uplinks": {
|
||||||
|
"title": "Uplinks",
|
||||||
|
"no-items": "{{name}} nĂŁo tem uplinks."
|
||||||
|
},
|
||||||
|
"versions": {
|
||||||
|
"current-tags": "Tags atuais",
|
||||||
|
"version-history": "Histórico de versões",
|
||||||
|
"not-available": "NĂŁo disponĂvel"
|
||||||
|
},
|
||||||
|
"package": {
|
||||||
|
"published-on": "Publicado em {{time}} •",
|
||||||
|
"version": "v{{version}}",
|
||||||
|
"visit-home-page": "Visitar a página inicial",
|
||||||
|
"homepage": "Página inicial",
|
||||||
|
"open-an-issue": "Criar um incidente",
|
||||||
|
"bugs": "Erros",
|
||||||
|
"download": "Baixar {{what}}",
|
||||||
|
"the-tar-file": "o arquivo tar",
|
||||||
|
"tarball": "Tarball"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"has-no-dependencies": "{{package}} nĂŁo tem dependĂŞncias.",
|
||||||
|
"dependency-block": "{{package}}@{{version}}"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"username": "Nome do usuário",
|
||||||
|
"password": "Senha"
|
||||||
|
},
|
||||||
|
"form-placeholder": {
|
||||||
|
"username": "O seu nome",
|
||||||
|
"password": "A sua senha forte"
|
||||||
|
},
|
||||||
|
"form-validation": {
|
||||||
|
"required-field": "Este campo Ă© obrigatĂłrio",
|
||||||
|
"required-min-length": "Este campo requer o mĂnimo de {{length}} caracteres",
|
||||||
|
"unable-to-sign-in": "NĂŁo foi possĂvel fazer login",
|
||||||
|
"username-or-password-cant-be-empty": "Nome de usuário ou senha não podem estar vazios!"
|
||||||
|
},
|
||||||
|
"help": {
|
||||||
|
"title": "Nenhum pacote publicado ainda.",
|
||||||
|
"sub-title": "Para publicar seu primeiro pacote apenas:",
|
||||||
|
"first-step": "1. Faça login",
|
||||||
|
"first-step-command-line": "npm adduser --registry {{registryUrl}}",
|
||||||
|
"second-step": "2. Publique",
|
||||||
|
"second-step-command-line": "npm publish --registry {{registryUrl}}",
|
||||||
|
"third-step": "3. Atualize esta página."
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"detail": {
|
||||||
|
"latest-version": "Ăšltima versĂŁo: v{{version}}",
|
||||||
|
"version": "v{{version}}"
|
||||||
|
},
|
||||||
|
"installation": {
|
||||||
|
"title": "Instalação",
|
||||||
|
"install-using-yarn": "Instale usando yarn",
|
||||||
|
"install-using-yarn-command": "yarn add {{packageName}}",
|
||||||
|
"install-using-npm": "Instale usando npm",
|
||||||
|
"install-using-npm-command": "npm install {{packageName}}",
|
||||||
|
"install-using-pnpm": "Instale usando pnpm",
|
||||||
|
"install-using-pnpm-command": "pnpm install {{packageName}}"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"title": "RepositĂłrio"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"title": "Autor(a)"
|
||||||
|
},
|
||||||
|
"distribution": {
|
||||||
|
"title": "Distribuição mais recente",
|
||||||
|
"license": "Licença",
|
||||||
|
"size": "Tamanho",
|
||||||
|
"file-count": "Contagem de arquivos"
|
||||||
|
},
|
||||||
|
"maintainers": {
|
||||||
|
"title": "Mantenedores(as)"
|
||||||
|
},
|
||||||
|
"contributors": {
|
||||||
|
"title": "Contribuidores(as)"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"npm-version": "VersĂŁo NPM",
|
||||||
|
"node-js": "NODE JS"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"powered-by": "DistribuĂdo por",
|
||||||
|
"made-with-love-on": "Feito com amor <0>♥</0> no(a)"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"close": "Fechar",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"login": "Conectar",
|
||||||
|
"logout": "Desconectar",
|
||||||
|
"go-to-the-home-page": "Ir para a página inicial",
|
||||||
|
"learn-more": "Leia mais",
|
||||||
|
"fund-this-package": "<0>Financie</0> este pacote"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"unspecific": "Algo deu errado.",
|
||||||
|
"404": {
|
||||||
|
"page-not-found": "404 - Página não encontrada",
|
||||||
|
"sorry-we-could-not-find-it": "Desculpe, nĂŁo conseguimos encontrar..."
|
||||||
|
},
|
||||||
|
"app-context-not-correct-used": "O contexto do aplicativo nĂŁo foi usado corretamente",
|
||||||
|
"theme-context-not-correct-used": "O contexto do tema nĂŁo foi usado corretamente",
|
||||||
|
"package-meta-is-required-at-detail-context": "packageMeta Ă© requerido em DetailContext"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@verdaccio/ui-theme",
|
"name": "@verdaccio/ui-theme",
|
||||||
"version": "0.3.13",
|
"version": "1.1.0",
|
||||||
"description": "Verdaccio User Interface",
|
"description": "Verdaccio User Interface",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Verdaccio Core Team",
|
"name": "Verdaccio Core Team",
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "7.8.0",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "7.8.0",
|
||||||
"@babel/plugin-proposal-optional-chaining": "7.8.0",
|
"@babel/plugin-proposal-optional-chaining": "7.8.0",
|
||||||
"@commitlint/cli": "8.3.4",
|
"@commitlint/cli": "8.3.5",
|
||||||
"@commitlint/config-conventional": "8.3.4",
|
"@commitlint/config-conventional": "8.3.4",
|
||||||
"@emotion/core": "10.0.22",
|
"@emotion/core": "10.0.22",
|
||||||
"@emotion/styled": "10.0.23",
|
"@emotion/styled": "10.0.23",
|
||||||
@@ -71,6 +71,7 @@
|
|||||||
"github-markdown-css": "3.0.1",
|
"github-markdown-css": "3.0.1",
|
||||||
"html-webpack-plugin": "3.2.0",
|
"html-webpack-plugin": "3.2.0",
|
||||||
"husky": "3.1.0",
|
"husky": "3.1.0",
|
||||||
|
"i18next": "19.1.0",
|
||||||
"identity-obj-proxy": "3.0.0",
|
"identity-obj-proxy": "3.0.0",
|
||||||
"in-publish": "2.0.0",
|
"in-publish": "2.0.0",
|
||||||
"jest": "24.9.0",
|
"jest": "24.9.0",
|
||||||
@@ -96,9 +97,10 @@
|
|||||||
"puppeteer": "2.0.0",
|
"puppeteer": "2.0.0",
|
||||||
"react": "16.12.0",
|
"react": "16.12.0",
|
||||||
"react-autosuggest": "9.4.3",
|
"react-autosuggest": "9.4.3",
|
||||||
"react-dom": "16.12.0",
|
"react-dom": "16.13.0",
|
||||||
"react-hook-form": "3.29.4",
|
"react-hook-form": "3.29.4",
|
||||||
"react-hot-loader": "4.12.18",
|
"react-hot-loader": "4.12.18",
|
||||||
|
"react-i18next": "11.3.1",
|
||||||
"react-router-dom": "5.1.2",
|
"react-router-dom": "5.1.2",
|
||||||
"request": "2.88.0",
|
"request": "2.88.0",
|
||||||
"resolve-url-loader": "3.1.1",
|
"resolve-url-loader": "3.1.1",
|
||||||
@@ -138,7 +140,7 @@
|
|||||||
"bundlesize": [
|
"bundlesize": [
|
||||||
{
|
{
|
||||||
"path": "./static/vendors.*.js",
|
"path": "./static/vendors.*.js",
|
||||||
"maxSize": "185 kB"
|
"maxSize": "200 kB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./static/main.*.js",
|
"path": "./static/main.*.js",
|
||||||
|
|||||||
@@ -4976,8 +4976,12 @@
|
|||||||
"_attachments": {
|
"_attachments": {
|
||||||
"jquery-1.5.1.tgz": {
|
"jquery-1.5.1.tgz": {
|
||||||
"shasum": "2ae2d661e906c1a01e044a71bb5b2743942183e5"
|
"shasum": "2ae2d661e906c1a01e044a71bb5b2743942183e5"
|
||||||
|
},
|
||||||
|
"jquery-3.3.1.tgz": {
|
||||||
|
"shasum": "958ce29e81c9790f31be7792df5d4d95fc57fbca"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"_rev": "60-fed4915c27b9c1e6",
|
"_rev": "61-e6be890a78963127",
|
||||||
"readme": "# jQuery\n\n> jQuery is a fast, small, and feature-rich JavaScript library.\n\nFor information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/).\nFor source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).\n\nIf upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.\n\n## Including jQuery\n\nBelow are some of the most common ways to include jQuery.\n\n### Browser\n\n#### Script tag\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.3.1.min.js\"></script>\n```\n\n#### Babel\n\n[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.\n\n```js\nimport $ from \"jquery\";\n```\n\n#### Browserify/Webpack\n\nThere are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this...\n\n```js\nvar $ = require(\"jquery\");\n```\n\n#### AMD (Asynchronous Module Definition)\n\nAMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html).\n\n```js\ndefine([\"jquery\"], function($) {\n\n});\n```\n\n### Node\n\nTo include jQuery in [Node](nodejs.org), first install with npm.\n\n```sh\nnpm install jquery\n```\n\nFor jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.\n\n```js\nrequire(\"jsdom\").env(\"\", function(err, window) {\n\tif (err) {\n\t\tconsole.error(err);\n\t\treturn;\n\t}\n\n\tvar $ = require(\"jquery\")(window);\n});\n```"
|
"readme": "# jQuery\n\n> jQuery is a fast, small, and feature-rich JavaScript library.\n\nFor information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/).\nFor source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).\n\nIf upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.\n\n## Including jQuery\n\nBelow are some of the most common ways to include jQuery.\n\n### Browser\n\n#### Script tag\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.3.1.min.js\"></script>\n```\n\n#### Babel\n\n[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.\n\n```js\nimport $ from \"jquery\";\n```\n\n#### Browserify/Webpack\n\nThere are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this...\n\n```js\nvar $ = require(\"jquery\");\n```\n\n#### AMD (Asynchronous Module Definition)\n\nAMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html).\n\n```js\ndefine([\"jquery\"], function($) {\n\n});\n```\n\n### Node\n\nTo include jQuery in [Node](nodejs.org), first install with npm.\n\n```sh\nnpm install jquery\n```\n\nFor jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.\n\n```js\nrequire(\"jsdom\").env(\"\", function(err, window) {\n\tif (err) {\n\t\tconsole.error(err);\n\t\treturn;\n\t}\n\n\tvar $ = require(\"jquery\")(window);\n});\n```",
|
||||||
}
|
"_id": "jquery"
|
||||||
|
}
|
||||||
@@ -1,21 +1,25 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
/* eslint-disable react/jsx-max-depth */
|
||||||
|
import React, { useState, useEffect, Suspense } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import isNil from 'lodash/isNil';
|
import isNil from 'lodash/isNil';
|
||||||
import { Router } from 'react-router-dom';
|
import { Router } from 'react-router-dom';
|
||||||
|
|
||||||
|
import '../../i18n/config';
|
||||||
import storage from '../utils/storage';
|
import storage from '../utils/storage';
|
||||||
import { isTokenExpire } from '../utils/login';
|
import { isTokenExpire } from '../utils/login';
|
||||||
import Header from '../components/Header';
|
import Header from '../components/Header';
|
||||||
import Footer from '../components/Footer';
|
import Footer from '../components/Footer';
|
||||||
|
import Loading from '../components/Loading';
|
||||||
import Box from '../muiComponents/Box';
|
import Box from '../muiComponents/Box';
|
||||||
import StyleBaseline from '../design-tokens/StyleBaseline';
|
import StyleBaseline from '../design-tokens/StyleBaseline';
|
||||||
import { Theme } from '../design-tokens/theme';
|
import { Theme } from '../design-tokens/theme';
|
||||||
|
|
||||||
import AppContextProvider from './AppContextProvider';
|
import AppContextProvider from './AppContextProvider';
|
||||||
import AppRoute, { history } from './AppRoute';
|
import AppRoute, { history } from './AppRoute';
|
||||||
|
import loadDayJSLocale from './load-dayjs-locale';
|
||||||
|
|
||||||
const StyledBox = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
const StyledBox = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
backgroundColor: theme && theme.palette.white,
|
backgroundColor: theme?.palette.background.default,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledBoxContent = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
const StyledBoxContent = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
@@ -31,7 +35,6 @@ const StyledBoxContent = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [user, setUser] = useState();
|
const [user, setUser] = useState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logout user
|
* Logout user
|
||||||
* Required by: <Header />
|
* Required by: <Header />
|
||||||
@@ -57,10 +60,11 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkUserAlreadyLoggedIn();
|
checkUserAlreadyLoggedIn();
|
||||||
|
loadDayJSLocale();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Suspense fallback={<Loading />}>
|
||||||
<StyleBaseline />
|
<StyleBaseline />
|
||||||
<StyledBox display="flex" flexDirection="column" height="100%">
|
<StyledBox display="flex" flexDirection="column" height="100%">
|
||||||
<>
|
<>
|
||||||
@@ -68,7 +72,6 @@ const App: React.FC = () => {
|
|||||||
<AppContextProvider user={user}>
|
<AppContextProvider user={user}>
|
||||||
<Header />
|
<Header />
|
||||||
<StyledBoxContent flexGrow={1}>
|
<StyledBoxContent flexGrow={1}>
|
||||||
{/* eslint-disable-next-line react/jsx-max-depth */}
|
|
||||||
<AppRoute />
|
<AppRoute />
|
||||||
</StyledBoxContent>
|
</StyledBoxContent>
|
||||||
</AppContextProvider>
|
</AppContextProvider>
|
||||||
@@ -76,7 +79,7 @@ const App: React.FC = () => {
|
|||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
</StyledBox>
|
</StyledBox>
|
||||||
</>
|
</Suspense>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React, { lazy, useContext, Suspense } from 'react';
|
import React, { lazy, useContext } from 'react';
|
||||||
import { Route as ReactRouterDomRoute, Switch, Router } from 'react-router-dom';
|
import { Route as ReactRouterDomRoute, Switch, Router } from 'react-router-dom';
|
||||||
import { createBrowserHistory } from 'history';
|
import { createBrowserHistory } from 'history';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import Loading from '../components/Loading';
|
|
||||||
|
|
||||||
import AppContext from './AppContext';
|
import AppContext from './AppContext';
|
||||||
|
|
||||||
@@ -25,9 +24,10 @@ export const history = createBrowserHistory({
|
|||||||
|
|
||||||
const AppRoute: React.FC = () => {
|
const AppRoute: React.FC = () => {
|
||||||
const appContext = useContext(AppContext);
|
const appContext = useContext(AppContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!appContext) {
|
if (!appContext) {
|
||||||
throw Error('The app Context was not correct used');
|
throw Error(t('app-context-not-correct-used'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = appContext;
|
const { user } = appContext;
|
||||||
@@ -36,36 +36,34 @@ const AppRoute: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
<Suspense fallback={<Loading />}>
|
<Switch>
|
||||||
<Switch>
|
<ReactRouterDomRoute exact={true} path={Route.ROOT}>
|
||||||
<ReactRouterDomRoute exact={true} path={Route.ROOT}>
|
<HomePage isUserLoggedIn={!!isUserLoggedIn} />
|
||||||
<HomePage isUserLoggedIn={!!isUserLoggedIn} />
|
</ReactRouterDomRoute>
|
||||||
</ReactRouterDomRoute>
|
<ReactRouterDomRoute exact={true} path={Route.PACKAGE}>
|
||||||
<ReactRouterDomRoute exact={true} path={Route.PACKAGE}>
|
<VersionContextProvider>
|
||||||
<VersionContextProvider>
|
<VersionPage />
|
||||||
<VersionPage />
|
</VersionContextProvider>
|
||||||
</VersionContextProvider>
|
</ReactRouterDomRoute>
|
||||||
</ReactRouterDomRoute>
|
<ReactRouterDomRoute exact={true} path={Route.PACKAGE_VERSION}>
|
||||||
<ReactRouterDomRoute exact={true} path={Route.PACKAGE_VERSION}>
|
<VersionContextProvider>
|
||||||
<VersionContextProvider>
|
<VersionPage />
|
||||||
<VersionPage />
|
</VersionContextProvider>
|
||||||
</VersionContextProvider>
|
</ReactRouterDomRoute>
|
||||||
</ReactRouterDomRoute>
|
<ReactRouterDomRoute exact={true} path={Route.SCOPE_PACKAGE_VERSION}>
|
||||||
<ReactRouterDomRoute exact={true} path={Route.SCOPE_PACKAGE_VERSION}>
|
<VersionContextProvider>
|
||||||
<VersionContextProvider>
|
<VersionPage />
|
||||||
<VersionPage />
|
</VersionContextProvider>
|
||||||
</VersionContextProvider>
|
</ReactRouterDomRoute>
|
||||||
</ReactRouterDomRoute>
|
<ReactRouterDomRoute exact={true} path={Route.SCOPE_PACKAGE}>
|
||||||
<ReactRouterDomRoute exact={true} path={Route.SCOPE_PACKAGE}>
|
<VersionContextProvider>
|
||||||
<VersionContextProvider>
|
<VersionPage />
|
||||||
<VersionPage />
|
</VersionContextProvider>
|
||||||
</VersionContextProvider>
|
</ReactRouterDomRoute>
|
||||||
</ReactRouterDomRoute>
|
<ReactRouterDomRoute>
|
||||||
<ReactRouterDomRoute>
|
<NotFound />
|
||||||
<NotFound />
|
</ReactRouterDomRoute>
|
||||||
</ReactRouterDomRoute>
|
</Switch>
|
||||||
</Switch>
|
|
||||||
</Suspense>
|
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -152,53 +152,6 @@ exports[`<App /> should display the Header component 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-34 {
|
|
||||||
-webkit-transform: translate(-50%,-50%);
|
|
||||||
-ms-transform: translate(-50%,-50%);
|
|
||||||
transform: translate(-50%,-50%);
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-28 {
|
|
||||||
margin: 0 0 30px 0;
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 10px 20px 0 rgba(69,58,100,0.2);
|
|
||||||
background: #f7f8f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-26 {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-position: center;
|
|
||||||
background-size: contain;
|
|
||||||
background-image: url([object Object]);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
width: 90px;
|
|
||||||
height: 90px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-32 {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-align-items: center;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-webkit-box-pack: center;
|
|
||||||
-webkit-justify-content: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-30 {
|
|
||||||
color: #4b5e40;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-76 {
|
.emotion-76 {
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
border-top: 1px solid #e3e3e3;
|
border-top: 1px solid #e3e3e3;
|
||||||
@@ -356,6 +309,53 @@ exports[`<App /> should display the Header component 1`] = `
|
|||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emotion-34 {
|
||||||
|
-webkit-transform: translate(-50%,-50%);
|
||||||
|
-ms-transform: translate(-50%,-50%);
|
||||||
|
transform: translate(-50%,-50%);
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emotion-28 {
|
||||||
|
margin: 0 0 30px 0;
|
||||||
|
border-radius: 25px;
|
||||||
|
box-shadow: 0 10px 20px 0 rgba(69,58,100,0.2);
|
||||||
|
background: #f7f8f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emotion-26 {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
background-image: url([object Object]);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emotion-32 {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emotion-30 {
|
||||||
|
color: #4b5e40;
|
||||||
|
}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-219 emotion-78 emotion-79"
|
class="MuiBox-root MuiBox-root-219 emotion-78 emotion-79"
|
||||||
>
|
>
|
||||||
@@ -522,6 +522,30 @@ exports[`<App /> should display the Header component 1`] = `
|
|||||||
class="MuiTouchRipple-root"
|
class="MuiTouchRipple-root"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiIconButton-label"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
focusable="false"
|
||||||
|
role="presentation"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit"
|
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit"
|
||||||
data-testid="header--button-login"
|
data-testid="header--button-login"
|
||||||
@@ -545,6 +569,7 @@ exports[`<App /> should display the Header component 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="container content"
|
class="container content"
|
||||||
|
data-testid="home-page-container"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="emotion-34 emotion-35"
|
class="emotion-34 emotion-35"
|
||||||
@@ -592,13 +617,13 @@ exports[`<App /> should display the Header component 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="emotion-65 emotion-66"
|
class="emotion-65 emotion-66"
|
||||||
>
|
>
|
||||||
Made with
|
Made with
|
||||||
<span
|
<span
|
||||||
class="emotion-38 emotion-39"
|
class="emotion-38 emotion-39"
|
||||||
>
|
>
|
||||||
♥
|
♥
|
||||||
</span>
|
</span>
|
||||||
on
|
on
|
||||||
<span
|
<span
|
||||||
class="emotion-63 emotion-64"
|
class="emotion-63 emotion-64"
|
||||||
>
|
>
|
||||||
@@ -700,7 +725,7 @@ exports[`<App /> should display the Header component 1`] = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<App /> should display the Loading component at the beginning 1`] = `
|
exports[`<App /> should display the Loading component at the beginning 1`] = `
|
||||||
.emotion-78 {
|
.emotion-68 {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -843,7 +868,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width:1240px) {
|
@media screen and (min-width:1240px) {
|
||||||
.emotion-36 {
|
.emotion-26 {
|
||||||
max-width: 1240px;
|
max-width: 1240px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@@ -851,54 +876,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-34 {
|
.emotion-66 {
|
||||||
-webkit-transform: translate(-50%,-50%);
|
|
||||||
-ms-transform: translate(-50%,-50%);
|
|
||||||
transform: translate(-50%,-50%);
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-28 {
|
|
||||||
margin: 0 0 30px 0;
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 10px 20px 0 rgba(69,58,100,0.2);
|
|
||||||
background: #f7f8f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-26 {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-position: center;
|
|
||||||
background-size: contain;
|
|
||||||
background-image: url([object Object]);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
width: 90px;
|
|
||||||
height: 90px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-32 {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-align-items: center;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-webkit-box-pack: center;
|
|
||||||
-webkit-justify-content: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-30 {
|
|
||||||
color: #4b5e40;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emotion-76 {
|
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
border-top: 1px solid #e3e3e3;
|
border-top: 1px solid #e3e3e3;
|
||||||
color: #999999;
|
color: #999999;
|
||||||
@@ -906,7 +884,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-74 {
|
.emotion-64 {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
@@ -923,7 +901,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width:768px) {
|
@media (min-width:768px) {
|
||||||
.emotion-74 {
|
.emotion-64 {
|
||||||
min-width: 400px;
|
min-width: 400px;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
@@ -935,12 +913,12 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width:1024px) {
|
@media (min-width:1024px) {
|
||||||
.emotion-74 {
|
.emotion-64 {
|
||||||
max-width: 1240px;
|
max-width: 1240px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-65 {
|
.emotion-55 {
|
||||||
-webkit-align-items: center;
|
-webkit-align-items: center;
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
-ms-flex-align: center;
|
-ms-flex-align: center;
|
||||||
@@ -949,7 +927,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width:768px) {
|
@media (min-width:768px) {
|
||||||
.emotion-65 {
|
.emotion-55 {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
@@ -957,21 +935,21 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-38 {
|
.emotion-28 {
|
||||||
color: #e25555;
|
color: #e25555;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-63 {
|
.emotion-53 {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-63:hover .emotion-62 {
|
.emotion-53:hover .emotion-52 {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-41 {
|
.emotion-31 {
|
||||||
box-sizing: initial;
|
box-sizing: initial;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@@ -980,7 +958,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-61 {
|
.emotion-51 {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: #d3dddd;
|
background: #d3dddd;
|
||||||
padding: 1px 4px;
|
padding: 1px 4px;
|
||||||
@@ -998,7 +976,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
top: -2px;
|
top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-61:before {
|
.emotion-51:before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 29%;
|
top: 29%;
|
||||||
@@ -1011,7 +989,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-44 {
|
.emotion-34 {
|
||||||
box-sizing: initial;
|
box-sizing: initial;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@@ -1020,7 +998,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-72 {
|
.emotion-62 {
|
||||||
-webkit-align-items: center;
|
-webkit-align-items: center;
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
-ms-flex-align: center;
|
-ms-flex-align: center;
|
||||||
@@ -1033,7 +1011,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width:768px) {
|
@media (min-width:768px) {
|
||||||
.emotion-72 {
|
.emotion-62 {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
@@ -1041,7 +1019,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-70 {
|
.emotion-60 {
|
||||||
box-sizing: initial;
|
box-sizing: initial;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -1050,13 +1028,14 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-67 {
|
.emotion-57 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-2 emotion-78 emotion-79"
|
class="MuiBox-root MuiBox-root-2 emotion-68 emotion-69"
|
||||||
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<header
|
<header
|
||||||
class="MuiPaper-root MuiPaper-elevation4 MuiAppBar-root MuiAppBar-positionStatic emotion-24 emotion-25 MuiAppBar-colorPrimary"
|
class="MuiPaper-root MuiPaper-elevation4 MuiAppBar-root MuiAppBar-positionStatic emotion-24 emotion-25 MuiAppBar-colorPrimary"
|
||||||
@@ -1221,6 +1200,30 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
class="MuiTouchRipple-root"
|
class="MuiTouchRipple-root"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiIconButton-label"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
focusable="false"
|
||||||
|
role="presentation"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit"
|
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit"
|
||||||
data-testid="header--button-login"
|
data-testid="header--button-login"
|
||||||
@@ -1240,65 +1243,29 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-195 emotion-36 emotion-37"
|
class="MuiBox-root MuiBox-root-195 emotion-26 emotion-27"
|
||||||
>
|
/>
|
||||||
<div
|
|
||||||
class="emotion-34 emotion-35"
|
|
||||||
data-testid="loading"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="emotion-28 emotion-29"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="emotion-26 emotion-1"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="emotion-32 emotion-33"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCircularProgress-root emotion-30 emotion-31 MuiCircularProgress-colorPrimary MuiCircularProgress-indeterminate"
|
|
||||||
role="progressbar"
|
|
||||||
style="width: 50px; height: 50px;"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="MuiCircularProgress-svg"
|
|
||||||
viewBox="22 22 44 44"
|
|
||||||
>
|
|
||||||
<circle
|
|
||||||
class="MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate"
|
|
||||||
cx="44"
|
|
||||||
cy="44"
|
|
||||||
fill="none"
|
|
||||||
r="20.2"
|
|
||||||
stroke-width="3.6"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="emotion-76 emotion-77"
|
class="emotion-66 emotion-67"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="emotion-74 emotion-75"
|
class="emotion-64 emotion-65"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="emotion-65 emotion-66"
|
class="emotion-55 emotion-56"
|
||||||
>
|
>
|
||||||
Made with
|
Made with
|
||||||
<span
|
<span
|
||||||
class="emotion-38 emotion-39"
|
class="emotion-28 emotion-29"
|
||||||
>
|
>
|
||||||
♥
|
♥
|
||||||
</span>
|
</span>
|
||||||
on
|
on
|
||||||
<span
|
<span
|
||||||
class="emotion-63 emotion-64"
|
class="emotion-53 emotion-54"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="emotion-40 emotion-41 emotion-42"
|
class="emotion-30 emotion-31 emotion-32"
|
||||||
>
|
>
|
||||||
<title>
|
<title>
|
||||||
Earth
|
Earth
|
||||||
@@ -1308,10 +1275,10 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span
|
<span
|
||||||
class="emotion-61 emotion-62"
|
class="emotion-51 emotion-52"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="emotion-43 emotion-44 emotion-42"
|
class="emotion-33 emotion-34 emotion-32"
|
||||||
>
|
>
|
||||||
<title>
|
<title>
|
||||||
Spain
|
Spain
|
||||||
@@ -1321,7 +1288,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<svg
|
<svg
|
||||||
class="emotion-43 emotion-44 emotion-42"
|
class="emotion-33 emotion-34 emotion-32"
|
||||||
>
|
>
|
||||||
<title>
|
<title>
|
||||||
Nicaragua
|
Nicaragua
|
||||||
@@ -1331,7 +1298,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<svg
|
<svg
|
||||||
class="emotion-43 emotion-44 emotion-42"
|
class="emotion-33 emotion-34 emotion-32"
|
||||||
>
|
>
|
||||||
<title>
|
<title>
|
||||||
India
|
India
|
||||||
@@ -1341,7 +1308,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<svg
|
<svg
|
||||||
class="emotion-43 emotion-44 emotion-42"
|
class="emotion-33 emotion-34 emotion-32"
|
||||||
>
|
>
|
||||||
<title>
|
<title>
|
||||||
Brazil
|
Brazil
|
||||||
@@ -1351,7 +1318,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<svg
|
<svg
|
||||||
class="emotion-43 emotion-44 emotion-42"
|
class="emotion-33 emotion-34 emotion-32"
|
||||||
>
|
>
|
||||||
<title>
|
<title>
|
||||||
China
|
China
|
||||||
@@ -1361,7 +1328,7 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<svg
|
<svg
|
||||||
class="emotion-43 emotion-44 emotion-42"
|
class="emotion-33 emotion-34 emotion-32"
|
||||||
>
|
>
|
||||||
<title>
|
<title>
|
||||||
Austria
|
Austria
|
||||||
@@ -1374,16 +1341,16 @@ exports[`<App /> should display the Loading component at the beginning 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="emotion-72 emotion-73"
|
class="emotion-62 emotion-63"
|
||||||
>
|
>
|
||||||
Powered by
|
Powered by
|
||||||
<span
|
<span
|
||||||
class="emotion-43 emotion-70 emotion-71"
|
class="emotion-33 emotion-60 emotion-61"
|
||||||
title="Verdaccio"
|
title="Verdaccio"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Verdaccio"
|
alt="Verdaccio"
|
||||||
class="emotion-67 emotion-68"
|
class="emotion-57 emotion-58"
|
||||||
src="[object Object]"
|
src="[object Object]"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
52
src/App/load-dayjs-locale.ts
Normal file
52
src/App/load-dayjs-locale.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import dayjs from 'dayjs';
|
||||||
|
import i18n from 'i18next';
|
||||||
|
|
||||||
|
function getFallFackLanguage(): string | undefined {
|
||||||
|
const fallbackLanguage = i18n.options.fallbackLng;
|
||||||
|
|
||||||
|
if (Array.isArray(fallbackLanguage)) {
|
||||||
|
return fallbackLanguage[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof fallbackLanguage === 'string') {
|
||||||
|
return fallbackLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDayJSLocale() {
|
||||||
|
const fallbackLanguage = getFallFackLanguage();
|
||||||
|
const locale = i18n.language || fallbackLanguage;
|
||||||
|
|
||||||
|
// dayjs loades en-US by default
|
||||||
|
if (!locale || locale === 'en-US') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (locale.toLowerCase()) {
|
||||||
|
// At the moment we only support pt-BR, please see: i18n/translations/*
|
||||||
|
case 'pt-br':
|
||||||
|
{
|
||||||
|
require('dayjs/locale/pt-br');
|
||||||
|
dayjs.locale('pt-br');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'de':
|
||||||
|
{
|
||||||
|
require('dayjs/locale/de');
|
||||||
|
dayjs.locale('de');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'es-es':
|
||||||
|
{
|
||||||
|
require('dayjs/locale/es');
|
||||||
|
dayjs.locale('es');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default loadDayJSLocale;
|
||||||
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
import BugReportIcon from '@material-ui/icons/BugReport';
|
import BugReportIcon from '@material-ui/icons/BugReport';
|
||||||
import DownloadIcon from '@material-ui/icons/CloudDownload';
|
import DownloadIcon from '@material-ui/icons/CloudDownload';
|
||||||
import HomeIcon from '@material-ui/icons/Home';
|
import HomeIcon from '@material-ui/icons/Home';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Tooltip from '../../muiComponents/Tooltip';
|
import Tooltip from '../../muiComponents/Tooltip';
|
||||||
import Link from '../Link';
|
import Link from '../Link';
|
||||||
@@ -26,10 +27,11 @@ export interface ActionBarActionProps {
|
|||||||
|
|
||||||
/* eslint-disable react/jsx-no-bind */
|
/* eslint-disable react/jsx-no-bind */
|
||||||
const ActionBarAction: React.FC<ActionBarActionProps> = ({ type, link }) => {
|
const ActionBarAction: React.FC<ActionBarActionProps> = ({ type, link }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'VISIT_HOMEPAGE':
|
case 'VISIT_HOMEPAGE':
|
||||||
return (
|
return (
|
||||||
<Tooltip title="Visit homepage">
|
<Tooltip title={t('action-bar-action.visit-home-page')}>
|
||||||
<Link external={true} to={link}>
|
<Link external={true} to={link}>
|
||||||
<Fab size="small">
|
<Fab size="small">
|
||||||
<HomeIcon />
|
<HomeIcon />
|
||||||
@@ -39,7 +41,7 @@ const ActionBarAction: React.FC<ActionBarActionProps> = ({ type, link }) => {
|
|||||||
);
|
);
|
||||||
case 'OPEN_AN_ISSUE':
|
case 'OPEN_AN_ISSUE':
|
||||||
return (
|
return (
|
||||||
<Tooltip title="Open an issue">
|
<Tooltip title={t('action-bar-action.open-an-issue')}>
|
||||||
<Link external={true} to={link}>
|
<Link external={true} to={link}>
|
||||||
<Fab size="small">
|
<Fab size="small">
|
||||||
<BugReportIcon />
|
<BugReportIcon />
|
||||||
@@ -49,7 +51,7 @@ const ActionBarAction: React.FC<ActionBarActionProps> = ({ type, link }) => {
|
|||||||
);
|
);
|
||||||
case 'DOWNLOAD_TARBALL':
|
case 'DOWNLOAD_TARBALL':
|
||||||
return (
|
return (
|
||||||
<Tooltip title="Download tarball">
|
<Tooltip title={t('action-bar-action.download-tarball')}>
|
||||||
<Fab data-testid="download-tarball-btn" onClick={downloadTarball(link)} size="small">
|
<Fab data-testid="download-tarball-btn" onClick={downloadTarball(link)} size="small">
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
</Fab>
|
</Fab>
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import React, { FC, useContext } from 'react';
|
import React, { FC, useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import { isEmail } from '../../utils/url';
|
import { isEmail } from '../../utils/url';
|
||||||
import Avatar from '../../muiComponents/Avatar';
|
import Avatar from '../../muiComponents/Avatar';
|
||||||
import List from '../../muiComponents/List';
|
import List from '../../muiComponents/List';
|
||||||
|
import { getAuthorName } from '../../utils/package';
|
||||||
|
|
||||||
import { StyledText, AuthorListItem, AuthorListItemText } from './styles';
|
import { StyledText, AuthorListItem, AuthorListItemText } from './styles';
|
||||||
|
|
||||||
const Author: FC = () => {
|
const Author: FC = () => {
|
||||||
const { packageMeta } = useContext(DetailContext);
|
const { packageMeta } = useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!packageMeta) {
|
if (!packageMeta) {
|
||||||
return null;
|
return null;
|
||||||
@@ -25,7 +28,7 @@ const Author: FC = () => {
|
|||||||
const avatarComponent = <Avatar alt={author.name} src={author.avatar} />;
|
const avatarComponent = <Avatar alt={author.name} src={author.avatar} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List subheader={<StyledText variant={'subtitle1'}>{'Author'}</StyledText>}>
|
<List subheader={<StyledText variant={'subtitle1'}>{t('sidebar.author.title')}</StyledText>}>
|
||||||
<AuthorListItem button={true}>
|
<AuthorListItem button={true}>
|
||||||
{!email || !isEmail(email) ? (
|
{!email || !isEmail(email) ? (
|
||||||
avatarComponent
|
avatarComponent
|
||||||
@@ -34,8 +37,7 @@ const Author: FC = () => {
|
|||||||
{avatarComponent}
|
{avatarComponent}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
{name && <AuthorListItemText primary={getAuthorName(name)} />}
|
||||||
<AuthorListItemText primary={name} />
|
|
||||||
</AuthorListItem>
|
</AuthorListItem>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<Author /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText e1xuehjw0 MuiTypography-subtitle1\\">Author</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1k45khb-AuthorListItem e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><a href=\\"mailto:verdaccio.user@verdaccio.org?subject=verdaccio@4.0.0\\" target=\\"_top\\"><div class=\\"MuiAvatar-root MuiAvatar-circle\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div></a><div class=\\"MuiListItemText-root css-1cnlq5d-AuthorListItemText e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
exports[`<Author /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-5wp24z-StyledText e1xuehjw0 MuiTypography-subtitle1\\">sidebar.author.title</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1k45khb-AuthorListItem e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><a href=\\"mailto:verdaccio.user@verdaccio.org?subject=verdaccio@4.0.0\\" target=\\"_top\\"><div class=\\"MuiAvatar-root MuiAvatar-circle\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div></a><div class=\\"MuiListItemText-root css-1cnlq5d-AuthorListItemText e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
||||||
|
|
||||||
exports[`<Author /> component should render the component when there is no author email 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText e1xuehjw0 MuiTypography-subtitle1\\">Author</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1k45khb-AuthorListItem e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div><div class=\\"MuiListItemText-root css-1cnlq5d-AuthorListItemText e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
exports[`<Author /> component should render the component when there is no author email 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-5wp24z-StyledText e1xuehjw0 MuiTypography-subtitle1\\">sidebar.author.title</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1k45khb-AuthorListItem e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div><div class=\\"MuiListItemText-root css-1cnlq5d-AuthorListItemText e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { Theme } from '../../design-tokens/theme';
|
|||||||
|
|
||||||
export const StyledText = styled(Text)<{ theme?: Theme }>(props => ({
|
export const StyledText = styled(Text)<{ theme?: Theme }>(props => ({
|
||||||
fontWeight: props.theme && props.theme.fontWeight.bold,
|
fontWeight: props.theme && props.theme.fontWeight.bold,
|
||||||
textTransform: 'capitalize',
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const AuthorListItem = styled(ListItem)({
|
export const AuthorListItem = styled(ListItem)({
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
import Autosuggest, { SuggestionSelectedEventData, InputProps, ChangeEvent } from 'react-autosuggest';
|
import Autosuggest, { SuggestionSelectedEventData, InputProps, ChangeEvent } from 'react-autosuggest';
|
||||||
import match from 'autosuggest-highlight/match';
|
import match from 'autosuggest-highlight/match';
|
||||||
import parse from 'autosuggest-highlight/parse';
|
import parse from 'autosuggest-highlight/parse';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import MenuItem from '../../muiComponents/MenuItem';
|
import MenuItem from '../../muiComponents/MenuItem';
|
||||||
import { Theme } from '../../design-tokens/theme';
|
import { Theme } from '../../design-tokens/theme';
|
||||||
@@ -83,12 +84,6 @@ const renderMessage = (message): JSX.Element => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SUGGESTIONS_RESPONSE = {
|
|
||||||
LOADING: 'Loading...',
|
|
||||||
FAILURE: 'Something went wrong.',
|
|
||||||
NO_RESULT: 'No results found.',
|
|
||||||
};
|
|
||||||
|
|
||||||
const AutoComplete = memo(
|
const AutoComplete = memo(
|
||||||
({
|
({
|
||||||
suggestions,
|
suggestions,
|
||||||
@@ -106,6 +101,8 @@ const AutoComplete = memo(
|
|||||||
suggestionsLoaded = false,
|
suggestionsLoaded = false,
|
||||||
suggestionsError = false,
|
suggestionsError = false,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const autosuggestProps = {
|
const autosuggestProps = {
|
||||||
renderInputComponent,
|
renderInputComponent,
|
||||||
suggestions,
|
suggestions,
|
||||||
@@ -130,9 +127,9 @@ const AutoComplete = memo(
|
|||||||
function renderSuggestionsContainer({ containerProps, children, query }): JSX.Element {
|
function renderSuggestionsContainer({ containerProps, children, query }): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<SuggestionContainer {...containerProps} square={true}>
|
<SuggestionContainer {...containerProps} square={true}>
|
||||||
{suggestionsLoaded && children === null && query && renderMessage(SUGGESTIONS_RESPONSE.NO_RESULT)}
|
{suggestionsLoaded && children === null && query && renderMessage(t('auto-complete.no-results-found'))}
|
||||||
{suggestionsLoading && query && renderMessage(SUGGESTIONS_RESPONSE.LOADING)}
|
{suggestionsLoading && query && renderMessage(t('auto-complete.loading'))}
|
||||||
{suggestionsError && renderMessage(SUGGESTIONS_RESPONSE.FAILURE)}
|
{suggestionsError && renderMessage(t('error.unspecific'))}
|
||||||
{children}
|
{children}
|
||||||
</SuggestionContainer>
|
</SuggestionContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import FileCopy from '@material-ui/icons/FileCopy';
|
import FileCopy from '@material-ui/icons/FileCopy';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { copyToClipBoardUtility } from '../../utils/cli-utils';
|
import { copyToClipBoardUtility } from '../../utils/cli-utils';
|
||||||
import { TEXT } from '../../utils/constants';
|
|
||||||
import Tooltip from '../../muiComponents/Tooltip';
|
import Tooltip from '../../muiComponents/Tooltip';
|
||||||
|
|
||||||
import { ClipBoardCopy, ClipBoardCopyText, CopyIcon } from './styles';
|
import { ClipBoardCopy, ClipBoardCopyText, CopyIcon } from './styles';
|
||||||
@@ -20,19 +20,16 @@ const renderText = (text: string, children: React.ReactNode): JSX.Element => {
|
|||||||
return <ClipBoardCopyText>{text}</ClipBoardCopyText>;
|
return <ClipBoardCopyText>{text}</ClipBoardCopyText>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderToolTipFileCopy = (text: string): React.ReactElement<HTMLElement> => (
|
|
||||||
<Tooltip disableFocusListener={true} title={TEXT.CLIPBOARD_COPY}>
|
|
||||||
<CopyIcon onClick={copyToClipBoardUtility(text)}>
|
|
||||||
<FileCopy />
|
|
||||||
</CopyIcon>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
|
|
||||||
const CopyToClipBoard: React.FC<Props> = ({ text, children }) => {
|
const CopyToClipBoard: React.FC<Props> = ({ text, children }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<ClipBoardCopy>
|
<ClipBoardCopy>
|
||||||
{renderText(text, children)}
|
{renderText(text, children)}
|
||||||
{renderToolTipFileCopy(text)}
|
<Tooltip disableFocusListener={true} title={t('copy-to-clipboard')}>
|
||||||
|
<CopyIcon onClick={copyToClipBoardUtility(text)}>
|
||||||
|
<FileCopy />
|
||||||
|
</CopyIcon>
|
||||||
|
</Tooltip>
|
||||||
</ClipBoardCopy>
|
</ClipBoardCopy>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<CopyToClipBoard /> component should load the component in default state 1`] = `"<div class=\\"css-1in239f-ClipBoardCopy eb8w2fo0\\"><span class=\\"css-7gar9h-ClipBoardCopyText eb8w2fo1\\">copy text</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-1fs86cq-CopyIcon eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div>"`;
|
exports[`<CopyToClipBoard /> component should load the component in default state 1`] = `"<div class=\\"css-1in239f-ClipBoardCopy eb8w2fo0\\"><span class=\\"css-7gar9h-ClipBoardCopyText eb8w2fo1\\">copy text</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-1fs86cq-CopyIcon eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"copy-to-clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div>"`;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import CardContent from '../../muiComponents/CardContent';
|
import CardContent from '../../muiComponents/CardContent';
|
||||||
import { PackageDependencies } from '../../../types/packageMeta';
|
import { PackageDependencies } from '../../../types/packageMeta';
|
||||||
@@ -16,6 +17,7 @@ interface DependencyBlockProps {
|
|||||||
const DependencyBlock: React.FC<DependencyBlockProps> = ({ title, dependencies }) => {
|
const DependencyBlock: React.FC<DependencyBlockProps> = ({ title, dependencies }) => {
|
||||||
const { enableLoading } = useContext(DetailContext);
|
const { enableLoading } = useContext(DetailContext);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const deps = Object.entries(dependencies);
|
const deps = Object.entries(dependencies);
|
||||||
|
|
||||||
@@ -31,8 +33,14 @@ const DependencyBlock: React.FC<DependencyBlockProps> = ({ title, dependencies }
|
|||||||
<StyledText variant="subtitle1">{`${title} (${deps.length})`}</StyledText>
|
<StyledText variant="subtitle1">{`${title} (${deps.length})`}</StyledText>
|
||||||
<Tags>
|
<Tags>
|
||||||
{deps.map(([name, version]) => (
|
{deps.map(([name, version]) => (
|
||||||
// eslint-disable-next-line
|
<Tag
|
||||||
<Tag className={'dep-tag'} clickable={true} key={name} label={`${name}@${version}`} onClick={() => handleClick(name)} />
|
className={'dep-tag'}
|
||||||
|
clickable={true}
|
||||||
|
key={name}
|
||||||
|
label={t('dependencies.dependency-block', { package: name, version })}
|
||||||
|
// eslint-disable-next-line
|
||||||
|
onClick={() => handleClick(name)}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Tags>
|
</Tags>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -46,9 +54,10 @@ function hasKeys(object?: { [key: string]: any }): boolean {
|
|||||||
|
|
||||||
const Dependencies: React.FC<{}> = () => {
|
const Dependencies: React.FC<{}> = () => {
|
||||||
const { packageMeta } = useContext(DetailContext);
|
const { packageMeta } = useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!packageMeta) {
|
if (!packageMeta) {
|
||||||
throw new Error('packageMeta is required at DetailContext');
|
throw new Error(t('error.package-meta-is-required-at-detail-context'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { latest } = packageMeta;
|
const { latest } = packageMeta;
|
||||||
@@ -72,7 +81,7 @@ const Dependencies: React.FC<{}> = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <NoItems className="no-dependencies" text={`${name} has no dependencies.`} />;
|
return <NoItems className="no-dependencies" text={t('dependencies.has-no-dependencies', { package: name })} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Dependencies;
|
export default Dependencies;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useState, ChangeEvent, useContext } from 'react';
|
import React, { useState, useContext } from 'react';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import Box from '../../muiComponents/Box';
|
import Box from '../../muiComponents/Box';
|
||||||
@@ -8,24 +8,19 @@ import DetailContainerContent from './DetailContainerContent';
|
|||||||
import { TabPosition } from './tabs';
|
import { TabPosition } from './tabs';
|
||||||
|
|
||||||
const DetailContainer: React.FC = () => {
|
const DetailContainer: React.FC = () => {
|
||||||
const [tabPosition, setTabPosition] = useState(TabPosition.README);
|
const tabs = Object.values(TabPosition);
|
||||||
|
const [tabPosition, setTabPosition] = useState(0);
|
||||||
const detailContext = useContext(DetailContext);
|
const detailContext = useContext(DetailContext);
|
||||||
const { readMe } = detailContext;
|
const { readMe } = detailContext;
|
||||||
|
|
||||||
const handleChangeTabPosition = useCallback(
|
const handleChange = (event, newValue) => {
|
||||||
(event: ChangeEvent<{}>) => {
|
setTabPosition(newValue);
|
||||||
event.preventDefault();
|
};
|
||||||
const eventTarget = event.target as HTMLSpanElement;
|
|
||||||
const chosentab = eventTarget.innerText as TabPosition;
|
|
||||||
setTabPosition(TabPosition[chosentab]);
|
|
||||||
},
|
|
||||||
[setTabPosition]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box component="div" display="flex" flexDirection="column" padding={2}>
|
<Box component="div" display="flex" flexDirection="column" padding={2}>
|
||||||
<DetailContainerTabs onChangeTabPosition={handleChangeTabPosition} tabPosition={tabPosition} />
|
<DetailContainerTabs onChange={handleChange} tabPosition={tabPosition} />
|
||||||
<DetailContainerContent readDescription={readMe} tabPosition={tabPosition} />
|
<DetailContainerContent readDescription={readMe} tabPosition={tabs[tabPosition]} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,44 +1,31 @@
|
|||||||
import React, { ChangeEvent, useState, useEffect } from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { default as MuiTabs } from '../../muiComponents/Tabs';
|
import { default as MuiTabs } from '../../muiComponents/Tabs';
|
||||||
import Tab from '../../muiComponents/Tab';
|
import Tab from '../../muiComponents/Tab';
|
||||||
|
import { Theme } from '../../design-tokens/theme';
|
||||||
import { TabPosition } from './tabs';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tabPosition: TabPosition;
|
onChange: (event, newValue) => void;
|
||||||
onChangeTabPosition: (event: ChangeEvent<{}>) => void;
|
tabPosition: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tabs = styled(MuiTabs)({
|
const DetailContainerTabs: React.FC<Props> = ({ tabPosition, onChange }) => {
|
||||||
marginBottom: 16,
|
const { t } = useTranslation();
|
||||||
});
|
|
||||||
|
|
||||||
const getTabIndex = (tabPosition: TabPosition): number =>
|
|
||||||
Object.keys(TabPosition).findIndex(position => position === String(tabPosition).toUpperCase());
|
|
||||||
|
|
||||||
const DetailContainerTabs: React.FC<Props> = ({ tabPosition, onChangeTabPosition }) => {
|
|
||||||
const [tabPositionIndex, setTabPositionIndex] = useState(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const tabIndex = getTabIndex(tabPosition);
|
|
||||||
setTabPositionIndex(tabIndex);
|
|
||||||
}, [tabPosition]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs color={'primary'} indicatorColor={'primary'} onChange={onChange} value={tabPosition} variant={'fullWidth'}>
|
||||||
indicatorColor={'primary'}
|
<Tab data-testid={'readme-tab'} id={'readme-tab'} label={t('tab.readme')} />
|
||||||
onChange={onChangeTabPosition}
|
<Tab data-testid={'dependencies-tab'} id={'dependencies-tab'} label={t('tab.dependencies')} />
|
||||||
textColor={'primary'}
|
<Tab data-testid={'versions-tab'} id={'versions-tab'} label={t('tab.versions')} />
|
||||||
value={tabPositionIndex}
|
<Tab data-testid={'uplinks-tab'} id={'uplinks-tab'} label={t('tab.uplinks')} />
|
||||||
variant={'fullWidth'}>
|
|
||||||
<Tab data-testid={'readme-tab'} id={'readme-tab'} label={TabPosition.README} />
|
|
||||||
<Tab data-testid={'dependencies-tab'} id={'dependencies-tab'} label={TabPosition.DEPENDENCIES} />
|
|
||||||
<Tab data-testid={'versions-tab'} id={'versions-tab'} label={TabPosition.VERSIONS} />
|
|
||||||
<Tab data-testid={'uplinks-tab'} id={'uplinks-tab'} label={TabPosition.UPLINKS} />
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DetailContainerTabs;
|
export default DetailContainerTabs;
|
||||||
|
|
||||||
|
const Tabs = styled(MuiTabs)<{ theme?: Theme }>({
|
||||||
|
marginBottom: 16,
|
||||||
|
});
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ exports[`DetailContainer renders correctly 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTabs-root emotion-0 emotion-1"
|
class="MuiTabs-root emotion-0 emotion-1"
|
||||||
|
color="primary"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTabs-scroller MuiTabs-fixed"
|
class="MuiTabs-scroller MuiTabs-fixed"
|
||||||
@@ -21,7 +22,7 @@ exports[`DetailContainer renders correctly 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-selected="true"
|
aria-selected="true"
|
||||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary Mui-selected MuiTab-fullWidth"
|
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit Mui-selected MuiTab-fullWidth"
|
||||||
data-testid="readme-tab"
|
data-testid="readme-tab"
|
||||||
id="readme-tab"
|
id="readme-tab"
|
||||||
role="tab"
|
role="tab"
|
||||||
@@ -39,7 +40,7 @@ exports[`DetailContainer renders correctly 1`] = `
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-selected="false"
|
aria-selected="false"
|
||||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth"
|
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit MuiTab-fullWidth"
|
||||||
data-testid="dependencies-tab"
|
data-testid="dependencies-tab"
|
||||||
id="dependencies-tab"
|
id="dependencies-tab"
|
||||||
role="tab"
|
role="tab"
|
||||||
@@ -57,7 +58,7 @@ exports[`DetailContainer renders correctly 1`] = `
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-selected="false"
|
aria-selected="false"
|
||||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth"
|
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit MuiTab-fullWidth"
|
||||||
data-testid="versions-tab"
|
data-testid="versions-tab"
|
||||||
id="versions-tab"
|
id="versions-tab"
|
||||||
role="tab"
|
role="tab"
|
||||||
@@ -75,7 +76,7 @@ exports[`DetailContainer renders correctly 1`] = `
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-selected="false"
|
aria-selected="false"
|
||||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth"
|
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit MuiTab-fullWidth"
|
||||||
data-testid="uplinks-tab"
|
data-testid="uplinks-tab"
|
||||||
id="uplinks-tab"
|
id="uplinks-tab"
|
||||||
role="tab"
|
role="tab"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export enum TabPosition {
|
export enum TabPosition {
|
||||||
README = 'Readme',
|
README = 'readme',
|
||||||
DEPENDENCIES = 'Dependencies',
|
DEPENDENCIES = 'dependencies',
|
||||||
VERSIONS = 'Versions',
|
VERSIONS = 'versions',
|
||||||
UPLINKS = 'Uplinks',
|
UPLINKS = 'uplinks',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ import { Theme } from '../../design-tokens/theme';
|
|||||||
import DetailSidebarTitle from './DetailSidebarTitle';
|
import DetailSidebarTitle from './DetailSidebarTitle';
|
||||||
import DetailSidebarFundButton from './DetailSidebarFundButton';
|
import DetailSidebarFundButton from './DetailSidebarFundButton';
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)<{ theme?: Theme }>(({ theme }) => ({
|
|
||||||
padding: theme.spacing(3, 2),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const DetailSidebar: React.FC = () => {
|
const DetailSidebar: React.FC = () => {
|
||||||
const detailContext = useContext(DetailContext);
|
const detailContext = useContext(DetailContext);
|
||||||
|
|
||||||
@@ -50,3 +46,7 @@ const DetailSidebar: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default DetailSidebar;
|
export default DetailSidebar;
|
||||||
|
|
||||||
|
const StyledPaper = styled(Paper)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
|
padding: theme?.spacing(3, 2),
|
||||||
|
}));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import Favorite from '@material-ui/icons/Favorite';
|
import Favorite from '@material-ui/icons/Favorite';
|
||||||
|
import { Trans } from 'react-i18next';
|
||||||
|
|
||||||
import Button from '../../muiComponents/Button';
|
import Button from '../../muiComponents/Button';
|
||||||
import Link from '../Link';
|
import Link from '../Link';
|
||||||
@@ -38,8 +39,7 @@ const DetailSidebarFundButton: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<StyledLink external={true} to={fundingUrl}>
|
<StyledLink external={true} to={fundingUrl}>
|
||||||
<Button color="primary" fullWidth={true} startIcon={<StyledFavoriteIcon />} variant="outlined">
|
<Button color="primary" fullWidth={true} startIcon={<StyledFavoriteIcon />} variant="outlined">
|
||||||
<StyledFundStrong>{'Fund'}</StyledFundStrong>
|
<Trans components={[<StyledFundStrong key="fund" />]} i18nKey="button.fund-this-package" />
|
||||||
{'this package'}
|
|
||||||
</Button>
|
</Button>
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Box from '../../muiComponents/Box';
|
import Box from '../../muiComponents/Box';
|
||||||
import Heading from '../../muiComponents/Heading';
|
import Heading from '../../muiComponents/Heading';
|
||||||
@@ -12,6 +13,21 @@ interface Props {
|
|||||||
isLatest: boolean;
|
isLatest: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DetailSidebarTitle: React.FC<Props> = ({ description, packageName, version, isLatest }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<Box className={'detail-info'} display="flex" flexDirection="column" marginBottom="8px">
|
||||||
|
<StyledHeading>{packageName}</StyledHeading>
|
||||||
|
{description && <div>{description}</div>}
|
||||||
|
<StyledBoxVersion>
|
||||||
|
{isLatest ? t('sidebar.detail.latest-version', { version }) : t('sidebar.detail.version', { version })}
|
||||||
|
</StyledBoxVersion>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DetailSidebarTitle;
|
||||||
|
|
||||||
const StyledHeading = styled(Heading)({
|
const StyledHeading = styled(Heading)({
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
@@ -20,13 +36,3 @@ const StyledHeading = styled(Heading)({
|
|||||||
const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
color: theme && theme.palette.text.secondary,
|
color: theme && theme.palette.text.secondary,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const DetailSidebarTitle: React.FC<Props> = ({ description, packageName, version, isLatest }) => (
|
|
||||||
<Box className={'detail-info'} display="flex" flexDirection="column" marginBottom="8px">
|
|
||||||
<StyledHeading>{packageName}</StyledHeading>
|
|
||||||
{description && <div>{description}</div>}
|
|
||||||
<StyledBoxVersion>{`${isLatest ? 'Latest v' : 'v'}${version}`}</StyledBoxVersion>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default DetailSidebarTitle;
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import React from 'react';
|
|||||||
import { mount } from '../../utils/test-enzyme';
|
import { mount } from '../../utils/test-enzyme';
|
||||||
import { DetailContextProvider } from '../../pages/Version';
|
import { DetailContextProvider } from '../../pages/Version';
|
||||||
|
|
||||||
import Developers, { DeveloperType, Fab } from './Developers';
|
import Developers, { Fab } from './Developers';
|
||||||
|
import { DeveloperType } from './types';
|
||||||
|
|
||||||
describe('test Developers', () => {
|
describe('test Developers', () => {
|
||||||
const packageMeta = {
|
const packageMeta = {
|
||||||
|
|||||||
@@ -1,38 +1,29 @@
|
|||||||
import React, { useState, useCallback, useContext, useEffect, useMemo } from 'react';
|
import React, { useState, useCallback, useContext, useEffect, useMemo } from 'react';
|
||||||
import Add from '@material-ui/icons/Add';
|
import Add from '@material-ui/icons/Add';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import Tooltip from '../../muiComponents/Tooltip';
|
import Tooltip from '../../muiComponents/Tooltip';
|
||||||
import Avatar from '../../muiComponents/Avatar';
|
import Avatar from '../../muiComponents/Avatar';
|
||||||
import Box from '../../muiComponents/Box';
|
import Box from '../../muiComponents/Box';
|
||||||
import Text from '../../muiComponents/Text';
|
|
||||||
import FloatingActionButton from '../../muiComponents/FloatingActionButton';
|
import FloatingActionButton from '../../muiComponents/FloatingActionButton';
|
||||||
import { Theme } from '../../design-tokens/theme';
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
import getUniqueDeveloperValues from './get-unique-developer-values';
|
import getUniqueDeveloperValues from './get-unique-developer-values';
|
||||||
|
import DevelopersTitle from './DevelopersTitle';
|
||||||
|
import { DeveloperType } from './types';
|
||||||
|
|
||||||
export const Fab = styled(FloatingActionButton)<{ theme?: Theme }>(props => ({
|
export const Fab = styled(FloatingActionButton)<{ theme?: Theme }>(props => ({
|
||||||
backgroundColor: props.theme && props.theme.palette.primary.main,
|
backgroundColor: props.theme && props.theme.palette.primary.main,
|
||||||
color: props.theme && props.theme.palette.white,
|
color: props.theme && props.theme.palette.white,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export enum DeveloperType {
|
|
||||||
CONTRIBUTORS = 'contributors',
|
|
||||||
MAINTAINERS = 'maintainers',
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: DeveloperType;
|
type: DeveloperType;
|
||||||
visibleMax?: number;
|
visibleMax?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StyledText = styled(Text)<{ theme?: Theme }>(({ theme }) => ({
|
|
||||||
fontWeight: theme && theme.fontWeight.bold,
|
|
||||||
marginBottom: '10px',
|
|
||||||
textTransform: 'capitalize',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledBox = styled(Box)({
|
const StyledBox = styled(Box)({
|
||||||
'> *': {
|
'> *': {
|
||||||
margin: 5,
|
margin: 5,
|
||||||
@@ -43,9 +34,10 @@ export const VISIBLE_MAX = 6;
|
|||||||
|
|
||||||
const Developers: React.FC<Props> = ({ type, visibleMax = VISIBLE_MAX }) => {
|
const Developers: React.FC<Props> = ({ type, visibleMax = VISIBLE_MAX }) => {
|
||||||
const detailContext = useContext(DetailContext);
|
const detailContext = useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!detailContext) {
|
if (!detailContext) {
|
||||||
throw Error("The app's detail Context was not correct used");
|
throw Error(t('app-context-not-correct-used'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const developers = useMemo(() => getUniqueDeveloperValues(detailContext.packageMeta?.latest[type]), [
|
const developers = useMemo(() => getUniqueDeveloperValues(detailContext.packageMeta?.latest[type]), [
|
||||||
@@ -69,7 +61,7 @@ const Developers: React.FC<Props> = ({ type, visibleMax = VISIBLE_MAX }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledText variant={'subtitle1'}>{type}</StyledText>
|
<DevelopersTitle type={type} />
|
||||||
<StyledBox display="flex" flexWrap="wrap" margin="10px 0 10px 0">
|
<StyledBox display="flex" flexWrap="wrap" margin="10px 0 10px 0">
|
||||||
{visibleDevelopers.map(visibleDeveloper => (
|
{visibleDevelopers.map(visibleDeveloper => (
|
||||||
<Tooltip key={visibleDeveloper.email} title={visibleDeveloper.name}>
|
<Tooltip key={visibleDeveloper.email} title={visibleDeveloper.name}>
|
||||||
|
|||||||
30
src/components/Developers/DevelopersTitle.tsx
Normal file
30
src/components/Developers/DevelopersTitle.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import Text from '../../muiComponents/Text';
|
||||||
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
|
import { DeveloperType } from './types';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type: DeveloperType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DevelopersTitle: React.FC<Props> = ({ type }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
switch (type) {
|
||||||
|
case DeveloperType.CONTRIBUTORS:
|
||||||
|
return <StyledText variant={'subtitle1'}>{t('sidebar.contributors.title')}</StyledText>;
|
||||||
|
case DeveloperType.MAINTAINERS:
|
||||||
|
return <StyledText variant={'subtitle1'}>{t('sidebar.maintainers.title')}</StyledText>;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DevelopersTitle;
|
||||||
|
|
||||||
|
const StyledText = styled(Text)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
|
fontWeight: theme && theme.fontWeight.bold,
|
||||||
|
marginBottom: '10px',
|
||||||
|
}));
|
||||||
@@ -4,7 +4,6 @@ exports[`test Developers should render the component for contributors with items
|
|||||||
.emotion-0 {
|
.emotion-0 {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-8 > * {
|
.emotion-8 > * {
|
||||||
@@ -14,64 +13,68 @@ exports[`test Developers should render the component for contributors with items
|
|||||||
<Developers
|
<Developers
|
||||||
type="contributors"
|
type="contributors"
|
||||||
>
|
>
|
||||||
<StyledText
|
<DevelopersTitle
|
||||||
variant="subtitle1"
|
type="contributors"
|
||||||
>
|
>
|
||||||
<ForwardRef(Text)
|
<StyledText
|
||||||
className="emotion-0 emotion-1"
|
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
<WithStyles(ForwardRef(Typography))
|
<ForwardRef(Text)
|
||||||
className="emotion-0 emotion-1"
|
className="emotion-0 emotion-1"
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
<ForwardRef(Typography)
|
<WithStyles(ForwardRef(Typography))
|
||||||
className="emotion-0 emotion-1"
|
className="emotion-0 emotion-1"
|
||||||
classes={
|
|
||||||
Object {
|
|
||||||
"alignCenter": "MuiTypography-alignCenter",
|
|
||||||
"alignJustify": "MuiTypography-alignJustify",
|
|
||||||
"alignLeft": "MuiTypography-alignLeft",
|
|
||||||
"alignRight": "MuiTypography-alignRight",
|
|
||||||
"body1": "MuiTypography-body1",
|
|
||||||
"body2": "MuiTypography-body2",
|
|
||||||
"button": "MuiTypography-button",
|
|
||||||
"caption": "MuiTypography-caption",
|
|
||||||
"colorError": "MuiTypography-colorError",
|
|
||||||
"colorInherit": "MuiTypography-colorInherit",
|
|
||||||
"colorPrimary": "MuiTypography-colorPrimary",
|
|
||||||
"colorSecondary": "MuiTypography-colorSecondary",
|
|
||||||
"colorTextPrimary": "MuiTypography-colorTextPrimary",
|
|
||||||
"colorTextSecondary": "MuiTypography-colorTextSecondary",
|
|
||||||
"displayBlock": "MuiTypography-displayBlock",
|
|
||||||
"displayInline": "MuiTypography-displayInline",
|
|
||||||
"gutterBottom": "MuiTypography-gutterBottom",
|
|
||||||
"h1": "MuiTypography-h1",
|
|
||||||
"h2": "MuiTypography-h2",
|
|
||||||
"h3": "MuiTypography-h3",
|
|
||||||
"h4": "MuiTypography-h4",
|
|
||||||
"h5": "MuiTypography-h5",
|
|
||||||
"h6": "MuiTypography-h6",
|
|
||||||
"noWrap": "MuiTypography-noWrap",
|
|
||||||
"overline": "MuiTypography-overline",
|
|
||||||
"paragraph": "MuiTypography-paragraph",
|
|
||||||
"root": "MuiTypography-root",
|
|
||||||
"srOnly": "MuiTypography-srOnly",
|
|
||||||
"subtitle1": "MuiTypography-subtitle1",
|
|
||||||
"subtitle2": "MuiTypography-subtitle2",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
<h6
|
<ForwardRef(Typography)
|
||||||
className="MuiTypography-root emotion-0 emotion-1 MuiTypography-subtitle1"
|
className="emotion-0 emotion-1"
|
||||||
|
classes={
|
||||||
|
Object {
|
||||||
|
"alignCenter": "MuiTypography-alignCenter",
|
||||||
|
"alignJustify": "MuiTypography-alignJustify",
|
||||||
|
"alignLeft": "MuiTypography-alignLeft",
|
||||||
|
"alignRight": "MuiTypography-alignRight",
|
||||||
|
"body1": "MuiTypography-body1",
|
||||||
|
"body2": "MuiTypography-body2",
|
||||||
|
"button": "MuiTypography-button",
|
||||||
|
"caption": "MuiTypography-caption",
|
||||||
|
"colorError": "MuiTypography-colorError",
|
||||||
|
"colorInherit": "MuiTypography-colorInherit",
|
||||||
|
"colorPrimary": "MuiTypography-colorPrimary",
|
||||||
|
"colorSecondary": "MuiTypography-colorSecondary",
|
||||||
|
"colorTextPrimary": "MuiTypography-colorTextPrimary",
|
||||||
|
"colorTextSecondary": "MuiTypography-colorTextSecondary",
|
||||||
|
"displayBlock": "MuiTypography-displayBlock",
|
||||||
|
"displayInline": "MuiTypography-displayInline",
|
||||||
|
"gutterBottom": "MuiTypography-gutterBottom",
|
||||||
|
"h1": "MuiTypography-h1",
|
||||||
|
"h2": "MuiTypography-h2",
|
||||||
|
"h3": "MuiTypography-h3",
|
||||||
|
"h4": "MuiTypography-h4",
|
||||||
|
"h5": "MuiTypography-h5",
|
||||||
|
"h6": "MuiTypography-h6",
|
||||||
|
"noWrap": "MuiTypography-noWrap",
|
||||||
|
"overline": "MuiTypography-overline",
|
||||||
|
"paragraph": "MuiTypography-paragraph",
|
||||||
|
"root": "MuiTypography-root",
|
||||||
|
"srOnly": "MuiTypography-srOnly",
|
||||||
|
"subtitle1": "MuiTypography-subtitle1",
|
||||||
|
"subtitle2": "MuiTypography-subtitle2",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
contributors
|
<h6
|
||||||
</h6>
|
className="MuiTypography-root emotion-0 emotion-1 MuiTypography-subtitle1"
|
||||||
</ForwardRef(Typography)>
|
>
|
||||||
</WithStyles(ForwardRef(Typography))>
|
sidebar.contributors.title
|
||||||
</ForwardRef(Text)>
|
</h6>
|
||||||
</StyledText>
|
</ForwardRef(Typography)>
|
||||||
|
</WithStyles(ForwardRef(Typography))>
|
||||||
|
</ForwardRef(Text)>
|
||||||
|
</StyledText>
|
||||||
|
</DevelopersTitle>
|
||||||
<StyledBox
|
<StyledBox
|
||||||
display="flex"
|
display="flex"
|
||||||
flexWrap="wrap"
|
flexWrap="wrap"
|
||||||
@@ -90,7 +93,7 @@ exports[`test Developers should render the component for contributors with items
|
|||||||
margin="10px 0 10px 0"
|
margin="10px 0 10px 0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="MuiBox-root MuiBox-root-60 emotion-8 emotion-9"
|
className="MuiBox-root MuiBox-root-91 emotion-8 emotion-9"
|
||||||
>
|
>
|
||||||
<ForwardRef(ToolTip)
|
<ForwardRef(ToolTip)
|
||||||
key="dave.methvin@gmail.com"
|
key="dave.methvin@gmail.com"
|
||||||
@@ -427,7 +430,6 @@ exports[`test Developers should render the component for maintainers with items
|
|||||||
.emotion-0 {
|
.emotion-0 {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.emotion-8 > * {
|
.emotion-8 > * {
|
||||||
@@ -437,64 +439,68 @@ exports[`test Developers should render the component for maintainers with items
|
|||||||
<Developers
|
<Developers
|
||||||
type="maintainers"
|
type="maintainers"
|
||||||
>
|
>
|
||||||
<StyledText
|
<DevelopersTitle
|
||||||
variant="subtitle1"
|
type="maintainers"
|
||||||
>
|
>
|
||||||
<ForwardRef(Text)
|
<StyledText
|
||||||
className="emotion-0 emotion-1"
|
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
<WithStyles(ForwardRef(Typography))
|
<ForwardRef(Text)
|
||||||
className="emotion-0 emotion-1"
|
className="emotion-0 emotion-1"
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
<ForwardRef(Typography)
|
<WithStyles(ForwardRef(Typography))
|
||||||
className="emotion-0 emotion-1"
|
className="emotion-0 emotion-1"
|
||||||
classes={
|
|
||||||
Object {
|
|
||||||
"alignCenter": "MuiTypography-alignCenter",
|
|
||||||
"alignJustify": "MuiTypography-alignJustify",
|
|
||||||
"alignLeft": "MuiTypography-alignLeft",
|
|
||||||
"alignRight": "MuiTypography-alignRight",
|
|
||||||
"body1": "MuiTypography-body1",
|
|
||||||
"body2": "MuiTypography-body2",
|
|
||||||
"button": "MuiTypography-button",
|
|
||||||
"caption": "MuiTypography-caption",
|
|
||||||
"colorError": "MuiTypography-colorError",
|
|
||||||
"colorInherit": "MuiTypography-colorInherit",
|
|
||||||
"colorPrimary": "MuiTypography-colorPrimary",
|
|
||||||
"colorSecondary": "MuiTypography-colorSecondary",
|
|
||||||
"colorTextPrimary": "MuiTypography-colorTextPrimary",
|
|
||||||
"colorTextSecondary": "MuiTypography-colorTextSecondary",
|
|
||||||
"displayBlock": "MuiTypography-displayBlock",
|
|
||||||
"displayInline": "MuiTypography-displayInline",
|
|
||||||
"gutterBottom": "MuiTypography-gutterBottom",
|
|
||||||
"h1": "MuiTypography-h1",
|
|
||||||
"h2": "MuiTypography-h2",
|
|
||||||
"h3": "MuiTypography-h3",
|
|
||||||
"h4": "MuiTypography-h4",
|
|
||||||
"h5": "MuiTypography-h5",
|
|
||||||
"h6": "MuiTypography-h6",
|
|
||||||
"noWrap": "MuiTypography-noWrap",
|
|
||||||
"overline": "MuiTypography-overline",
|
|
||||||
"paragraph": "MuiTypography-paragraph",
|
|
||||||
"root": "MuiTypography-root",
|
|
||||||
"srOnly": "MuiTypography-srOnly",
|
|
||||||
"subtitle1": "MuiTypography-subtitle1",
|
|
||||||
"subtitle2": "MuiTypography-subtitle2",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
<h6
|
<ForwardRef(Typography)
|
||||||
className="MuiTypography-root emotion-0 emotion-1 MuiTypography-subtitle1"
|
className="emotion-0 emotion-1"
|
||||||
|
classes={
|
||||||
|
Object {
|
||||||
|
"alignCenter": "MuiTypography-alignCenter",
|
||||||
|
"alignJustify": "MuiTypography-alignJustify",
|
||||||
|
"alignLeft": "MuiTypography-alignLeft",
|
||||||
|
"alignRight": "MuiTypography-alignRight",
|
||||||
|
"body1": "MuiTypography-body1",
|
||||||
|
"body2": "MuiTypography-body2",
|
||||||
|
"button": "MuiTypography-button",
|
||||||
|
"caption": "MuiTypography-caption",
|
||||||
|
"colorError": "MuiTypography-colorError",
|
||||||
|
"colorInherit": "MuiTypography-colorInherit",
|
||||||
|
"colorPrimary": "MuiTypography-colorPrimary",
|
||||||
|
"colorSecondary": "MuiTypography-colorSecondary",
|
||||||
|
"colorTextPrimary": "MuiTypography-colorTextPrimary",
|
||||||
|
"colorTextSecondary": "MuiTypography-colorTextSecondary",
|
||||||
|
"displayBlock": "MuiTypography-displayBlock",
|
||||||
|
"displayInline": "MuiTypography-displayInline",
|
||||||
|
"gutterBottom": "MuiTypography-gutterBottom",
|
||||||
|
"h1": "MuiTypography-h1",
|
||||||
|
"h2": "MuiTypography-h2",
|
||||||
|
"h3": "MuiTypography-h3",
|
||||||
|
"h4": "MuiTypography-h4",
|
||||||
|
"h5": "MuiTypography-h5",
|
||||||
|
"h6": "MuiTypography-h6",
|
||||||
|
"noWrap": "MuiTypography-noWrap",
|
||||||
|
"overline": "MuiTypography-overline",
|
||||||
|
"paragraph": "MuiTypography-paragraph",
|
||||||
|
"root": "MuiTypography-root",
|
||||||
|
"srOnly": "MuiTypography-srOnly",
|
||||||
|
"subtitle1": "MuiTypography-subtitle1",
|
||||||
|
"subtitle2": "MuiTypography-subtitle2",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variant="subtitle1"
|
||||||
>
|
>
|
||||||
maintainers
|
<h6
|
||||||
</h6>
|
className="MuiTypography-root emotion-0 emotion-1 MuiTypography-subtitle1"
|
||||||
</ForwardRef(Typography)>
|
>
|
||||||
</WithStyles(ForwardRef(Typography))>
|
sidebar.maintainers.title
|
||||||
</ForwardRef(Text)>
|
</h6>
|
||||||
</StyledText>
|
</ForwardRef(Typography)>
|
||||||
|
</WithStyles(ForwardRef(Typography))>
|
||||||
|
</ForwardRef(Text)>
|
||||||
|
</StyledText>
|
||||||
|
</DevelopersTitle>
|
||||||
<StyledBox
|
<StyledBox
|
||||||
display="flex"
|
display="flex"
|
||||||
flexWrap="wrap"
|
flexWrap="wrap"
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export { default, DeveloperType } from './Developers';
|
export { default } from './Developers';
|
||||||
|
export { DeveloperType } from './types';
|
||||||
|
|||||||
4
src/components/Developers/types.ts
Normal file
4
src/components/Developers/types.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export enum DeveloperType {
|
||||||
|
CONTRIBUTORS = 'contributors',
|
||||||
|
MAINTAINERS = 'maintainers',
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { FC, useContext } from 'react';
|
import React, { FC, useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import fileSizeSI from '../../utils/file-size';
|
import fileSizeSI from '../../utils/file-size';
|
||||||
@@ -22,6 +23,7 @@ const DistChip: FC<{ name: string }> = ({ name, children }) =>
|
|||||||
|
|
||||||
const Dist: FC = () => {
|
const Dist: FC = () => {
|
||||||
const { packageMeta } = useContext(DetailContext);
|
const { packageMeta } = useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!packageMeta) {
|
if (!packageMeta) {
|
||||||
return null;
|
return null;
|
||||||
@@ -30,11 +32,11 @@ const Dist: FC = () => {
|
|||||||
const { dist, license } = packageMeta && packageMeta.latest;
|
const { dist, license } = packageMeta && packageMeta.latest;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List subheader={<StyledText variant="subtitle1">{'Latest Distribution'}</StyledText>}>
|
<List subheader={<StyledText variant="subtitle1">{t('sidebar.distribution.title')}</StyledText>}>
|
||||||
<DistListItem button={true}>
|
<DistListItem button={true}>
|
||||||
<DistChip name="file count">{dist.fileCount}</DistChip>
|
<DistChip name={t('sidebar.distribution.file-count')}>{dist.fileCount}</DistChip>
|
||||||
<DistChip name="size">{dist.unpackedSize && fileSizeSI(dist.unpackedSize)}</DistChip>
|
<DistChip name={t('sidebar.distribution.size')}>{dist.unpackedSize && fileSizeSI(dist.unpackedSize)}</DistChip>
|
||||||
<DistChip name="license">{formatLicense(license)}</DistChip>
|
<DistChip name={t('sidebar.distribution.license')}>{formatLicense(license)}</DistChip>
|
||||||
</DistListItem>
|
</DistListItem>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<Dist /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1mms18p-DistListItem estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
exports[`<Dist /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText estxrtg0 MuiTypography-subtitle1\\">sidebar.distribution.title</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1mms18p-DistListItem estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.file-count</b>: 7</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.size</b>: 10.00 Bytes</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
||||||
|
|
||||||
exports[`<Dist /> component should render the component with license as object 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1mms18p-DistListItem estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
exports[`<Dist /> component should render the component with license as object 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText estxrtg0 MuiTypography-subtitle1\\">sidebar.distribution.title</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1mms18p-DistListItem estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.file-count</b>: 7</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
||||||
|
|
||||||
exports[`<Dist /> component should render the component with license as string 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1mms18p-DistListItem estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
exports[`<Dist /> component should render the component with license as string 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText estxrtg0 MuiTypography-subtitle1\\">sidebar.distribution.title</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1mms18p-DistListItem estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.file-count</b>: 7</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-e2le7v-DistChips estxrtg2\\"><span class=\\"MuiChip-label\\"><b>sidebar.distribution.license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import Avatar from '../../muiComponents/Avatar';
|
import Avatar from '../../muiComponents/Avatar';
|
||||||
@@ -12,6 +13,7 @@ import node from './img/node.png';
|
|||||||
|
|
||||||
const Engine: React.FC = () => {
|
const Engine: React.FC = () => {
|
||||||
const { packageMeta } = useContext(DetailContext);
|
const { packageMeta } = useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const engines = packageMeta?.latest?.engines;
|
const engines = packageMeta?.latest?.engines;
|
||||||
|
|
||||||
@@ -23,7 +25,7 @@ const Engine: React.FC = () => {
|
|||||||
<Grid container={true}>
|
<Grid container={true}>
|
||||||
{engines.node && (
|
{engines.node && (
|
||||||
<Grid item={true} xs={6}>
|
<Grid item={true} xs={6}>
|
||||||
<List subheader={<StyledText variant={'subtitle1'}>{'node JS'}</StyledText>}>
|
<List subheader={<StyledText variant={'subtitle1'}>{t('sidebar.engines.node-js')}</StyledText>}>
|
||||||
<EngineListItem button={true}>
|
<EngineListItem button={true}>
|
||||||
<Avatar src={node} />
|
<Avatar src={node} />
|
||||||
<ListItemText primary={engines.node} />
|
<ListItemText primary={engines.node} />
|
||||||
@@ -34,7 +36,7 @@ const Engine: React.FC = () => {
|
|||||||
|
|
||||||
{engines.npm && (
|
{engines.npm && (
|
||||||
<Grid item={true} xs={6}>
|
<Grid item={true} xs={6}>
|
||||||
<List subheader={<StyledText variant={'subtitle1'}>{'NPM version'}</StyledText>}>
|
<List subheader={<StyledText variant={'subtitle1'}>{t('sidebar.engines.npm-version')}</StyledText>}>
|
||||||
<EngineListItem button={true}>
|
<EngineListItem button={true}>
|
||||||
<Avatar src={npm} />
|
<Avatar src={npm} />
|
||||||
<ListItemText primary={engines.npm} />
|
<ListItemText primary={engines.npm} />
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<Engines /> component should render the component in default state 1`] = `"<div class=\\"MuiGrid-root MuiGrid-container\\"><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText et66bt70 MuiTypography-subtitle1\\">node JS</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-18b06t0-EngineListItem et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault\\"><svg class=\\"MuiSvgIcon-root MuiAvatar-fallback\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\\"></path></svg></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">>= 0.1.98</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText et66bt70 MuiTypography-subtitle1\\">NPM version</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-18b06t0-EngineListItem et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault\\"><svg class=\\"MuiSvgIcon-root MuiAvatar-fallback\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\\"></path></svg></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">>3</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div></div>"`;
|
exports[`<Engines /> component should render the component in default state 1`] = `"<div class=\\"MuiGrid-root MuiGrid-container\\"><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText et66bt70 MuiTypography-subtitle1\\">sidebar.engines.node-js</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-18b06t0-EngineListItem et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault\\"><svg class=\\"MuiSvgIcon-root MuiAvatar-fallback\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\\"></path></svg></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">>= 0.1.98</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-1na337r-StyledText et66bt70 MuiTypography-subtitle1\\">sidebar.engines.npm-version</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-18b06t0-EngineListItem et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault\\"><svg class=\\"MuiSvgIcon-root MuiAvatar-fallback\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\\"></path></svg></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">>3</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div></div>"`;
|
||||||
|
|||||||
@@ -1,53 +1,38 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation, Trans } from 'react-i18next';
|
||||||
|
|
||||||
import { goToVerdaccioWebsite } from '../../utils/windows';
|
import { goToVerdaccioWebsite } from '../../utils/windows';
|
||||||
|
|
||||||
import { Wrapper, Left, Right, Earth, Flags, Love, Flag, Logo, Inner, ToolTip } from './styles';
|
import { Wrapper, Left, Right, Earth, Flags, Love, Flag, Logo, Inner, ToolTip } from './styles';
|
||||||
|
|
||||||
const renderTooltip = (): JSX.Element => (
|
/* eslint-disable react/jsx-key */
|
||||||
<ToolTip>
|
const Footer: React.FC = () => {
|
||||||
<Earth name="earth" size="md" />
|
const { t } = useTranslation();
|
||||||
<Flags>
|
|
||||||
<Flag name="spain" size="md" />
|
|
||||||
<Flag name="nicaragua" size="md" />
|
|
||||||
<Flag name="india" size="md" />
|
|
||||||
<Flag name="brazil" size="md" />
|
|
||||||
<Flag name="china" size="md" />
|
|
||||||
<Flag name="austria" size="md" />
|
|
||||||
</Flags>
|
|
||||||
</ToolTip>
|
|
||||||
);
|
|
||||||
const POWERED_LABEL = 'Powered by';
|
|
||||||
const MADEWITH_LABEL = ' Made with';
|
|
||||||
const ON_LABEL = 'on';
|
|
||||||
const HEARTH_EMOJI = '♥';
|
|
||||||
|
|
||||||
const renderRight = (version = window.VERDACCIO_VERSION): JSX.Element => {
|
|
||||||
return (
|
return (
|
||||||
<Right>
|
<Wrapper>
|
||||||
{POWERED_LABEL}
|
<Inner>
|
||||||
<Logo img={true} name="verdaccio" onClick={goToVerdaccioWebsite} pointer={true} size="md" />
|
<Left>
|
||||||
{`/ ${version}`}
|
<Trans components={[<Love />]} i18nKey="footer.made-with-love-on" />
|
||||||
</Right>
|
<ToolTip>
|
||||||
|
<Earth name="earth" size="md" />
|
||||||
|
<Flags>
|
||||||
|
<Flag name="spain" size="md" />
|
||||||
|
<Flag name="nicaragua" size="md" />
|
||||||
|
<Flag name="india" size="md" />
|
||||||
|
<Flag name="brazil" size="md" />
|
||||||
|
<Flag name="china" size="md" />
|
||||||
|
<Flag name="austria" size="md" />
|
||||||
|
</Flags>
|
||||||
|
</ToolTip>
|
||||||
|
</Left>
|
||||||
|
<Right>
|
||||||
|
{t('footer.powered-by')}
|
||||||
|
<Logo img={true} name="verdaccio" onClick={goToVerdaccioWebsite} pointer={true} size="md" />
|
||||||
|
{`/ ${window.VERDACCIO_VERSION}`}
|
||||||
|
</Right>
|
||||||
|
</Inner>
|
||||||
|
</Wrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderLeft = (): JSX.Element => (
|
|
||||||
<Left>
|
|
||||||
{MADEWITH_LABEL}
|
|
||||||
<Love>{HEARTH_EMOJI}</Love>
|
|
||||||
{ON_LABEL}
|
|
||||||
{renderTooltip()}
|
|
||||||
</Left>
|
|
||||||
);
|
|
||||||
|
|
||||||
const Footer: React.FC = () => (
|
|
||||||
<Wrapper>
|
|
||||||
<Inner>
|
|
||||||
{renderLeft()}
|
|
||||||
{renderRight()}
|
|
||||||
</Inner>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default Footer;
|
export default Footer;
|
||||||
|
|||||||
@@ -167,13 +167,13 @@ exports[`<Footer /> component should load the initial state of Footer component
|
|||||||
<div
|
<div
|
||||||
class="emotion-27 emotion-28"
|
class="emotion-27 emotion-28"
|
||||||
>
|
>
|
||||||
Made with
|
Made with
|
||||||
<span
|
<span
|
||||||
class="emotion-0 emotion-1"
|
class="emotion-0 emotion-1"
|
||||||
>
|
>
|
||||||
♥
|
♥
|
||||||
</span>
|
</span>
|
||||||
on
|
on
|
||||||
<span
|
<span
|
||||||
class="emotion-25 emotion-26"
|
class="emotion-25 emotion-26"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import styled from '@emotion/styled';
|
|||||||
import Icon from '../Icon/Icon';
|
import Icon from '../Icon/Icon';
|
||||||
import { Theme } from '../../design-tokens/theme';
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
export const Wrapper = styled('div')<{ theme?: Theme }>(props => ({
|
export const Wrapper = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
background: props.theme && props.theme.palette.snow,
|
background: theme?.palette.type === 'dark' ? theme?.palette.primary.main : theme?.palette.snow,
|
||||||
borderTop: `1px solid ${props.theme && props.theme.palette.greyGainsboro}`,
|
borderTop: `1px solid ${theme?.palette.greyGainsboro}`,
|
||||||
color: props.theme && props.theme.palette.nobel01,
|
color: theme?.palette.type === 'dark' ? theme?.palette.white : theme?.palette.nobel01,
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
padding: '20px',
|
padding: '20px',
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { BrowserRouter as Router } from 'react-router-dom';
|
|||||||
|
|
||||||
import { render, fireEvent, waitForElement, waitForElementToBeRemoved } from '../../utils/test-react-testing-library';
|
import { render, fireEvent, waitForElement, waitForElementToBeRemoved } from '../../utils/test-react-testing-library';
|
||||||
import { AppContextProvider } from '../../App';
|
import { AppContextProvider } from '../../App';
|
||||||
|
import translationEN from '../../../i18n/translations/en-US.json';
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ describe('<Header /> component with logged in state', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should open login dialog', async () => {
|
test('should open login dialog', async () => {
|
||||||
const { getByText } = render(
|
const { getByTestId } = render(
|
||||||
<Router>
|
<Router>
|
||||||
<AppContextProvider>
|
<AppContextProvider>
|
||||||
<Header />
|
<Header />
|
||||||
@@ -52,9 +53,9 @@ describe('<Header /> component with logged in state', () => {
|
|||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|
||||||
const loginBtn = getByText('Login');
|
const loginBtn = getByTestId('header--button-login');
|
||||||
fireEvent.click(loginBtn);
|
fireEvent.click(loginBtn);
|
||||||
const loginDialog = await waitForElement(() => getByText('Sign in'));
|
const loginDialog = await waitForElement(() => getByTestId('login--dialog'));
|
||||||
expect(loginDialog).toBeTruthy();
|
expect(loginDialog).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@ describe('<Header /> component with logged in state', () => {
|
|||||||
fireEvent.click(infoBtn);
|
fireEvent.click(infoBtn);
|
||||||
|
|
||||||
// wait for Close's button of registrationInfo modal appearance and return the element
|
// wait for Close's button of registrationInfo modal appearance and return the element
|
||||||
const closeBtn = await waitForElement(() => getByText('CLOSE'));
|
const closeBtn = await waitForElement(() => getByText(translationEN.button.close));
|
||||||
fireEvent.click(closeBtn);
|
fireEvent.click(closeBtn);
|
||||||
|
|
||||||
const hasRegistrationInfoModalBeenRemoved = await waitForElementToBeRemoved(() =>
|
const hasRegistrationInfoModalBeenRemoved = await waitForElementToBeRemoved(() =>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useState, useContext } from 'react';
|
import React, { useState, useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import storage from '../../utils/storage';
|
import storage from '../../utils/storage';
|
||||||
import { getRegistryURL } from '../../utils/url';
|
import { getRegistryURL } from '../../utils/url';
|
||||||
@@ -18,17 +19,17 @@ interface Props {
|
|||||||
|
|
||||||
/* eslint-disable react/jsx-no-bind*/
|
/* eslint-disable react/jsx-no-bind*/
|
||||||
const Header: React.FC<Props> = ({ withoutSearch }) => {
|
const Header: React.FC<Props> = ({ withoutSearch }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const appContext = useContext(AppContext);
|
const appContext = useContext(AppContext);
|
||||||
const [isInfoDialogOpen, setOpenInfoDialog] = useState();
|
const [isInfoDialogOpen, setOpenInfoDialog] = useState();
|
||||||
const [showMobileNavBar, setShowMobileNavBar] = useState();
|
const [showMobileNavBar, setShowMobileNavBar] = useState();
|
||||||
const [showLoginModal, setShowLoginModal] = useState(false);
|
const [showLoginModal, setShowLoginModal] = useState(false);
|
||||||
|
|
||||||
if (!appContext) {
|
if (!appContext) {
|
||||||
throw Error('The app Context was not correct used');
|
throw Error(t('app-context-not-correct-used'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user, scope, setUser } = appContext;
|
const { user, scope, setUser } = appContext;
|
||||||
const logo = window.VERDACCIO_LOGO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logouts user
|
* Logouts user
|
||||||
@@ -44,7 +45,7 @@ const Header: React.FC<Props> = ({ withoutSearch }) => {
|
|||||||
<>
|
<>
|
||||||
<NavBar data-testid="header" position="static">
|
<NavBar data-testid="header" position="static">
|
||||||
<InnerNavBar>
|
<InnerNavBar>
|
||||||
<HeaderLeft logo={logo} />
|
<HeaderLeft />
|
||||||
<HeaderRight
|
<HeaderRight
|
||||||
onLogout={handleLogout}
|
onLogout={handleLogout}
|
||||||
onOpenRegistryInfoDialog={() => setOpenInfoDialog(true)}
|
onOpenRegistryInfoDialog={() => setOpenInfoDialog(true)}
|
||||||
@@ -67,7 +68,7 @@ const Header: React.FC<Props> = ({ withoutSearch }) => {
|
|||||||
<Search />
|
<Search />
|
||||||
</InnerMobileNavBar>
|
</InnerMobileNavBar>
|
||||||
<Button color="inherit" onClick={() => setShowMobileNavBar(false)}>
|
<Button color="inherit" onClick={() => setShowMobileNavBar(false)}>
|
||||||
{'Cancel'}
|
{t('button.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
</MobileNavBar>
|
</MobileNavBar>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Label from '../Label';
|
import Label from '../Label';
|
||||||
|
|
||||||
@@ -8,11 +9,14 @@ interface Props {
|
|||||||
username: string;
|
username: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderGreetings: React.FC<Props> = ({ username }) => (
|
const HeaderGreetings: React.FC<Props> = ({ username }) => {
|
||||||
<>
|
const { t } = useTranslation();
|
||||||
<Greetings>{'Hi,'}</Greetings>
|
return (
|
||||||
<Label capitalize={true} data-testid="greetings-label" text={username} weight="bold" />
|
<>
|
||||||
</>
|
<Greetings>{t('header.greetings')}</Greetings>
|
||||||
);
|
<Label capitalize={true} data-testid="greetings-label" text={username} weight="bold" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default HeaderGreetings;
|
export default HeaderGreetings;
|
||||||
|
|||||||
@@ -3,23 +3,22 @@ import styled from '@emotion/styled';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import Search from '../Search/';
|
import Search from '../Search/';
|
||||||
|
import Logo from '../Logo';
|
||||||
|
|
||||||
import HeaderLogo from './HeaderLogo';
|
|
||||||
import { LeftSide, SearchWrapper } from './styles';
|
import { LeftSide, SearchWrapper } from './styles';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
withoutSearch?: boolean;
|
withoutSearch?: boolean;
|
||||||
logo?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledLink = styled(Link)({
|
const StyledLink = styled(Link)({
|
||||||
marginRight: '1em',
|
marginRight: '1em',
|
||||||
});
|
});
|
||||||
|
|
||||||
const HeaderLeft: React.FC<Props> = ({ withoutSearch = false, logo }) => (
|
const HeaderLeft: React.FC<Props> = ({ withoutSearch = false }) => (
|
||||||
<LeftSide>
|
<LeftSide>
|
||||||
<StyledLink to={'/'}>
|
<StyledLink to={'/'}>
|
||||||
<HeaderLogo logo={logo} />
|
<Logo />
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
{!withoutSearch && (
|
{!withoutSearch && (
|
||||||
<SearchWrapper>
|
<SearchWrapper>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import Logo from '../Logo';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
logo?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const HeaderLogo: React.FC<Props> = ({ logo }) => {
|
|
||||||
if (logo) {
|
|
||||||
const Wrapper = styled('div')({
|
|
||||||
fontSize: 0,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<Wrapper>
|
|
||||||
<img alt="logo" height="40px" src={logo} />
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Logo />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default HeaderLogo;
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { MouseEvent } from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import AccountCircle from '@material-ui/icons/AccountCircle';
|
import AccountCircle from '@material-ui/icons/AccountCircle';
|
||||||
|
|
||||||
import IconButton from '../../muiComponents/IconButton';
|
import IconButton from '../../muiComponents/IconButton';
|
||||||
@@ -23,35 +24,38 @@ const HeaderMenu: React.FC<Props> = ({
|
|||||||
anchorEl,
|
anchorEl,
|
||||||
onLoggedInMenu,
|
onLoggedInMenu,
|
||||||
onLoggedInMenuClose,
|
onLoggedInMenuClose,
|
||||||
}) => (
|
}) => {
|
||||||
<>
|
const { t } = useTranslation();
|
||||||
<IconButton
|
return (
|
||||||
color="inherit"
|
<>
|
||||||
data-testid="header--menu-accountcircle"
|
<IconButton
|
||||||
id="header--button-account"
|
color="inherit"
|
||||||
onClick={onLoggedInMenu}>
|
data-testid="header--menu-accountcircle"
|
||||||
<AccountCircle />
|
id="header--button-account"
|
||||||
</IconButton>
|
onClick={onLoggedInMenu}>
|
||||||
<Menu
|
<AccountCircle />
|
||||||
anchorEl={anchorEl}
|
</IconButton>
|
||||||
anchorOrigin={{
|
<Menu
|
||||||
vertical: 'top',
|
anchorEl={anchorEl}
|
||||||
horizontal: 'right',
|
anchorOrigin={{
|
||||||
}}
|
vertical: 'top',
|
||||||
onClose={onLoggedInMenuClose}
|
horizontal: 'right',
|
||||||
open={isMenuOpen}
|
}}
|
||||||
transformOrigin={{
|
onClose={onLoggedInMenuClose}
|
||||||
vertical: 'top',
|
open={isMenuOpen}
|
||||||
horizontal: 'right',
|
transformOrigin={{
|
||||||
}}>
|
vertical: 'top',
|
||||||
<MenuItem disabled={true}>
|
horizontal: 'right',
|
||||||
<HeaderGreetings username={username} />
|
}}>
|
||||||
</MenuItem>
|
<MenuItem disabled={true}>
|
||||||
<MenuItem button={true} data-testid="header--button-logout" id="header--button-logout" onClick={onLogout}>
|
<HeaderGreetings username={username} />
|
||||||
{'Logout'}
|
</MenuItem>
|
||||||
</MenuItem>
|
<MenuItem button={true} data-testid="header--button-logout" id="header--button-logout" onClick={onLogout}>
|
||||||
</Menu>
|
{t('button.logout')}
|
||||||
</>
|
</MenuItem>
|
||||||
);
|
</Menu>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default HeaderMenu;
|
export default HeaderMenu;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { useState, useEffect, MouseEvent } from 'react';
|
import React, { useState, useEffect, useContext, MouseEvent } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Button from '../../muiComponents/Button';
|
import Button from '../../muiComponents/Button';
|
||||||
|
import ThemeContext from '../../design-tokens/ThemeContext';
|
||||||
|
|
||||||
import { RightSide } from './styles';
|
import { RightSide } from './styles';
|
||||||
import HeaderToolTip from './HeaderToolTip';
|
import HeaderToolTip from './HeaderToolTip';
|
||||||
@@ -23,9 +25,16 @@ const HeaderRight: React.FC<Props> = ({
|
|||||||
onToggleMobileNav,
|
onToggleMobileNav,
|
||||||
onOpenRegistryInfoDialog,
|
onOpenRegistryInfoDialog,
|
||||||
}) => {
|
}) => {
|
||||||
|
const themeContext = useContext(ThemeContext);
|
||||||
const [anchorEl, setAnchorEl] = useState();
|
const [anchorEl, setAnchorEl] = useState();
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState();
|
const [isMenuOpen, setIsMenuOpen] = useState();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
if (!themeContext) {
|
||||||
|
throw Error(t('theme-context-not-correct-used'));
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsMenuOpen(Boolean(anchorEl));
|
setIsMenuOpen(Boolean(anchorEl));
|
||||||
}, [anchorEl]);
|
}, [anchorEl]);
|
||||||
@@ -52,13 +61,25 @@ const HeaderRight: React.FC<Props> = ({
|
|||||||
onToggleLogin();
|
onToggleLogin();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleToggleDarkLightMode = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
themeContext.setIsDarkMode(!themeContext.isDarkMode);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RightSide data-testid="header-right">
|
<RightSide data-testid="header-right">
|
||||||
{!withoutSearch && (
|
{!withoutSearch && (
|
||||||
<HeaderToolTip onClick={onToggleMobileNav} title={'Search packages'} tooltipIconType={'search'} />
|
<HeaderToolTip onClick={onToggleMobileNav} title={t('search.packages')} tooltipIconType={'search'} />
|
||||||
)}
|
)}
|
||||||
<HeaderToolTip title={'Documentation'} tooltipIconType={'help'} />
|
<HeaderToolTip title={t('header.documentation')} tooltipIconType={'help'} />
|
||||||
<HeaderToolTip onClick={onOpenRegistryInfoDialog} title={'Registry Information'} tooltipIconType={'info'} />
|
<HeaderToolTip onClick={onOpenRegistryInfoDialog} title={t('header.registry-info')} tooltipIconType={'info'} />
|
||||||
|
<HeaderToolTip
|
||||||
|
onClick={handleToggleDarkLightMode}
|
||||||
|
title={t('header.documentation')}
|
||||||
|
tooltipIconType={themeContext.isDarkMode ? 'dark-mode' : 'light-mode'}
|
||||||
|
/>
|
||||||
|
|
||||||
{username ? (
|
{username ? (
|
||||||
<HeaderMenu
|
<HeaderMenu
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
@@ -70,7 +91,7 @@ const HeaderRight: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Button color="inherit" data-testid="header--button-login" onClick={handleToggleLogin}>
|
<Button color="inherit" data-testid="header--button-login" onClick={handleToggleLogin}>
|
||||||
{'Login'}
|
{t('button.login')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</RightSide>
|
</RightSide>
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ import React, { forwardRef } from 'react';
|
|||||||
import Info from '@material-ui/icons/Info';
|
import Info from '@material-ui/icons/Info';
|
||||||
import Help from '@material-ui/icons/Help';
|
import Help from '@material-ui/icons/Help';
|
||||||
import Search from '@material-ui/icons/Search';
|
import Search from '@material-ui/icons/Search';
|
||||||
|
import NightsStay from '@material-ui/icons/NightsStay';
|
||||||
|
import WbSunny from '@material-ui/icons/WbSunny';
|
||||||
|
|
||||||
import IconButton from '../../muiComponents/IconButton';
|
import IconButton from '../../muiComponents/IconButton';
|
||||||
|
|
||||||
import { IconSearchButton, StyledLink } from './styles';
|
import { IconSearchButton, StyledLink } from './styles';
|
||||||
|
|
||||||
export type TooltipIconType = 'search' | 'help' | 'info';
|
export type TooltipIconType = 'search' | 'help' | 'info' | 'dark-mode' | 'light-mode';
|
||||||
interface Props {
|
interface Props {
|
||||||
tooltipIconType: TooltipIconType;
|
tooltipIconType: TooltipIconType;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
@@ -50,6 +52,21 @@ const HeaderToolTipIcon = forwardRef<HeaderToolTipIconRef, Props>(function Heade
|
|||||||
<Search />
|
<Search />
|
||||||
</IconSearchButton>
|
</IconSearchButton>
|
||||||
);
|
);
|
||||||
|
case 'dark-mode':
|
||||||
|
// todo(Priscila): Add Zoom transition effect
|
||||||
|
return (
|
||||||
|
<IconButton color="inherit" onClick={onClick} ref={ref}>
|
||||||
|
<NightsStay />
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'light-mode':
|
||||||
|
// todo(Priscila): Add Zoom transition effect
|
||||||
|
return (
|
||||||
|
<IconButton color="inherit" onClick={onClick} ref={ref}>
|
||||||
|
<WbSunny />
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,6 +302,30 @@ exports[`<Header /> component with logged in state should load the component in
|
|||||||
class="MuiTouchRipple-root"
|
class="MuiTouchRipple-root"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiIconButton-label"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
focusable="false"
|
||||||
|
role="presentation"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
|
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
|
||||||
data-testid="header--menu-accountcircle"
|
data-testid="header--menu-accountcircle"
|
||||||
@@ -635,6 +659,30 @@ exports[`<Header /> component with logged in state should load the component in
|
|||||||
class="MuiTouchRipple-root"
|
class="MuiTouchRipple-root"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiIconButton-label"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
focusable="false"
|
||||||
|
role="presentation"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit"
|
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit"
|
||||||
data-testid="header--button-login"
|
data-testid="header--button-login"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { getRegistryURL } from '../../utils/url';
|
import { getRegistryURL } from '../../utils/url';
|
||||||
import CopyToClipBoard from '../CopyToClipBoard';
|
import CopyToClipBoard from '../CopyToClipBoard';
|
||||||
@@ -24,23 +25,24 @@ function renderHeadingClipboardSegments(title: string, text: string): React.Reac
|
|||||||
|
|
||||||
const Help: React.FC = () => {
|
const Help: React.FC = () => {
|
||||||
const registryUrl = getRegistryURL();
|
const registryUrl = getRegistryURL();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card id="help-card">
|
<Card id="help-card">
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography component="h2" gutterBottom={true} id={COMPONENT_HELP_ID} variant="h5">
|
<Typography component="h2" gutterBottom={true} id={COMPONENT_HELP_ID} variant="h5">
|
||||||
{HELP_TITLE}
|
{t('help.title')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<HelpTitle color="textSecondary" gutterBottom={true}>
|
<HelpTitle color="textSecondary" gutterBottom={true}>
|
||||||
{'To publish your first package just:'}
|
{t('help.sub-title')}
|
||||||
</HelpTitle>
|
</HelpTitle>
|
||||||
{renderHeadingClipboardSegments('1. Login', `npm adduser --registry ${registryUrl}`)}
|
{renderHeadingClipboardSegments(t('help.first-step'), t('help.first-step-command-line', { registryUrl }))}
|
||||||
{renderHeadingClipboardSegments('2. Publish', `npm publish --registry ${registryUrl}`)}
|
{renderHeadingClipboardSegments(t('help.second-step'), t('help.second-step-command-line', { registryUrl }))}
|
||||||
<Text variant="body2">{'3. Refresh this page.'}</Text>
|
<Text variant="body2">{t('help.third-step')}</Text>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardActions>
|
<CardActions>
|
||||||
<Button color="primary" href="https://verdaccio.org/docs/en/installation" size="small">
|
<Button color="primary" href="https://verdaccio.org/docs/en/installation" size="small">
|
||||||
{'Learn More'}
|
{t('button.learn-more')}
|
||||||
</Button>
|
</Button>
|
||||||
</CardActions>
|
</CardActions>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ exports[`<Help /> component should load the component in default state 1`] = `
|
|||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiIconButton-root emotion-4 emotion-5"
|
class="MuiButtonBase-root MuiIconButton-root emotion-4 emotion-5"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
title="Copy to Clipboard"
|
title="Copy to clipboard"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -107,7 +107,7 @@ exports[`<Help /> component should load the component in default state 1`] = `
|
|||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiIconButton-root emotion-4 emotion-5"
|
class="MuiButtonBase-root MuiIconButton-root emotion-4 emotion-5"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
title="Copy to Clipboard"
|
title="Copy to clipboard"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import Text from '../../muiComponents/Text';
|
import Text from '../../muiComponents/Text';
|
||||||
@@ -14,6 +15,7 @@ const StyledText = styled(Text)<{ theme?: Theme }>(props => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const Install: React.FC = () => {
|
const Install: React.FC = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const detailContext = useContext(DetailContext);
|
const detailContext = useContext(DetailContext);
|
||||||
|
|
||||||
const { packageMeta, packageName } = detailContext;
|
const { packageMeta, packageName } = detailContext;
|
||||||
@@ -23,7 +25,9 @@ const Install: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List data-testid={'installList'} subheader={<StyledText variant={'subtitle1'}>{'Installation'}</StyledText>}>
|
<List
|
||||||
|
data-testid={'installList'}
|
||||||
|
subheader={<StyledText variant={'subtitle1'}>{t('sidebar.installation.title')}</StyledText>}>
|
||||||
<InstallListItem dependencyManager={DependencyManager.NPM} packageName={packageName} />
|
<InstallListItem dependencyManager={DependencyManager.NPM} packageName={packageName} />
|
||||||
<InstallListItem dependencyManager={DependencyManager.YARN} packageName={packageName} />
|
<InstallListItem dependencyManager={DependencyManager.YARN} packageName={packageName} />
|
||||||
<InstallListItem dependencyManager={DependencyManager.PNPM} packageName={packageName} />
|
<InstallListItem dependencyManager={DependencyManager.PNPM} packageName={packageName} />
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import CopyToClipBoard from '../CopyToClipBoard';
|
import CopyToClipBoard from '../CopyToClipBoard';
|
||||||
import Avatar from '../../muiComponents/Avatar';
|
import Avatar from '../../muiComponents/Avatar';
|
||||||
@@ -43,14 +44,16 @@ interface Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }) => {
|
const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
switch (dependencyManager) {
|
switch (dependencyManager) {
|
||||||
case DependencyManager.NPM:
|
case DependencyManager.NPM:
|
||||||
return (
|
return (
|
||||||
<InstallItem button={true} data-testid={'installListItem-npm'}>
|
<InstallItem button={true} data-testid={'installListItem-npm'}>
|
||||||
<PackageMangerAvatar alt="npm" src={npmLogo} />
|
<PackageMangerAvatar alt="npm" src={npmLogo} />
|
||||||
<InstallListItemText
|
<InstallListItemText
|
||||||
primary={<CopyToClipBoard text={`npm install ${packageName}`} />}
|
primary={<CopyToClipBoard text={t('sidebar.installation.install-using-npm-command', { packageName })} />}
|
||||||
secondary={'Install using npm'}
|
secondary={t('sidebar.installation.install-using-npm')}
|
||||||
/>
|
/>
|
||||||
</InstallItem>
|
</InstallItem>
|
||||||
);
|
);
|
||||||
@@ -59,8 +62,8 @@ const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }
|
|||||||
<InstallItem button={true} data-testid={'installListItem-yarn'}>
|
<InstallItem button={true} data-testid={'installListItem-yarn'}>
|
||||||
<PackageMangerAvatar alt="yarn" src={yarnLogo} />
|
<PackageMangerAvatar alt="yarn" src={yarnLogo} />
|
||||||
<InstallListItemText
|
<InstallListItemText
|
||||||
primary={<CopyToClipBoard text={`yarn add ${packageName}`} />}
|
primary={<CopyToClipBoard text={t('sidebar.installation.install-using-yarn-command', { packageName })} />}
|
||||||
secondary={'Install using yarn'}
|
secondary={t('sidebar.installation.install-using-yarn')}
|
||||||
/>
|
/>
|
||||||
</InstallItem>
|
</InstallItem>
|
||||||
);
|
);
|
||||||
@@ -69,8 +72,8 @@ const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }
|
|||||||
<InstallItem button={true} data-testid={'installListItem-pnpm'}>
|
<InstallItem button={true} data-testid={'installListItem-pnpm'}>
|
||||||
<PackageMangerAvatar alt={'pnpm'} src={pnpmLogo} />
|
<PackageMangerAvatar alt={'pnpm'} src={pnpmLogo} />
|
||||||
<InstallListItemText
|
<InstallListItemText
|
||||||
primary={<CopyToClipBoard text={`pnpm install ${packageName}`} />}
|
primary={<CopyToClipBoard text={t('sidebar.installation.install-using-pnpm-command', { packageName })} />}
|
||||||
secondary={'Install using pnpm'}
|
secondary={t('sidebar.installation.install-using-pnpm')}
|
||||||
/>
|
/>
|
||||||
</InstallItem>
|
</InstallItem>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ exports[`<Install /> renders correctly 1`] = `
|
|||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiIconButton-root emotion-6 emotion-7"
|
class="MuiButtonBase-root MuiIconButton-root emotion-6 emotion-7"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
title="Copy to Clipboard"
|
title="Copy to clipboard"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -161,7 +161,7 @@ exports[`<Install /> renders correctly 1`] = `
|
|||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiIconButton-root emotion-6 emotion-7"
|
class="MuiButtonBase-root MuiIconButton-root emotion-6 emotion-7"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
title="Copy to Clipboard"
|
title="Copy to clipboard"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -228,7 +228,7 @@ exports[`<Install /> renders correctly 1`] = `
|
|||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiIconButton-root emotion-6 emotion-7"
|
class="MuiButtonBase-root MuiIconButton-root emotion-6 emotion-7"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
title="Copy to Clipboard"
|
title="Copy to clipboard"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
|
||||||
import Text, { TextProps } from '../../muiComponents/Text';
|
import Text, { TextProps } from '../../muiComponents/Text';
|
||||||
@@ -8,6 +8,7 @@ interface Props extends Pick<TextProps, 'variant'> {
|
|||||||
className?: string;
|
className?: string;
|
||||||
to: string;
|
to: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LinkRef = HTMLAnchorElement;
|
type LinkRef = HTMLAnchorElement;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
export const Wrapper = styled('div')({
|
export const Wrapper = styled('div')({
|
||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
top: '50%',
|
top: '50%',
|
||||||
@@ -7,9 +9,9 @@ export const Wrapper = styled('div')({
|
|||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Badge = styled('div')({
|
export const Badge = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
margin: '0 0 30px 0',
|
margin: '0 0 30px 0',
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
boxShadow: '0 10px 20px 0 rgba(69, 58, 100, 0.2)',
|
boxShadow: '0 10px 20px 0 rgba(69, 58, 100, 0.2)',
|
||||||
background: '#f7f8f6',
|
background: theme?.palette.type === 'dark' ? theme?.palette.black : '#f7f8f6',
|
||||||
});
|
}));
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { render, waitForElement, fireEvent, waitForElementToBeRemoved } from '../../utils/test-react-testing-library';
|
import { render, waitForElement, fireEvent } from '../../utils/test-react-testing-library';
|
||||||
import AppContext, { AppContextProps } from '../../App/AppContext';
|
import AppContext, { AppContextProps } from '../../App/AppContext';
|
||||||
import api from '../../utils/api';
|
import api from '../../utils/api';
|
||||||
|
import translationEN from '../../../i18n/translations/en-US.json';
|
||||||
|
|
||||||
import LoginDialog from './LoginDialog';
|
import LoginDialog from './LoginDialog';
|
||||||
|
|
||||||
@@ -35,13 +36,13 @@ describe('<LoginDialog /> component', () => {
|
|||||||
onClose: jest.fn(),
|
onClose: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const { getByText } = render(
|
const { getByTestId } = render(
|
||||||
<AppContext.Provider value={appContextValue}>
|
<AppContext.Provider value={appContextValue}>
|
||||||
<LoginDialog onClose={props.onClose} open={props.open} />
|
<LoginDialog onClose={props.onClose} open={props.open} />
|
||||||
</AppContext.Provider>
|
</AppContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
const loginDialogHeading = await waitForElement(() => getByText('Sign in'));
|
const loginDialogHeading = await waitForElement(() => getByTestId('login-dialog-form-login-button'));
|
||||||
expect(loginDialogHeading).toBeTruthy();
|
expect(loginDialogHeading).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useState, useContext, useCallback } from 'react';
|
import React, { useState, useContext, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { makeLogin } from '../../utils/login';
|
import { makeLogin } from '../../utils/login';
|
||||||
import storage from '../../utils/storage';
|
import storage from '../../utils/storage';
|
||||||
@@ -16,10 +17,11 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LoginDialog: React.FC<Props> = ({ onClose, open = false }) => {
|
const LoginDialog: React.FC<Props> = ({ onClose, open = false }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const appContext = useContext(AppContext);
|
const appContext = useContext(AppContext);
|
||||||
|
|
||||||
if (!appContext) {
|
if (!appContext) {
|
||||||
throw Error('The app Context was not correct used');
|
throw Error(t('app-context-not-correct-used'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState();
|
||||||
@@ -43,7 +45,7 @@ const LoginDialog: React.FC<Props> = ({ onClose, open = false }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog fullWidth={true} id="login--dialog" maxWidth="sm" onClose={onClose} open={open}>
|
<Dialog data-testid="login--dialog" fullWidth={true} id="login--dialog" maxWidth="sm" onClose={onClose} open={open}>
|
||||||
<LoginDialogCloseButton onClose={onClose} />
|
<LoginDialogCloseButton onClose={onClose} />
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<LoginDialogHeader />
|
<LoginDialogHeader />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import CloseIcon from '@material-ui/icons/Close';
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import DialogTitle from '../../muiComponents/DialogTitle';
|
import DialogTitle from '../../muiComponents/DialogTitle';
|
||||||
import IconButton from '../../muiComponents/IconButton';
|
import IconButton from '../../muiComponents/IconButton';
|
||||||
@@ -17,12 +18,15 @@ interface Props {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoginDialogCloseButton: React.FC<Props> = ({ onClose }) => (
|
const LoginDialogCloseButton: React.FC<Props> = ({ onClose }) => {
|
||||||
<DialogTitle>
|
const { t } = useTranslation();
|
||||||
<StyledIconButton data-testid="close-login-dialog-button" onClick={onClose}>
|
return (
|
||||||
<CloseIcon titleAccess="Close Dialog" />
|
<DialogTitle>
|
||||||
</StyledIconButton>
|
<StyledIconButton data-testid="close-login-dialog-button" onClick={onClose}>
|
||||||
</DialogTitle>
|
<CloseIcon titleAccess={t('button.close')} />
|
||||||
);
|
</StyledIconButton>
|
||||||
|
</DialogTitle>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default LoginDialogCloseButton;
|
export default LoginDialogCloseButton;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import useForm from 'react-hook-form/dist/react-hook-form.ie11';
|
import useForm from 'react-hook-form/dist/react-hook-form.ie11';
|
||||||
|
|
||||||
import TextField from '../../muiComponents/TextField';
|
import TextField from '../../muiComponents/TextField';
|
||||||
@@ -28,6 +29,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LoginDialogForm = memo(({ onSubmit, error }: Props) => {
|
const LoginDialogForm = memo(({ onSubmit, error }: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
errors,
|
errors,
|
||||||
@@ -48,13 +50,13 @@ const LoginDialogForm = memo(({ onSubmit, error }: Props) => {
|
|||||||
helperText={errors.username?.message}
|
helperText={errors.username?.message}
|
||||||
id="login--dialog-username"
|
id="login--dialog-username"
|
||||||
inputRef={register({
|
inputRef={register({
|
||||||
required: { value: true, message: 'This field is required' },
|
required: { value: true, message: t('form-validation.required-field') },
|
||||||
minLength: { value: 2, message: 'This field required the min length of 2' },
|
minLength: { value: 2, message: t('form-validation.required-min-length', { length: 2 }) },
|
||||||
})}
|
})}
|
||||||
label="Username"
|
label={t('form.username')}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
name="username"
|
name="username"
|
||||||
placeholder="Your username"
|
placeholder={t('form-placeholder.username')}
|
||||||
required={true}
|
required={true}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
@@ -65,13 +67,13 @@ const LoginDialogForm = memo(({ onSubmit, error }: Props) => {
|
|||||||
helperText={errors.password?.message}
|
helperText={errors.password?.message}
|
||||||
id="login--dialog-password"
|
id="login--dialog-password"
|
||||||
inputRef={register({
|
inputRef={register({
|
||||||
required: { value: true, message: 'This field is required' },
|
required: { value: true, message: t('form-validation.required-field') },
|
||||||
minLength: { value: 2, message: 'This field required the min length of 2' },
|
minLength: { value: 2, message: t('form-validation.required-min-length', { length: 2 }) },
|
||||||
})}
|
})}
|
||||||
label="Password"
|
label={t('form.password')}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
name="password"
|
name="password"
|
||||||
placeholder="Your strong password"
|
placeholder={t('form-placeholder.password')}
|
||||||
required={true}
|
required={true}
|
||||||
type="password"
|
type="password"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -79,13 +81,14 @@ const LoginDialogForm = memo(({ onSubmit, error }: Props) => {
|
|||||||
{error && <LoginDialogFormError error={error} />}
|
{error && <LoginDialogFormError error={error} />}
|
||||||
<StyledButton
|
<StyledButton
|
||||||
color="primary"
|
color="primary"
|
||||||
|
data-testid="login-dialog-form-login-button"
|
||||||
disabled={!isValid}
|
disabled={!isValid}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
id="login--dialog-button-submit"
|
id="login--dialog-button-submit"
|
||||||
size="large"
|
size="large"
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="contained">
|
variant="contained">
|
||||||
{'Sign In'}
|
{t('button.login')}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
</StyledForm>
|
</StyledForm>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ import { Theme } from '../../design-tokens/theme';
|
|||||||
import { LoginError } from '../../utils/login';
|
import { LoginError } from '../../utils/login';
|
||||||
|
|
||||||
const StyledSnackbarContent = styled(SnackbarContent)<{ theme?: Theme }>(({ theme }) => ({
|
const StyledSnackbarContent = styled(SnackbarContent)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.error.dark,
|
backgroundColor: theme?.palette.error.dark,
|
||||||
|
color: theme?.palette.white,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledErrorIcon = styled(Error)<{ theme?: Theme }>(({ theme }) => ({
|
const StyledErrorIcon = styled(Error)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
marginRight: theme.spacing(1),
|
marginRight: theme?.spacing(1),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export interface FormValues {
|
export interface FormValues {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import LockOutlined from '@material-ui/icons/LockOutlined';
|
import LockOutlined from '@material-ui/icons/LockOutlined';
|
||||||
import CloseIcon from '@material-ui/icons/Close';
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Heading from '../../muiComponents/Heading';
|
import Heading from '../../muiComponents/Heading';
|
||||||
import Avatar from '../../muiComponents/Avatar';
|
import Avatar from '../../muiComponents/Avatar';
|
||||||
@@ -12,6 +13,7 @@ import { Theme } from '../../design-tokens/theme';
|
|||||||
const StyledAvatar = styled(Avatar)<{ theme?: Theme }>(({ theme }) => ({
|
const StyledAvatar = styled(Avatar)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
margin: theme.spacing(1),
|
margin: theme.spacing(1),
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
color: theme.palette.white,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledIconButton = styled(IconButton)<{ theme?: Theme }>(({ theme }) => ({
|
const StyledIconButton = styled(IconButton)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
@@ -26,17 +28,19 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LoginDialogHeader: React.FC<Props> = ({ onClose }) => {
|
const LoginDialogHeader: React.FC<Props> = ({ onClose }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box alignItems="center" display="flex" flexDirection="column" position="relative">
|
<Box alignItems="center" display="flex" flexDirection="column" position="relative">
|
||||||
{onClose && (
|
{onClose && (
|
||||||
<StyledIconButton aria-label="Close" onClick={onClose}>
|
<StyledIconButton aria-label={t('button.close')} onClick={onClose}>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</StyledIconButton>
|
</StyledIconButton>
|
||||||
)}
|
)}
|
||||||
<StyledAvatar>
|
<StyledAvatar>
|
||||||
<LockOutlined />
|
<LockOutlined />
|
||||||
</StyledAvatar>
|
</StyledAvatar>
|
||||||
<Heading>{'Sign in'}</Heading>
|
<Heading>{t('button.login')}</Heading>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,31 +1,52 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import logo from './img/logo.svg';
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
|
import defaultLogo from './img/logo.svg';
|
||||||
|
import blackAndWithLogo from './img/logo-black-and-white.svg';
|
||||||
|
|
||||||
export enum Size {
|
export enum Size {
|
||||||
Small = '40px',
|
Small = '40px',
|
||||||
Big = '90px',
|
Big = '90px',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logos = {
|
||||||
|
light: defaultLogo,
|
||||||
|
dark: blackAndWithLogo,
|
||||||
|
};
|
||||||
|
|
||||||
|
const logo = window.VERDACCIO_LOGO;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
size?: Size;
|
size?: Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledLogo = styled('div')<Props>(props => ({
|
const Logo: React.FC<Props> = ({ size = Size.Small }) => {
|
||||||
|
if (logo) {
|
||||||
|
return (
|
||||||
|
<ImageLogo>
|
||||||
|
<img alt="logo" height="40px" src={logo} />
|
||||||
|
</ImageLogo>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <StyledLogo size={size} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Logo;
|
||||||
|
|
||||||
|
const ImageLogo = styled('div')({
|
||||||
|
fontSize: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledLogo = styled('div')<Props & { theme?: Theme }>(({ size, theme }) => ({
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
verticalAlign: 'middle',
|
verticalAlign: 'middle',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
backgroundPosition: 'center',
|
backgroundPosition: 'center',
|
||||||
backgroundSize: 'contain',
|
backgroundSize: 'contain',
|
||||||
backgroundImage: `url(${logo})`,
|
backgroundImage: `url(${logos[theme?.palette.type]})`,
|
||||||
backgroundRepeat: ' no-repeat',
|
backgroundRepeat: ' no-repeat',
|
||||||
width: props.size,
|
width: size,
|
||||||
height: props.size,
|
height: size,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Logo: React.FC<Props> = ({ size = Size.Small }) => {
|
|
||||||
return <StyledLogo size={size} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Logo;
|
|
||||||
|
|||||||
1
src/components/Logo/img/logo-black-and-white.svg
Normal file
1
src/components/Logo/img/logo-black-and-white.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><filter x="-19.8%" y="-11.7%" width="139.6%" height="140.4%" filterUnits="objectBoundingBox" id="a"><feOffset dy="4" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="2.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646286 0" in="shadowBlurOuter1"/></filter><filter x="-33.9%" y="-50%" width="167.9%" height="272.7%" filterUnits="objectBoundingBox" id="c"><feOffset dy="4" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="2.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646286 0" in="shadowBlurOuter1"/></filter><path id="b" d="M48 16.729L32.672 47h-8.874L0 0h15.328l12.907 25.492 4.437-8.763H48z"/><path d="M35.2 11H28V8.643h8.4l1.2-2.357H32V3.929h6.8l.8-1.572H36V0h20l-5.6 11H35.2z" id="d"/></defs><g fill="none" fill-rule="evenodd"><rect fill="#000" width="100" height="100" rx="37"/><g transform="translate(22 30)"><use fill="#000" filter="url(#a)" xlink:href="#b"/><use fill-opacity=".6" fill="#FFF" xlink:href="#b"/></g><g transform="translate(22 30)"><use fill="#000" filter="url(#c)" xlink:href="#d"/><use fill="#FFF" xlink:href="#d"/></g><path fill="#FFF" d="M54.785 77H45.88L22 30h15.38L58 70.718z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,6 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Box from '../../muiComponents/Box';
|
import Box from '../../muiComponents/Box';
|
||||||
import Button from '../../muiComponents/Button';
|
import Button from '../../muiComponents/Button';
|
||||||
@@ -9,10 +10,6 @@ import { Theme } from '../../design-tokens/theme';
|
|||||||
|
|
||||||
import PackageImg from './img/package.svg';
|
import PackageImg from './img/package.svg';
|
||||||
|
|
||||||
export const NOT_FOUND_TEXT = "Sorry, we couldn't find it...";
|
|
||||||
export const LABEL_NOT_FOUND = "The page you're looking for doesn't exist.";
|
|
||||||
export const GO_TO_HOME_PAGE = 'Go to the home page';
|
|
||||||
|
|
||||||
const EmptyPackage = styled('img')({
|
const EmptyPackage = styled('img')({
|
||||||
width: '150px',
|
width: '150px',
|
||||||
margin: '0 auto',
|
margin: '0 auto',
|
||||||
@@ -25,6 +22,7 @@ const StyledHeading = styled(Heading)<{ theme?: Theme }>(props => ({
|
|||||||
|
|
||||||
const NotFound: React.FC = () => {
|
const NotFound: React.FC = () => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleGoHome = useCallback(() => {
|
const handleGoHome = useCallback(() => {
|
||||||
history.push('/');
|
history.push('/');
|
||||||
@@ -39,12 +37,12 @@ const NotFound: React.FC = () => {
|
|||||||
flexGrow={1}
|
flexGrow={1}
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
p={2}>
|
p={2}>
|
||||||
<EmptyPackage alt="404 - Page not found" src={PackageImg} />
|
<EmptyPackage alt={t('error.404.page-not-found')} src={PackageImg} />
|
||||||
<StyledHeading className="not-found-text" variant="h4">
|
<StyledHeading className="not-found-text" variant="h4">
|
||||||
{NOT_FOUND_TEXT}
|
{t('error.404.sorry-we-could-not-find-it')}
|
||||||
</StyledHeading>
|
</StyledHeading>
|
||||||
<Button onClick={handleGoHome} variant="contained">
|
<Button data-testid="not-found-go-to-home-button" onClick={handleGoHome} variant="contained">
|
||||||
{GO_TO_HOME_PAGE}
|
{t('button.go-to-the-home-page')}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { BrowserRouter as Router } from 'react-router-dom';
|
|||||||
|
|
||||||
import { render, fireEvent } from '../../utils/test-react-testing-library';
|
import { render, fireEvent } from '../../utils/test-react-testing-library';
|
||||||
|
|
||||||
import NotFound, { GO_TO_HOME_PAGE } from './NotFound';
|
import NotFound from './NotFound';
|
||||||
|
|
||||||
describe('<NotFound /> component', () => {
|
describe('<NotFound /> component', () => {
|
||||||
test('should load the component in default state', () => {
|
test('should load the component in default state', () => {
|
||||||
@@ -14,17 +14,17 @@ describe('<NotFound /> component', () => {
|
|||||||
);
|
);
|
||||||
expect(container.firstChild).toMatchSnapshot();
|
expect(container.firstChild).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('go to Home Page button click', () => {
|
|
||||||
|
test('go to Home Page button click', async () => {
|
||||||
const spy = jest.spyOn(React, 'useCallback');
|
const spy = jest.spyOn(React, 'useCallback');
|
||||||
const { getByText } = render(
|
const { getByTestId } = render(
|
||||||
<Router>
|
<Router>
|
||||||
<NotFound />
|
<NotFound />
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|
||||||
const node = getByText(GO_TO_HOME_PAGE);
|
const node = getByTestId('not-found-go-to-home-button');
|
||||||
fireEvent.click(node);
|
fireEvent.click(node);
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalled();
|
expect(spy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ exports[`<NotFound /> component should load the component in default state 1`] =
|
|||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiButton-root MuiButton-contained"
|
class="MuiButtonBase-root MuiButton-root MuiButton-contained"
|
||||||
|
data-testid="not-found-go-to-home-button"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default, NOT_FOUND_TEXT } from './NotFound';
|
export { default } from './NotFound';
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ import React from 'react';
|
|||||||
import BugReport from '@material-ui/icons/BugReport';
|
import BugReport from '@material-ui/icons/BugReport';
|
||||||
import DownloadIcon from '@material-ui/icons/CloudDownload';
|
import DownloadIcon from '@material-ui/icons/CloudDownload';
|
||||||
import HomeIcon from '@material-ui/icons/Home';
|
import HomeIcon from '@material-ui/icons/Home';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { PackageMetaInterface, Author as PackageAuthor } from '../../../types/packageMeta';
|
import { PackageMetaInterface, Author as PackageAuthor } from '../../../types/packageMeta';
|
||||||
import Tag from '../Tag';
|
import Tag from '../Tag';
|
||||||
import fileSizeSI from '../../utils/file-size';
|
import fileSizeSI from '../../utils/file-size';
|
||||||
import { formatDate, formatDateDistance } from '../../utils/package';
|
import { formatDate, formatDateDistance, getAuthorName } from '../../utils/package';
|
||||||
import Tooltip from '../../muiComponents/Tooltip';
|
import Tooltip from '../../muiComponents/Tooltip';
|
||||||
|
import Link from '../Link';
|
||||||
import { isURL } from '../../utils/url';
|
import { isURL } from '../../utils/url';
|
||||||
import { downloadTarball } from '../ActionBar';
|
import { downloadTarball } from '../ActionBar';
|
||||||
import ListItem from '../../muiComponents/ListItem';
|
import ListItem from '../../muiComponents/ListItem';
|
||||||
@@ -64,11 +66,13 @@ const Package: React.FC<PackageInterface> = ({
|
|||||||
time,
|
time,
|
||||||
version,
|
version,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const renderVersionInfo = (): React.ReactNode =>
|
const renderVersionInfo = (): React.ReactNode =>
|
||||||
version && (
|
version && (
|
||||||
<OverviewItem>
|
<OverviewItem>
|
||||||
<Icon name={'version'} />
|
<Icon name={'version'} />
|
||||||
{`v${version}`}
|
{t('package.version', { version })}
|
||||||
</OverviewItem>
|
</OverviewItem>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -77,7 +81,7 @@ const Package: React.FC<PackageInterface> = ({
|
|||||||
<Author>
|
<Author>
|
||||||
<Avatar alt={authorName} src={authorAvatar} />
|
<Avatar alt={authorName} src={authorAvatar} />
|
||||||
<Details>
|
<Details>
|
||||||
<Text text={authorName} />
|
<Text text={getAuthorName(authorName)} />
|
||||||
</Details>
|
</Details>
|
||||||
</Author>
|
</Author>
|
||||||
);
|
);
|
||||||
@@ -103,7 +107,7 @@ const Package: React.FC<PackageInterface> = ({
|
|||||||
time && (
|
time && (
|
||||||
<OverviewItem>
|
<OverviewItem>
|
||||||
<Icon name="time" />
|
<Icon name="time" />
|
||||||
<Published>{`Published on ${formatDate(time)} •`}</Published>
|
<Published>{t('package.published-on', { time: formatDate(time) })}</Published>
|
||||||
{formatDateDistance(time)}
|
{formatDateDistance(time)}
|
||||||
</OverviewItem>
|
</OverviewItem>
|
||||||
);
|
);
|
||||||
@@ -111,26 +115,26 @@ const Package: React.FC<PackageInterface> = ({
|
|||||||
const renderHomePageLink = (): React.ReactNode =>
|
const renderHomePageLink = (): React.ReactNode =>
|
||||||
homepage &&
|
homepage &&
|
||||||
isURL(homepage) && (
|
isURL(homepage) && (
|
||||||
<a href={homepage} target={'_blank'}>
|
<Link external={true} to={homepage}>
|
||||||
<Tooltip aria-label={'Homepage'} title={'Visit homepage'}>
|
<Tooltip aria-label={t('package.homepage')} title={t('package.visit-home-page')}>
|
||||||
<IconButton aria-label={'Homepage'}>
|
<IconButton aria-label={t('package.homepage')}>
|
||||||
<HomeIcon />
|
<HomeIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</a>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderBugsLink = (): React.ReactNode =>
|
const renderBugsLink = (): React.ReactNode =>
|
||||||
bugs &&
|
bugs &&
|
||||||
bugs.url &&
|
bugs.url &&
|
||||||
isURL(bugs.url) && (
|
isURL(bugs.url) && (
|
||||||
<a href={bugs.url} target={'_blank'}>
|
<Link external={true} to={bugs.url}>
|
||||||
<Tooltip aria-label={'Bugs'} title={'Open an issue'}>
|
<Tooltip aria-label={t('package.bugs')} title={t('package.open-an-issue')}>
|
||||||
<IconButton aria-label={'Bugs'}>
|
<IconButton aria-label={t('package.bugs')}>
|
||||||
<BugReport />
|
<BugReport />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</a>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderDownloadLink = (): React.ReactNode =>
|
const renderDownloadLink = (): React.ReactNode =>
|
||||||
@@ -138,13 +142,13 @@ const Package: React.FC<PackageInterface> = ({
|
|||||||
dist.tarball &&
|
dist.tarball &&
|
||||||
isURL(dist.tarball) && (
|
isURL(dist.tarball) && (
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
<a onClick={downloadTarball(dist.tarball.replace(`https://registry.npmjs.org/`, window.location.href))} target={'_blank'}>
|
<Link to="#" external={true} onClick={downloadTarball(dist.tarball.replace(`https://registry.npmjs.org/`, window.location.href))}>
|
||||||
<Tooltip aria-label={'Download the tar file'} title={'Download tarball'}>
|
<Tooltip aria-label={t('package.download', { what: t('package.the-tar-file') })} title={t('package.tarball')}>
|
||||||
<IconButton aria-label={'Download'}>
|
<IconButton aria-label={t('package.download')}>
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</a>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderPrimaryComponent = (): React.ReactNode => {
|
const renderPrimaryComponent = (): React.ReactNode => {
|
||||||
@@ -155,7 +159,7 @@ const Package: React.FC<PackageInterface> = ({
|
|||||||
<PackageTitle className="package-title">{packageName}</PackageTitle>
|
<PackageTitle className="package-title">{packageName}</PackageTitle>
|
||||||
</WrapperLink>
|
</WrapperLink>
|
||||||
</Grid>
|
</Grid>
|
||||||
<GridRightAligned item={true} xs={true}>
|
<GridRightAligned alignItems="center" container={true} item={true} justify="flex-end" xs={true}>
|
||||||
{renderHomePageLink()}
|
{renderHomePageLink()}
|
||||||
{renderBugsLink()}
|
{renderBugsLink()}
|
||||||
{renderDownloadLink()}
|
{renderDownloadLink()}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const OverviewItem = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
margin: '0 0 0 16px',
|
margin: '0 0 0 16px',
|
||||||
color: theme && theme.palette.greyLight2,
|
color: theme?.palette.type === 'light' ? theme?.palette.greyLight2 : theme?.palette.dodgerBlue,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
[`@media (max-width: ${theme && theme.breakPoints.medium}px)`]: {
|
[`@media (max-width: ${theme && theme.breakPoints.medium}px)`]: {
|
||||||
':nth-of-type(3)': {
|
':nth-of-type(3)': {
|
||||||
@@ -29,20 +29,20 @@ export const OverviewItem = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Icon = styled(Ico)<{ theme?: Theme }>(props => ({
|
export const Icon = styled(Ico)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
margin: '2px 10px 0 0',
|
margin: '2px 10px 0 0',
|
||||||
fill: props.theme && props.theme.palette.greyLight2,
|
fill: theme?.palette.type === 'light' ? theme?.palette.greyLight2 : theme?.palette.dodgerBlue,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Published = styled('span')<{ theme?: Theme }>(props => ({
|
export const Published = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
color: props.theme && props.theme.palette.greyLight2,
|
color: theme?.palette.type === 'light' ? theme?.palette.greyLight2 : theme?.palette.dodgerBlue,
|
||||||
margin: '0 5px 0 0',
|
margin: '0 5px 0 0',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Text = styled(Label)<{ theme?: Theme }>(props => ({
|
export const Text = styled(Label)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
fontSize: '12px',
|
fontSize: '12px',
|
||||||
fontWeight: props.theme && props.theme.fontWeight.semiBold,
|
fontWeight: theme?.fontWeight.semiBold,
|
||||||
color: props.theme && props.theme.palette.greyLight2,
|
color: theme?.palette.type === 'light' ? theme?.palette.greyLight2 : theme?.palette.dodgerBlue,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Details = styled('span')({
|
export const Details = styled('span')({
|
||||||
@@ -71,11 +71,8 @@ export const PackageTitle = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
|||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
display: 'block',
|
display: 'block',
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
color: theme && theme.palette.eclipse,
|
color: theme?.palette.type == 'dark' ? theme?.palette.white : theme?.palette.eclipse,
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
':hover': {
|
|
||||||
color: theme && theme.palette.black,
|
|
||||||
},
|
|
||||||
[`@media (max-width: ${theme && theme.breakPoints.small}px)`]: {
|
[`@media (max-width: ${theme && theme.breakPoints.small}px)`]: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
marginBottom: 8,
|
marginBottom: 8,
|
||||||
@@ -86,14 +83,15 @@ export const GridRightAligned = styled(Grid)({
|
|||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PackageList = styled(List)<{ theme?: Theme }>(props => ({
|
export const PackageList = styled(List)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
padding: '12px 0 12px 0',
|
padding: '12px 0 12px 0',
|
||||||
':hover': {
|
':hover': {
|
||||||
backgroundColor: props.theme && props.theme.palette.greyLight3,
|
backgroundColor: theme?.palette?.type == 'dark' ? theme?.palette?.primary.main : theme?.palette?.greyLight3,
|
||||||
},
|
},
|
||||||
'> :last-child': {
|
'> :last-child': {
|
||||||
paddingTop: 0,
|
paddingTop: 0,
|
||||||
},
|
},
|
||||||
|
borderRadius: 4,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const IconButton = styled(MuiIconButton)({
|
export const IconButton = styled(MuiIconButton)({
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ describe('<Readme /> component', () => {
|
|||||||
|
|
||||||
test('should dangerously set html', () => {
|
test('should dangerously set html', () => {
|
||||||
const wrapper = mount(<Readme description="<h1>This is a test string</h1>" />);
|
const wrapper = mount(<Readme description="<h1>This is a test string</h1>" />);
|
||||||
expect(wrapper.html()).toEqual('<div class="markdown-body"><h1>This is a test string</h1></div>');
|
expect(wrapper.html()).toEqual(
|
||||||
|
'<div class="markdown-body css-beaqbv-Wrapper ecnabbe0"><h1>This is a test string</h1></div>'
|
||||||
|
);
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import 'github-markdown-css';
|
import 'github-markdown-css';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
import { Props } from './types';
|
import { Props } from './types';
|
||||||
|
|
||||||
const Readme: React.FC<Props> = ({ description }) => (
|
const Readme: React.FC<Props> = ({ description }) => (
|
||||||
<div className="markdown-body" dangerouslySetInnerHTML={{ __html: description }} />
|
<Wrapper className="markdown-body" dangerouslySetInnerHTML={{ __html: description }} />
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Readme;
|
export default Readme;
|
||||||
|
|
||||||
|
const Wrapper = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
|
background: theme?.palette.white,
|
||||||
|
color: theme?.palette.black,
|
||||||
|
padding: theme?.spacing(2, 3),
|
||||||
|
}));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<Readme /> component should dangerously set html 1`] = `"<div class=\\"markdown-body\\"><h1>This is a test string</h1></div>"`;
|
exports[`<Readme /> component should dangerously set html 1`] = `"<div class=\\"markdown-body css-beaqbv-Wrapper ecnabbe0\\"><h1>This is a test string</h1></div>"`;
|
||||||
|
|
||||||
exports[`<Readme /> component should load the component in default state 1`] = `"<div class=\\"markdown-body\\">test</div>"`;
|
exports[`<Readme /> component should load the component in default state 1`] = `"<div class=\\"markdown-body css-beaqbv-Wrapper ecnabbe0\\">test</div>"`;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { css } from '@emotion/core';
|
|
||||||
|
|
||||||
import CopyToClipBoard from '../CopyToClipBoard';
|
import CopyToClipBoard from '../CopyToClipBoard';
|
||||||
import { getCLISetRegistry, getCLIChangePassword, getCLISetConfigRegistry } from '../../utils/cli-utils';
|
import { getCLISetRegistry, getCLIChangePassword, getCLISetConfigRegistry } from '../../utils/cli-utils';
|
||||||
@@ -48,10 +47,10 @@ const RegistryInfoContent: React.FC<Props> = props => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tabs
|
<Tabs
|
||||||
|
color={'primary'}
|
||||||
data-testid={'tabs-el'}
|
data-testid={'tabs-el'}
|
||||||
indicatorColor="primary"
|
indicatorColor={'primary'}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
textColor="primary"
|
|
||||||
value={tabPosition}
|
value={tabPosition}
|
||||||
variant="fullWidth">
|
variant="fullWidth">
|
||||||
<Tab data-testid={'npm-tab'} label={NODE_MANAGER.npm} />
|
<Tab data-testid={'npm-tab'} label={NODE_MANAGER.npm} />
|
||||||
@@ -69,14 +68,7 @@ const RegistryInfoContent: React.FC<Props> = props => {
|
|||||||
const TabContainer = ({ children }): JSX.Element => {
|
const TabContainer = ({ children }): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<CommandContainer>
|
<CommandContainer>
|
||||||
<Typography
|
<Typography component="div">{children}</Typography>
|
||||||
// className={css`
|
|
||||||
// padding: 0;
|
|
||||||
// min-height: 170;
|
|
||||||
// `}
|
|
||||||
component="div">
|
|
||||||
{children}
|
|
||||||
</Typography>
|
|
||||||
</CommandContainer>
|
</CommandContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Button from '../../muiComponents/Button';
|
import Button from '../../muiComponents/Button';
|
||||||
import Dialog from '../../muiComponents/Dialog';
|
import Dialog from '../../muiComponents/Dialog';
|
||||||
@@ -7,18 +8,19 @@ import DialogActions from '../../muiComponents/DialogActions';
|
|||||||
import { Title, Content } from './styles';
|
import { Title, Content } from './styles';
|
||||||
import { Props } from './types';
|
import { Props } from './types';
|
||||||
|
|
||||||
const LABEL = 'CLOSE';
|
const RegistryInfoDialog: React.FC<Props> = ({ open = false, children, onClose }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const RegistryInfoDialog: React.FC<Props> = ({ open = false, children, onClose }) => (
|
return (
|
||||||
<Dialog data-testid={'registryInfo--dialog'} id="registryInfo--dialog-container" onClose={onClose} open={open}>
|
<Dialog data-testid={'registryInfo--dialog'} id="registryInfo--dialog-container" onClose={onClose} open={open}>
|
||||||
<Title disableTypography={true}>{'Register Info'}</Title>
|
<Title disableTypography={true}>{t('dialog.registry-info.title')}</Title>
|
||||||
<Content>{children}</Content>
|
<Content>{children}</Content>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button color="inherit" id="registryInfo--dialog-close" onClick={onClose}>
|
<Button color="inherit" id="registryInfo--dialog-close" onClick={onClose}>
|
||||||
{LABEL}
|
{t('button.close')}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default RegistryInfoDialog;
|
export default RegistryInfoDialog;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const Title = styled(DialogTitle)<{ theme?: Theme }>(props => ({
|
|||||||
fontSize: props.theme && props.theme.fontSize.lg,
|
fontSize: props.theme && props.theme.fontSize.lg,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Content = styled(DialogContent)({
|
export const Content = styled(DialogContent)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
padding: '0 24px',
|
padding: '0 24px',
|
||||||
});
|
backgroundColor: theme?.palette.background.default,
|
||||||
|
}));
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Avatar from '../../muiComponents/Avatar';
|
import Avatar from '../../muiComponents/Avatar';
|
||||||
import Text from '../../muiComponents/Text';
|
import Text from '../../muiComponents/Text';
|
||||||
import ListItem from '../../muiComponents/ListItem';
|
import ListItem from '../../muiComponents/ListItem';
|
||||||
import ListItemText from '../../muiComponents/ListItemText';
|
import ListItemText from '../../muiComponents/ListItemText';
|
||||||
|
import Link from '../Link';
|
||||||
import { isURL } from '../../utils/url';
|
import { isURL } from '../../utils/url';
|
||||||
import CopyToClipBoard from '../CopyToClipBoard';
|
import CopyToClipBoard from '../CopyToClipBoard';
|
||||||
import List from '../../muiComponents/List';
|
import List from '../../muiComponents/List';
|
||||||
@@ -18,8 +20,11 @@ const StyledText = styled(Text)<{ theme?: Theme }>(props => ({
|
|||||||
textTransform: 'capitalize',
|
textTransform: 'capitalize',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const GithubLink = styled('a')<{ theme?: Theme }>(props => ({
|
const GithubLink = styled(Link)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
color: props.theme && props.theme.palette.primary.main,
|
color: theme?.palette.type === 'light' ? theme?.palette.primary.main : theme?.palette.white,
|
||||||
|
':hover': {
|
||||||
|
color: theme?.palette.dodgerBlue,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const RepositoryListItem = styled(ListItem)({
|
const RepositoryListItem = styled(ListItem)({
|
||||||
@@ -44,6 +49,7 @@ const RepositoryAvatar = styled(Avatar)({
|
|||||||
|
|
||||||
const Repository: React.FC = () => {
|
const Repository: React.FC = () => {
|
||||||
const detailContext = React.useContext(DetailContext);
|
const detailContext = React.useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { packageMeta } = detailContext;
|
const { packageMeta } = detailContext;
|
||||||
|
|
||||||
@@ -64,13 +70,13 @@ const Repository: React.FC = () => {
|
|||||||
const repositoryURL = getCorrectRepositoryURL();
|
const repositoryURL = getCorrectRepositoryURL();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List dense={true} subheader={<StyledText variant="subtitle1">{'Repository'}</StyledText>}>
|
<List dense={true} subheader={<StyledText variant="subtitle1">{t('sidebar.repository.title')}</StyledText>}>
|
||||||
<RepositoryListItem button={true}>
|
<RepositoryListItem button={true}>
|
||||||
<RepositoryAvatar src={git} />
|
<RepositoryAvatar src={git} />
|
||||||
<RepositoryListItemText
|
<RepositoryListItemText
|
||||||
primary={
|
primary={
|
||||||
<CopyToClipBoard text={repositoryURL}>
|
<CopyToClipBoard text={repositoryURL}>
|
||||||
<GithubLink href={repositoryURL} target="_blank">
|
<GithubLink external={true} to={repositoryURL}>
|
||||||
{repositoryURL}
|
{repositoryURL}
|
||||||
</GithubLink>
|
</GithubLink>
|
||||||
</CopyToClipBoard>
|
</CopyToClipBoard>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useState, FormEvent, useCallback } from 'react';
|
|||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import { RouteComponentProps, withRouter } from 'react-router';
|
import { RouteComponentProps, withRouter } from 'react-router';
|
||||||
import { SuggestionSelectedEventData } from 'react-autosuggest';
|
import { SuggestionSelectedEventData } from 'react-autosuggest';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import AutoComplete from '../AutoComplete';
|
import AutoComplete from '../AutoComplete';
|
||||||
import { callSearch } from '../../utils/calls';
|
import { callSearch } from '../../utils/calls';
|
||||||
@@ -10,11 +11,11 @@ import SearchAdornment from './SearchAdornment';
|
|||||||
|
|
||||||
const CONSTANTS = {
|
const CONSTANTS = {
|
||||||
API_DELAY: 300,
|
API_DELAY: 300,
|
||||||
PLACEHOLDER_TEXT: 'Search Packages',
|
|
||||||
ABORT_ERROR: 'AbortError',
|
ABORT_ERROR: 'AbortError',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [suggestions, setSuggestions] = useState([]);
|
const [suggestions, setSuggestions] = useState([]);
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
@@ -141,7 +142,7 @@ const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
|||||||
onCleanSuggestions={handlePackagesClearRequested}
|
onCleanSuggestions={handlePackagesClearRequested}
|
||||||
onClick={handleClickSearch}
|
onClick={handleClickSearch}
|
||||||
onSuggestionsFetch={debounce(handleFetchPackages, CONSTANTS.API_DELAY)}
|
onSuggestionsFetch={debounce(handleFetchPackages, CONSTANTS.API_DELAY)}
|
||||||
placeholder={CONSTANTS.PLACEHOLDER_TEXT}
|
placeholder={t('search.packages')}
|
||||||
startAdornment={<SearchAdornment />}
|
startAdornment={<SearchAdornment />}
|
||||||
suggestions={suggestions}
|
suggestions={suggestions}
|
||||||
suggestionsError={error}
|
suggestionsError={error}
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ export const Wrapper = styled('div')<WrapperProps>(props => ({
|
|||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Circular = styled(CircularProgress)<{ theme?: Theme }>(props => ({
|
export const Circular = styled(CircularProgress)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
color: props.theme && props.theme.palette.primary.main,
|
color: theme?.palette.type === 'dark' ? theme?.palette.white : theme?.palette.primary.main,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import NoItems from '../NoItems';
|
import NoItems from '../NoItems';
|
||||||
@@ -10,6 +11,7 @@ import { StyledText, Spacer, ListItemText } from './styles';
|
|||||||
|
|
||||||
const UpLinks: React.FC = () => {
|
const UpLinks: React.FC = () => {
|
||||||
const { packageMeta } = useContext(DetailContext);
|
const { packageMeta } = useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (!packageMeta || !packageMeta._uplinks || !packageMeta.latest) {
|
if (!packageMeta || !packageMeta._uplinks || !packageMeta.latest) {
|
||||||
return null;
|
return null;
|
||||||
@@ -18,12 +20,12 @@ const UpLinks: React.FC = () => {
|
|||||||
const { _uplinks: uplinks, latest } = packageMeta;
|
const { _uplinks: uplinks, latest } = packageMeta;
|
||||||
|
|
||||||
if (Object.keys(uplinks).length === 0) {
|
if (Object.keys(uplinks).length === 0) {
|
||||||
return <NoItems text={`${latest.name} has no uplinks.`} />;
|
return <NoItems text={t('uplinks.no-items', { name: latest.name })} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledText variant="subtitle1">{'Uplinks'}</StyledText>
|
<StyledText variant="subtitle1">{t('uplinks.title')}</StyledText>
|
||||||
<List>
|
<List>
|
||||||
{Object.keys(uplinks)
|
{Object.keys(uplinks)
|
||||||
.reverse()
|
.reverse()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<UpLinks /> component should render the component when there is no uplink 1`] = `"<h6 class=\\"MuiTypography-root MuiTypography-subtitle1 MuiTypography-gutterBottom\\">verdaccio has no uplinks.</h6>"`;
|
exports[`<UpLinks /> component should render the component when there is no uplink 1`] = `"<h6 class=\\"MuiTypography-root MuiTypography-subtitle1 MuiTypography-gutterBottom\\">uplinks.no-items</h6>"`;
|
||||||
|
|
||||||
exports[`<UpLinks /> component should render the component with uplinks 1`] = `"<h6 class=\\"MuiTypography-root css-5wp24z-StyledText e14i1sy10 MuiTypography-subtitle1\\">Uplinks</h6><ul class=\\"MuiList-root MuiList-padding\\"><li class=\\"MuiListItem-root MuiListItem-gutters\\"><div class=\\"MuiListItemText-root css-1pxn9ma-ListItemText e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">npmjs</span></div><div class=\\"css-t1rp47-Spacer e14i1sy11\\"></div><div class=\\"MuiListItemText-root css-1pxn9ma-ListItemText e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">2 years ago</span></div></li></ul>"`;
|
exports[`<UpLinks /> component should render the component with uplinks 1`] = `"<h6 class=\\"MuiTypography-root css-5wp24z-StyledText e14i1sy10 MuiTypography-subtitle1\\">uplinks.title</h6><ul class=\\"MuiList-root MuiList-padding\\"><li class=\\"MuiListItem-root MuiListItem-gutters\\"><div class=\\"MuiListItemText-root css-1ork7s0-ListItemText e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">npmjs</span></div><div class=\\"css-4lqckn-Spacer e14i1sy11\\"></div><div class=\\"MuiListItemText-root css-1ork7s0-ListItemText e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">2 years ago</span></div></li></ul>"`;
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ export const StyledText = styled(Text)<{ theme?: Theme }>(props => ({
|
|||||||
fontWeight: props.theme && props.theme.fontWeight.bold,
|
fontWeight: props.theme && props.theme.fontWeight.bold,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Spacer = styled('div')({
|
export const Spacer = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
flex: '1 1 auto',
|
flex: '1 1 auto',
|
||||||
borderBottom: '1px dotted rgba(0, 0, 0, 0.2)',
|
borderBottom: `1px dotted ${theme?.palette.type == 'light' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.2)'} `,
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
height: '0.5em',
|
height: '0.5em',
|
||||||
});
|
}));
|
||||||
|
|
||||||
export const ListItemText = styled(MuiListItemText)({
|
export const ListItemText = styled(MuiListItemText)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
flex: 'none',
|
flex: 'none',
|
||||||
color: 'black',
|
color: theme?.palette.type == 'light' ? theme?.palette.black : theme?.palette.white,
|
||||||
opacity: 0.6,
|
opacity: 0.6,
|
||||||
});
|
}));
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import { MemoryRouter } from 'react-router-dom';
|
|||||||
import { render, cleanup } from '../../utils/test-react-testing-library';
|
import { render, cleanup } from '../../utils/test-react-testing-library';
|
||||||
import { mount } from '../../utils/test-enzyme';
|
import { mount } from '../../utils/test-enzyme';
|
||||||
import { DetailContext, DetailContextProps } from '../../pages/Version';
|
import { DetailContext, DetailContextProps } from '../../pages/Version';
|
||||||
|
import translationEN from '../../../i18n/translations/en-US.json';
|
||||||
|
|
||||||
import Versions, { LABEL_CURRENT_TAGS, LABEL_VERSION_HISTORY } from './Versions';
|
import Versions from './Versions';
|
||||||
import data from './__partials__/data.json';
|
import data from './__partials__/data.json';
|
||||||
|
|
||||||
const detailContextValue: Partial<DetailContextProps> = {
|
const detailContextValue: Partial<DetailContextProps> = {
|
||||||
@@ -35,8 +36,8 @@ describe('<Version /> component', () => {
|
|||||||
test('should render versions', () => {
|
test('should render versions', () => {
|
||||||
const { getByText } = render(<ComponentToBeRendered contextValue={detailContextValue} />);
|
const { getByText } = render(<ComponentToBeRendered contextValue={detailContextValue} />);
|
||||||
|
|
||||||
expect(getByText(LABEL_VERSION_HISTORY)).toBeTruthy();
|
expect(getByText(translationEN.versions['version-history'])).toBeTruthy();
|
||||||
expect(getByText(LABEL_CURRENT_TAGS)).toBeTruthy();
|
expect(getByText(translationEN.versions['current-tags'])).toBeTruthy();
|
||||||
|
|
||||||
// pick some versions
|
// pick some versions
|
||||||
expect(getByText('2.3.0')).toBeTruthy();
|
expect(getByText('2.3.0')).toBeTruthy();
|
||||||
@@ -48,8 +49,8 @@ describe('<Version /> component', () => {
|
|||||||
<ComponentToBeRendered contextValue={{ packageName: detailContextValue.packageName }} />
|
<ComponentToBeRendered contextValue={{ packageName: detailContextValue.packageName }} />
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(queryByText(LABEL_VERSION_HISTORY)).toBeFalsy();
|
expect(queryByText(translationEN.versions['version-history'])).toBeFalsy();
|
||||||
expect(queryByText(LABEL_CURRENT_TAGS)).toBeFalsy();
|
expect(queryByText(translationEN.versions['current-tags'])).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.todo('should click on version link');
|
test.todo('should click on version link');
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import { DIST_TAGS } from '../../../lib/constants';
|
import { DIST_TAGS } from '../../../lib/constants';
|
||||||
@@ -7,12 +8,9 @@ import { StyledText } from './styles';
|
|||||||
import VersionsTagList from './VersionsTagList';
|
import VersionsTagList from './VersionsTagList';
|
||||||
import VersionsHistoryList from './VersionsHistoryList';
|
import VersionsHistoryList from './VersionsHistoryList';
|
||||||
|
|
||||||
export const NOT_AVAILABLE = 'Not available';
|
|
||||||
export const LABEL_CURRENT_TAGS = 'Current Tags';
|
|
||||||
export const LABEL_VERSION_HISTORY = 'Version History';
|
|
||||||
|
|
||||||
const Versions: React.FC = () => {
|
const Versions: React.FC = () => {
|
||||||
const detailContext = useContext(DetailContext);
|
const detailContext = useContext(DetailContext);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { packageMeta, packageName } = detailContext;
|
const { packageMeta, packageName } = detailContext;
|
||||||
|
|
||||||
@@ -26,13 +24,13 @@ const Versions: React.FC = () => {
|
|||||||
<>
|
<>
|
||||||
{distTags && Object.keys(distTags).length > 0 && (
|
{distTags && Object.keys(distTags).length > 0 && (
|
||||||
<>
|
<>
|
||||||
<StyledText variant="subtitle1">{LABEL_CURRENT_TAGS}</StyledText>
|
<StyledText variant="subtitle1">{t('versions.current-tags')}</StyledText>
|
||||||
<VersionsTagList tags={distTags} />
|
<VersionsTagList tags={distTags} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{versions && Object.keys(versions).length > 0 && packageName && (
|
{versions && Object.keys(versions).length > 0 && packageName && (
|
||||||
<>
|
<>
|
||||||
<StyledText variant="subtitle1">{LABEL_VERSION_HISTORY}</StyledText>
|
<StyledText variant="subtitle1">{t('versions.version-history')}</StyledText>
|
||||||
<VersionsHistoryList packageName={packageName} time={time} versions={versions} />
|
<VersionsHistoryList packageName={packageName} time={time} versions={versions} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Versions, Time } from '../../../types/packageMeta';
|
import { Versions, Time } from '../../../types/packageMeta';
|
||||||
import { formatDateDistance } from '../../utils/package';
|
import { formatDateDistance } from '../../utils/package';
|
||||||
@@ -7,28 +8,32 @@ import ListItem from '../../muiComponents/ListItem';
|
|||||||
|
|
||||||
import { Spacer, ListItemText, StyledLink } from './styles';
|
import { Spacer, ListItemText, StyledLink } from './styles';
|
||||||
|
|
||||||
export const NOT_AVAILABLE = 'Not available';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
versions: Versions;
|
versions: Versions;
|
||||||
packageName: string;
|
packageName: string;
|
||||||
time: Time;
|
time: Time;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) => (
|
const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) => {
|
||||||
<List dense={true}>
|
const { t } = useTranslation();
|
||||||
{Object.keys(versions)
|
|
||||||
.reverse()
|
return (
|
||||||
.map(version => (
|
<List dense={true}>
|
||||||
<ListItem className="version-item" key={version}>
|
{Object.keys(versions)
|
||||||
<StyledLink to={`/-/web/detail/${packageName}/v/${version}`}>
|
.reverse()
|
||||||
<ListItemText>{version}</ListItemText>
|
.map(version => (
|
||||||
</StyledLink>
|
<ListItem className="version-item" key={version}>
|
||||||
<Spacer />
|
<StyledLink to={`/-/web/detail/${packageName}/v/${version}`}>
|
||||||
<ListItemText>{time[version] ? formatDateDistance(time[version]) : NOT_AVAILABLE}</ListItemText>
|
<ListItemText>{version}</ListItemText>
|
||||||
</ListItem>
|
</StyledLink>
|
||||||
))}
|
<Spacer />
|
||||||
</List>
|
<ListItemText>
|
||||||
);
|
{time[version] ? formatDateDistance(time[version]) : t('versions.not-available')}
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default VersionsHistoryList;
|
export default VersionsHistoryList;
|
||||||
|
|||||||
@@ -9,19 +9,19 @@ export const StyledText = styled(Text)<{ theme?: Theme }>(props => ({
|
|||||||
fontWeight: props.theme && props.theme.fontWeight.bold,
|
fontWeight: props.theme && props.theme.fontWeight.bold,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Spacer = styled('div')({
|
export const Spacer = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
flex: '1 1 auto',
|
flex: '1 1 auto',
|
||||||
borderBottom: '1px dotted rgba(0, 0, 0, 0.2)',
|
borderBottom: `1px dotted ${theme?.palette.type == 'light' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.2)'} `,
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
height: '0.5em',
|
height: '0.5em',
|
||||||
margin: '0 16px',
|
margin: '0 16px',
|
||||||
});
|
}));
|
||||||
|
|
||||||
export const ListItemText = styled(MuiListItemText)({
|
export const ListItemText = styled(MuiListItemText)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
flex: 'none',
|
flex: 'none',
|
||||||
color: 'black',
|
|
||||||
opacity: 0.6,
|
opacity: 0.6,
|
||||||
});
|
color: theme?.palette.type == 'light' ? theme?.palette.black : theme?.palette.white,
|
||||||
|
}));
|
||||||
|
|
||||||
export const StyledLink = styled(Link)({
|
export const StyledLink = styled(Link)({
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
|
|||||||
10
src/design-tokens/ThemeContext.ts
Normal file
10
src/design-tokens/ThemeContext.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isDarkMode: boolean;
|
||||||
|
setIsDarkMode: (isDarkMode: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeContext = createContext<undefined | Props>(undefined);
|
||||||
|
|
||||||
|
export default ThemeContext;
|
||||||
@@ -2,12 +2,23 @@ import React from 'react';
|
|||||||
import { ThemeProvider as MuiThemeProvider } from '@material-ui/core/styles';
|
import { ThemeProvider as MuiThemeProvider } from '@material-ui/core/styles';
|
||||||
import { ThemeProvider as EmotionThemeProvider } from 'emotion-theming';
|
import { ThemeProvider as EmotionThemeProvider } from 'emotion-theming';
|
||||||
|
|
||||||
import theme from './theme';
|
import ThemeContext from './ThemeContext';
|
||||||
|
import { getTheme, ThemeMode } from './theme';
|
||||||
|
import useLocalStorage from './useLocalStorage';
|
||||||
|
|
||||||
const ThemeProvider: React.FC = ({ children }) => (
|
const ThemeProvider: React.FC = ({ children }) => {
|
||||||
<EmotionThemeProvider theme={theme}>
|
const isDarkModeDefault = window?.__VERDACCIO_BASENAME_UI_OPTIONS?.darkMode;
|
||||||
<MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
|
const [isDarkMode, setIsDarkMode] = useLocalStorage('darkMode', !!isDarkModeDefault);
|
||||||
</EmotionThemeProvider>
|
|
||||||
);
|
const themeMode: ThemeMode = isDarkMode ? 'dark' : 'light';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{ isDarkMode, setIsDarkMode }}>
|
||||||
|
<EmotionThemeProvider theme={getTheme(themeMode)}>
|
||||||
|
<MuiThemeProvider theme={getTheme(themeMode)}>{children}</MuiThemeProvider>
|
||||||
|
</EmotionThemeProvider>
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default ThemeProvider;
|
export default ThemeProvider;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import createMuiTheme from '@material-ui/core/styles/createMuiTheme';
|
import createMuiTheme from '@material-ui/core/styles/createMuiTheme';
|
||||||
|
|
||||||
// Main colors
|
|
||||||
// -------------------------
|
|
||||||
const colors = {
|
const colors = {
|
||||||
black: '#000',
|
black: '#000',
|
||||||
white: '#fff',
|
white: '#fff',
|
||||||
@@ -25,9 +23,23 @@ const colors = {
|
|||||||
nobel02: '#9f9f9f',
|
nobel02: '#9f9f9f',
|
||||||
primary: window.VERDACCIO_PRIMARY_COLOR || '#4b5e40',
|
primary: window.VERDACCIO_PRIMARY_COLOR || '#4b5e40',
|
||||||
secondary: '#20232a',
|
secondary: '#20232a',
|
||||||
|
background: '#fff',
|
||||||
|
dodgerBlue: '#1ba1f2',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Colors = keyof typeof colors;
|
const themeModes = {
|
||||||
|
light: {
|
||||||
|
...colors,
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
...colors,
|
||||||
|
primary: '#253341',
|
||||||
|
secondary: '#20232a',
|
||||||
|
background: '#1A202C',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ThemeMode = keyof typeof themeModes;
|
||||||
|
|
||||||
const fontSize = {
|
const fontSize = {
|
||||||
xxl: 26,
|
xxl: 26,
|
||||||
@@ -67,20 +79,27 @@ const customizedTheme = {
|
|||||||
|
|
||||||
type CustomizedTheme = typeof customizedTheme;
|
type CustomizedTheme = typeof customizedTheme;
|
||||||
|
|
||||||
export const theme = createMuiTheme({
|
export const getTheme = (themeMode: ThemeMode) => {
|
||||||
typography: {
|
const palette = themeModes[themeMode];
|
||||||
fontFamily: 'inherit',
|
return createMuiTheme({
|
||||||
},
|
typography: {
|
||||||
palette: {
|
fontFamily: 'inherit',
|
||||||
...colors,
|
},
|
||||||
primary: { main: colors.primary },
|
palette: {
|
||||||
secondary: { main: colors.secondary },
|
type: themeMode,
|
||||||
error: { main: colors.red },
|
...palette,
|
||||||
},
|
primary: { main: palette.primary },
|
||||||
...customizedTheme,
|
secondary: { main: palette.secondary },
|
||||||
});
|
error: { main: palette.red },
|
||||||
|
background: {
|
||||||
|
default: palette.background,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...customizedTheme,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export type Theme = typeof theme;
|
export type Theme = ReturnType<typeof getTheme>;
|
||||||
|
|
||||||
declare module '@material-ui/core/styles/createMuiTheme' {
|
declare module '@material-ui/core/styles/createMuiTheme' {
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-empty-interface */
|
/* eslint-disable-next-line @typescript-eslint/no-empty-interface */
|
||||||
@@ -111,6 +130,8 @@ declare module '@material-ui/core/styles/createPalette' {
|
|||||||
love: string;
|
love: string;
|
||||||
nobel01: string;
|
nobel01: string;
|
||||||
nobel02: string;
|
nobel02: string;
|
||||||
|
background: string;
|
||||||
|
dodgerBlue: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-empty-interface */
|
/* eslint-disable-next-line @typescript-eslint/no-empty-interface */
|
||||||
@@ -118,5 +139,3 @@ declare module '@material-ui/core/styles/createPalette' {
|
|||||||
/* eslint-disable-next-line @typescript-eslint/no-empty-interface */
|
/* eslint-disable-next-line @typescript-eslint/no-empty-interface */
|
||||||
interface PaletteOptions extends Partial<CustomPalette> {}
|
interface PaletteOptions extends Partial<CustomPalette> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { ...theme };
|
|
||||||
|
|||||||
38
src/design-tokens/useLocalStorage.ts
Normal file
38
src/design-tokens/useLocalStorage.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
// based on https://usehooks.com/useLocalStorage/
|
||||||
|
const useLocalStorage = <V>(key: string, initialValue: V) => {
|
||||||
|
// State to store our value
|
||||||
|
// Pass initial state function to useState so logic is only executed once
|
||||||
|
const [storedValue, setStoredValue] = useState(() => {
|
||||||
|
try {
|
||||||
|
// Get from local storage by key
|
||||||
|
const item = window.localStorage.getItem(key);
|
||||||
|
// Parse stored json or if none return initialValue
|
||||||
|
return item ? JSON.parse(item) : initialValue;
|
||||||
|
} catch (error) {
|
||||||
|
// If error also return initialValue
|
||||||
|
console.error('An error occurred getting a sessionStorage key', error);
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return a wrapped version of useState's setter function that ...
|
||||||
|
// ... persists the new value to localStorage.
|
||||||
|
const setValue = (value: V) => {
|
||||||
|
try {
|
||||||
|
// Allow value to be a function so we have same API as useState
|
||||||
|
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
||||||
|
// Save state
|
||||||
|
setStoredValue(valueToStore);
|
||||||
|
// Save to local storage
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('An error occurred writing to sessionStorage', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [storedValue, setValue];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useLocalStorage;
|
||||||
7
src/design-tokens/useTheme.ts
Normal file
7
src/design-tokens/useTheme.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { useTheme as muiUseTheme } from '@material-ui/styles';
|
||||||
|
|
||||||
|
import { Theme } from './theme';
|
||||||
|
|
||||||
|
const useTheme = () => muiUseTheme<Theme>();
|
||||||
|
|
||||||
|
export default useTheme;
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
/* eslint-disable max-len */
|
|
||||||
/* eslint-disable react/jsx-curly-brace-presence */
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import SvgIcon from '../muiComponents/SvgIcon';
|
|
||||||
|
|
||||||
const GitHub: React.FC = props => (
|
|
||||||
<SvgIcon {...props}>
|
|
||||||
<path d="M12.007 0C6.12 0 1.1 4.27.157 10.08c-.944 5.813 2.468 11.45 8.054 13.312.19.064.397.033.555-.084.16-.117.25-.304.244-.5v-2.042c-3.33.735-4.037-1.56-4.037-1.56-.22-.726-.694-1.35-1.334-1.756-1.096-.75.074-.735.074-.735.773.103 1.454.557 1.846 1.23.694 1.21 2.23 1.638 3.45.96.056-.61.327-1.178.766-1.605-2.67-.3-5.462-1.335-5.462-6.002-.02-1.193.42-2.35 1.23-3.226-.327-1.015-.27-2.116.166-3.09 0 0 1.006-.33 3.3 1.23 1.966-.538 4.04-.538 6.003 0 2.295-1.5 3.3-1.23 3.3-1.23.445 1.006.49 2.144.12 3.18.81.877 1.25 2.033 1.23 3.226 0 4.607-2.805 5.627-5.476 5.927.578.583.88 1.386.825 2.206v3.29c-.005.2.092.393.26.507.164.115.377.14.565.063 5.568-1.88 8.956-7.514 8.007-13.313C22.892 4.267 17.884.007 12.008 0z" />
|
|
||||||
</SvgIcon>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default GitHub;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default } from './GitHub';
|
|
||||||
@@ -3,7 +3,7 @@ import { MemoryRouter } from 'react-router';
|
|||||||
import { waitForElement } from '@testing-library/dom';
|
import { waitForElement } from '@testing-library/dom';
|
||||||
|
|
||||||
import { render } from '../../utils/test-react-testing-library';
|
import { render } from '../../utils/test-react-testing-library';
|
||||||
import { NOT_FOUND_TEXT } from '../../components/NotFound';
|
import translationEN from '../../../i18n/translations/en-US.json';
|
||||||
|
|
||||||
import Version from './Version';
|
import Version from './Version';
|
||||||
import { DetailContext } from './context';
|
import { DetailContext } from './context';
|
||||||
@@ -51,7 +51,9 @@ describe('test Version page', () => {
|
|||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
// we wait fetch response (mocked above)
|
// we wait fetch response (mocked above)
|
||||||
const notFoundElement = await waitForElement(() => getByText(NOT_FOUND_TEXT));
|
const notFoundElement = await waitForElement(() =>
|
||||||
|
getByText(translationEN.error['404']['sorry-we-could-not-find-it'])
|
||||||
|
);
|
||||||
expect(notFoundElement).toBeTruthy();
|
expect(notFoundElement).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ const Home: React.FC<Props> = ({ isUserLoggedIn }) => {
|
|||||||
loadPackages().then();
|
loadPackages().then();
|
||||||
}, [isUserLoggedIn]);
|
}, [isUserLoggedIn]);
|
||||||
|
|
||||||
return <div className="container content">{isLoading ? <Loading /> : <PackageList packages={packages} />}</div>;
|
return (
|
||||||
|
<div className="container content" data-testid="home-page-container">
|
||||||
|
{isLoading ? <Loading /> : <PackageList packages={packages} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Home;
|
export default Home;
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
export const TEXT = {
|
|
||||||
CLIPBOARD_COPY: 'Copy to Clipboard',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const NODE_MANAGER = {
|
export const NODE_MANAGER = {
|
||||||
npm: 'npm',
|
npm: 'npm',
|
||||||
yarn: 'yarn',
|
yarn: 'yarn',
|
||||||
|
|||||||
@@ -16,6 +16,22 @@ jest.mock('./api', () => ({
|
|||||||
request: require('../../jest/unit/components/__mocks__/api').default.request,
|
request: require('../../jest/unit/components/__mocks__/api').default.request,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('i18next', () => {
|
||||||
|
const translationEN = require('../../i18n/translations/en-US.json');
|
||||||
|
return {
|
||||||
|
t: (key: string) => {
|
||||||
|
const splittedKey = key.split('.');
|
||||||
|
let result = translationEN;
|
||||||
|
|
||||||
|
for (const element of splittedKey) {
|
||||||
|
result = result[element];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
describe('isTokenExpire', (): void => {
|
describe('isTokenExpire', (): void => {
|
||||||
test('isTokenExpire - null is not a valid payload', (): void => {
|
test('isTokenExpire - null is not a valid payload', (): void => {
|
||||||
expect(isTokenExpire(null)).toBeTruthy();
|
expect(isTokenExpire(null)).toBeTruthy();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import isString from 'lodash/isString';
|
|||||||
import isNumber from 'lodash/isNumber';
|
import isNumber from 'lodash/isNumber';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import { Base64 } from 'js-base64';
|
import { Base64 } from 'js-base64';
|
||||||
|
import i18next from 'i18next';
|
||||||
|
|
||||||
import { HEADERS } from '../../lib/constants';
|
import { HEADERS } from '../../lib/constants';
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ export async function makeLogin(username?: string, password?: string): Promise<L
|
|||||||
if (isEmpty(username) || isEmpty(password)) {
|
if (isEmpty(username) || isEmpty(password)) {
|
||||||
const error = {
|
const error = {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
description: "Username or password can't be empty!",
|
description: i18next.t('form-validation.username-or-password-cant-be-empty'),
|
||||||
};
|
};
|
||||||
return { error };
|
return { error };
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,7 @@ export async function makeLogin(username?: string, password?: string): Promise<L
|
|||||||
console.error('login error', e.message);
|
console.error('login error', e.message);
|
||||||
const error = {
|
const error = {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
description: 'Unable to sign in',
|
description: i18next.t('form-validation.unable-to-sign-in'),
|
||||||
};
|
};
|
||||||
return { error };
|
return { error };
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user