From 770263f085ba9754fd3f3a68c91fc70de4bd29e9 Mon Sep 17 00:00:00 2001 From: Sky Lundy Date: Sun, 24 Mar 2024 12:12:20 -0700 Subject: [PATCH] Version bump to 1.0.9, update changelog, add PW forum link to readme, Add additional checks and config resets for resetEngineData during upgrade --- CHANGELOG.md | 9 ++ Fluency.info.php | 2 +- Fluency.module.php | 93 ++++++++++--------- FluencyConfig.php | 64 +++++++++++-- README.md | 6 +- .../FluencyProcessWireFileTranslator.php | 6 ++ assets/styles/fluency_module_config.min.css | 2 +- .../maps/fluency_module_config.min.css.map | 2 +- src/scss/fluency_module_config.scss | 5 + 9 files changed, 130 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8f6af3..7b8cd44 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Fluency for ProcessWire Changelog +### 1.0.9 2024-06-18 + +NOTE: If upgrading from 1.0.7 or earlier, you will be required to configure your selected +translation engine again after upgrading. Existing content will not be affected. + +- Fix issue where upgrading from v1.0.7 or earlier to v1.0.8 would cause translation failure due to + updating how the module stores configuration data. Credit to @jacmaes for finding and reporting. + Resolves https://github.com/SkyLundy/Fluency/issues/5 + ## 1.0.8 2024-24-03 ### New features, Bugfixes, Documentation, Code Improvement, Recommended for all users diff --git a/Fluency.info.php b/Fluency.info.php index cd229ab..d5eea61 100755 --- a/Fluency.info.php +++ b/Fluency.info.php @@ -6,7 +6,7 @@ $info = [ 'title' => 'Fluency', - 'version' => '108', + 'version' => '109', 'href' => 'https://processwire.com/talk/topic/24567-fluency-integrated-deepl-powered-content-translation', 'icon' => 'language', 'summary' => 'The complete translation enhancement suite for ProcessWire.', diff --git a/Fluency.module.php b/Fluency.module.php index c374f64..ec4f9ea 100755 --- a/Fluency.module.php +++ b/Fluency.module.php @@ -120,13 +120,18 @@ final class Fluency extends Process implements Module, ConfigurableModule { * @return void */ public function init() { + $this->fluencyConfig = (new FluencyConfig())->getConfigData(); + + if (!$this->translationEngineIsReady()) { + return; + } + // Create global $fluency variable $this->wire->set('fluency', $this); $this->moduleJsPath = "{$this->urls->$this}assets/scripts/"; $this->moduleCssPath = "{$this->urls->$this}assets/styles/"; - $this->fluencyConfig = (new FluencyConfig())->getConfigData(); $this->initializeCaches(); $this->initializeTranslationEngine(); $this->processWireFileTranslator = new ProcessWireFileTranslator($this); @@ -146,6 +151,48 @@ public function ready() { $this->insertAdminAssets(); } + /** + * ProcessWire languages are configured within Fluency and translation is available for admin Inputfields + * + * Requires that: + * - The default ProcessWire language has been configured in Fluency + * - At least one additional language has been configured in Fluency + * - The Translation Engine has been configured and is ready to process requests + * + * #pw-notes Requires that ProcessWire languages are configured in Fluency + * + * #pw-group-Translation-Readiness + * + * @return bool + */ + public function inputfieldTranslationIsReady(): bool { + return $this->translationEngineIsReady() && count($this->getConfiguredLanguages()) >= 2; + } + + /** + * Translation Engine has been configured and is ready to process requests + * + * This indicates that the Translation Engine authenticates and is able to send and receive data + * via the corresponding translation service API. This is separate from + * Fluency::inputfieldTranslationIsReady() in that it does not indicate whether languages have + * been configured within Fluency. + * + * Requires that: + * + * - A Translation Engine is selected in Fluency + * - The Translation Engine is configured in Fluency and ready + * - The translation service API used by the engine successfuly accepts/returns requests + * + * #pw-notes Does not require ProcessWire languages to be configured in Fluency + * + * #pw-group-Translation-Readiness + * + * @return bool + */ + public function translationEngineIsReady(): bool { + return $this->fluencyConfig?->translation_api_ready ?? false; + } + /** * Adds ability to disable translation per-field when configuring multi-language fields */ @@ -194,7 +241,7 @@ private function registerFieldRenderHooks(): void { * Determine if module should initialize */ private function moduleShouldInitInAdmin(): bool { - return $this->page->name !== 'login' && $this->userIsAuthorized(); + return $this->page->name !== 'login' && $this->userIsAuthorized() && !!$this->fluencyConfig; } /** @@ -296,48 +343,6 @@ public function insertApiUsageTableFieldsetAssets(): void { $this->config->styles->add("{$this->moduleCssPath}fluency_api_usage.min.css"); } - /** - * ProcessWire languages are configured within Fluency and translation is available for admin Inputfields - * - * Requires that: - * - The default ProcessWire language has been configured in Fluency - * - At least one additional language has been configured in Fluency - * - The Translation Engine has been configured and is ready to process requests - * - * #pw-notes Requires that ProcessWire languages are configured in Fluency - * - * #pw-group-Translation-Readiness - * - * @return bool - */ - public function inputfieldTranslationIsReady(): bool { - return $this->translationEngineIsReady() && count($this->getConfiguredLanguages()) >= 2; - } - - /** - * Translation Engine has been configured and is ready to process requests - * - * This indicates that the Translation Engine authenticates and is able to send and receive data - * via the corresponding translation service API. This is separate from - * Fluency::inputfieldTranslationIsReady() in that it does not indicate whether languages have - * been configured within Fluency. - * - * Requires that: - * - * - A Translation Engine is selected in Fluency - * - The Translation Engine is configured in Fluency and ready - * - The translation service API used by the engine successfuly accepts/returns requests - * - * #pw-notes Does not require ProcessWire languages to be configured in Fluency - * - * #pw-group-Translation-Readiness - * - * @return bool - */ - public function translationEngineIsReady(): bool { - return $this->fluencyConfig->translation_api_ready ?? false; - } - /** * Module actions and Translation Engine interfaces */ diff --git a/FluencyConfig.php b/FluencyConfig.php index 8b10da4..a35048e 100755 --- a/FluencyConfig.php +++ b/FluencyConfig.php @@ -70,7 +70,11 @@ public function getConfigData(): ?FluencyConfigData { $moduleConfig = $this->getModuleConfig(); - if (!$moduleConfig->selected_engine) { + // Addresses issues where selected_engine may contain legacy or invalid engine config data + // If so, reset and return null + if (!$this->selectedEngineIsValid()) { + $this->resetEngineData(); + return null; } @@ -137,14 +141,30 @@ public function initTranslationEngine(): ?array { * @param array ...$newConfigData Named arguments */ private function saveModuleConfig(...$newConfigData): void { - $this->modules->saveModuleConfigData('Fluency', [ + $this->modules->saveConfig('Fluency', [ ...(array) $this->getModuleConfig(), ...$newConfigData ]); } /** - * Internal module use only + * Removes config keys and their values from the module's config + * @param array $configRemovalKeys Keys of configs to remove + */ + private function removeFromModuleConfig(array $configRemovalKeys): void { + $config = (array) $this->getModuleConfig(); + + $config = array_filter( + $config, + fn($config) => !in_array($config, $configRemovalKeys), + ARRAY_FILTER_USE_KEY + ); + + $this->modules->saveConfig('Fluency', $config); + } + + /** + * Get module config as an object containing all set and default values * * @return object Config as an object */ @@ -154,12 +174,33 @@ private function getModuleConfig(): object { /** * Resets all configured engine data by removing the selected engine and it's associated settings - * This may be required when upgrading the module + * This may be required when upgrading the module due to previous storage formats */ public function resetEngineData(): void { + $configKeys = array_keys((array) $this->getModuleConfig()); + + $removals = array_filter( + $configKeys, + fn($key) => !!str_starts_with($key, 'pw_language_') + ); + + $this->removeFromModuleConfig($removals); + $this->saveModuleConfig(translation_api_ready: false, selected_engine: null); } + /** + * Determines if there is a currently selected translation engine and that it is stored in the + * valid format + * + * @todo Deprecate this in the future when possible, only needed for upgrades from < 1.0.8 + */ + public function selectedEngineIsValid(): bool { + $moduleConfig = $this->getModuleConfig(); + + return !!$moduleConfig->selected_engine && !!json_decode($moduleConfig->selected_engine); + } + /** * This renders all Fluency config fields, as well as integrating the Translation Engine Config * fields, when necessary, when an engine is selected @@ -210,7 +251,7 @@ public function getInputFields(): InputfieldWrapper { ] ]); - if (!$engineSelected) { + if (!$this->selectedEngineIsValid()) { return $inputfields->add($fieldset); } @@ -275,7 +316,7 @@ public function getInputFields(): InputfieldWrapper { // Verify API credentials by getting translatable languages // 2 birds, 1 stone - if ($moduleConfig->selected_engine && !$moduleConfig->translation_api_ready || $engineChanged) { + if ($this->selectedEngineIsValid() && !$moduleConfig->translation_api_ready || $engineChanged) { $engineLanguages = $engine->getLanguages(); if ($engineLanguages->error) { @@ -518,11 +559,14 @@ function ($markup, $language) { Markup::div( Markup::a( href: 'https://paypal.me/noonesboy', - content: Markup::img("{$this->wire('urls')->get('Fluency')}/assets/img/paypal_me.png", 'PayPal Me'), + content: Markup::img( + source: "{$this->wire('urls')->get('Fluency')}/assets/img/paypal_me.png", + alt: 'PayPal Me' + ), rel: 'noopener', - target: '_blank' - ), - 'button-donate' + target: '_blank', + classes: 'button-donate' + ) ) ) ]); diff --git a/README.md b/README.md index 6f2daec..8769941 100755 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ Fluency can be used: - When adding multi-language abilities to an existing ProcessWire application - To add translation abilities to an existing multi-language ProcessWire application -You can help out by filing Github issues when bugs are found, or submit a pull request with fixes. +You can help make Fluency better by filing Github issues when bugs are found, or submit a pull request with fixes. + +For support and community discussion about Fluency, visit [the module thread in the ProcessWire forums](https://processwire.com/talk/topic/24567-fluency-the-complete-translation-enhancement-suite-for-processwire/). ## Contents @@ -55,7 +57,7 @@ You can help out by filing Github issues when bugs are found, or submit a pull r - LanguageTabs - ProcessLanguage - UIKit admin theme -- At least 2 languages configured in ProcessWire to add translation to fields +- At least 2 languages configured in ProcessWire and Fluency to add translation to fields - API key for the chosen third party translation service, free tiers are available ## Installing diff --git a/app/Services/FluencyProcessWireFileTranslator.php b/app/Services/FluencyProcessWireFileTranslator.php index f31362c..553c28a 100755 --- a/app/Services/FluencyProcessWireFileTranslator.php +++ b/app/Services/FluencyProcessWireFileTranslator.php @@ -30,6 +30,12 @@ class FluencyProcessWireFileTranslator { public function __construct( private Fluency $fluency ) { + if (!!$fluency->fluencyConfig) { + $this->init(); + } + } + + private function init(): void { $this->defaultFluencyLanguage = $this->fluency->getConfiguredLanguages()->getDefault(); $this->defaultPwLanguage = wire('languages')->getDefault(); $this->defaultPwLanguageTranslator = $this->defaultPwLanguage->translator(); diff --git a/assets/styles/fluency_module_config.min.css b/assets/styles/fluency_module_config.min.css index 4c778a4..67c4955 100755 --- a/assets/styles/fluency_module_config.min.css +++ b/assets/styles/fluency_module_config.min.css @@ -12,5 +12,5 @@ var(--ft-error-1), var(--ft-error-2), var(--ft-error-1) - );--ft-flash-error-background:var(--ft-error-1);--ft-activity-message-success-background:rgba(34, 156, 53, 0.6);--ft-activity-message-background:rgba(83, 121, 162, 0.8);--ft-activity-animation-accent:rgba(255, 255, 255, 0.3);--ft-activity-text-color:rgb(255, 255, 255);--ft-inputfield-state-default-border:2px solid rgb(255, 255, 255);--ft-inputfield-state-modified-border:2px solid #60caad;--ft-inputfield-translate-status-color:rgb(135, 135, 135);--ft-inputfield-translate-icon-color:rgb(135, 135, 135);--ft-secondary-translate-button-container-border:rgb(201, 201, 201);--button-disabled:rgb(201, 201, 201);--text-disabled:rgb(135, 135, 135)}.ft-activity-overlay-container{position:relative}@keyframes backround-scroll{0%{background-position:100% 0}100%{background-position:-100% 0}}.ft-activity-overlay-container .ft-activity-overlay{align-items:center;outline:1px solid var(--ft-white);color:var(--ft-activity-text-color);display:flex;height:100%;justify-content:center;opacity:0;pointer-events:none;position:absolute;left:0;top:0;transition:opacity .3s;width:100%;z-index:10}.ft-activity-overlay-container .ft-activity-overlay.visible{opacity:1;pointer-events:initial}.ft-activity-overlay-container .ft-activity-overlay .ft-activity,.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message{align-items:center;display:flex;height:100%;justify-content:center;opacity:0;position:absolute;width:100%;transition:opacity 1s;font-size:1.1rem}.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message{background-color:var(--ft-activity-message-background);padding:1rem;text-align:center}.ft-activity-overlay-container .ft-activity-overlay.message .ft-activity-message{opacity:1}.ft-activity-overlay-container .ft-activity-overlay.message.error .ft-activity-message{animation:backround-scroll 7s reverse linear infinite;background:var(--ft-activity-animation-error-background);background-size:200% 100%}.ft-activity-overlay-container .ft-activity-overlay.message.error.flash .ft-activity-message{background:var(--ft-flash-error-background)}.ft-activity-overlay-container .ft-activity-overlay.message.success .ft-activity-message{background-color:var(--ft-activity-message-success-background);transition:opacity .1s}.ft-activity-overlay-container .ft-activity-overlay.message.success.flash{transition:opacity .1s}.ft-activity-overlay-container .ft-activity-overlay.activity .ft-activity{opacity:1}.ft-activity-overlay-container .ft-activity-overlay .ft-activity{animation:backround-scroll 3.5s linear infinite;background:var(--ft-activity-animation-background);background-size:200% 100%;flex-direction:column;font-size:1rem;justify-content:center;letter-spacing:2px;opacity:0}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-text{text-align:center;font-size:1.15rem;padding:0 5rem .5rem;border-bottom:1px solid var(--ft-activity-animation-accent)}@keyframes text-rotation{0%{opacity:0}1%{opacity:0;transform:translateY(-20px)}3.5%{opacity:1;transform:translateY(0)}11%{opacity:1;transform:translateY(0)}12.5%{opacity:0;transform:translateY(20px)}20%{opacity:0}100%{opacity:0}}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container{display:flex;justify-content:center;padding-top:.5rem;height:2rem}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item{animation:text-rotation 4.05s ease-in-out infinite 0s;font-size:1rem;opacity:0;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(2){animation-delay:.45s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(3){animation-delay:.9s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(4){animation-delay:1.35s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(5){animation-delay:1.8s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(6){animation-delay:2.25s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(7){animation-delay:2.7s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(8){animation-delay:3.15s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(9){animation-delay:3.6s}.ft-translatable-language-list .iso-code,.ft-translatable-language-list .name,.ft-translatable-language-list .separator{display:inline-block}.ft-translatable-language-list .iso-code{display:inline-block;padding:0 .25rem;text-align:right}.ft-translatable-language-list .separator{padding:0 .15rem}.ft-translatable-language-list .name{padding:0 .3rem}.button-donate{margin:2.5rem auto 1rem;width:180px} + );--ft-flash-error-background:var(--ft-error-1);--ft-activity-message-success-background:rgba(34, 156, 53, 0.6);--ft-activity-message-background:rgba(83, 121, 162, 0.8);--ft-activity-animation-accent:rgba(255, 255, 255, 0.3);--ft-activity-text-color:rgb(255, 255, 255);--ft-inputfield-state-default-border:2px solid rgb(255, 255, 255);--ft-inputfield-state-modified-border:2px solid #60caad;--ft-inputfield-translate-status-color:rgb(135, 135, 135);--ft-inputfield-translate-icon-color:rgb(135, 135, 135);--ft-secondary-translate-button-container-border:rgb(201, 201, 201);--button-disabled:rgb(201, 201, 201);--text-disabled:rgb(135, 135, 135)}.ft-activity-overlay-container{position:relative}@keyframes backround-scroll{0%{background-position:100% 0}100%{background-position:-100% 0}}.ft-activity-overlay-container .ft-activity-overlay{align-items:center;outline:1px solid var(--ft-white);color:var(--ft-activity-text-color);display:flex;height:100%;justify-content:center;opacity:0;pointer-events:none;position:absolute;left:0;top:0;transition:opacity .3s;width:100%;z-index:10}.ft-activity-overlay-container .ft-activity-overlay.visible{opacity:1;pointer-events:initial}.ft-activity-overlay-container .ft-activity-overlay .ft-activity,.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message{align-items:center;display:flex;height:100%;justify-content:center;opacity:0;position:absolute;width:100%;transition:opacity 1s;font-size:1.1rem}.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message{background-color:var(--ft-activity-message-background);padding:1rem;text-align:center}.ft-activity-overlay-container .ft-activity-overlay.message .ft-activity-message{opacity:1}.ft-activity-overlay-container .ft-activity-overlay.message.error .ft-activity-message{animation:backround-scroll 7s reverse linear infinite;background:var(--ft-activity-animation-error-background);background-size:200% 100%}.ft-activity-overlay-container .ft-activity-overlay.message.error.flash .ft-activity-message{background:var(--ft-flash-error-background)}.ft-activity-overlay-container .ft-activity-overlay.message.success .ft-activity-message{background-color:var(--ft-activity-message-success-background);transition:opacity .1s}.ft-activity-overlay-container .ft-activity-overlay.message.success.flash{transition:opacity .1s}.ft-activity-overlay-container .ft-activity-overlay.activity .ft-activity{opacity:1}.ft-activity-overlay-container .ft-activity-overlay .ft-activity{animation:backround-scroll 3.5s linear infinite;background:var(--ft-activity-animation-background);background-size:200% 100%;flex-direction:column;font-size:1rem;justify-content:center;letter-spacing:2px;opacity:0}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-text{text-align:center;font-size:1.15rem;padding:0 5rem .5rem;border-bottom:1px solid var(--ft-activity-animation-accent)}@keyframes text-rotation{0%{opacity:0}1%{opacity:0;transform:translateY(-20px)}3.5%{opacity:1;transform:translateY(0)}11%{opacity:1;transform:translateY(0)}12.5%{opacity:0;transform:translateY(20px)}20%{opacity:0}100%{opacity:0}}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container{display:flex;justify-content:center;padding-top:.5rem;height:2rem}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item{animation:text-rotation 4.05s ease-in-out infinite 0s;font-size:1rem;opacity:0;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(2){animation-delay:.45s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(3){animation-delay:.9s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(4){animation-delay:1.35s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(5){animation-delay:1.8s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(6){animation-delay:2.25s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(7){animation-delay:2.7s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(8){animation-delay:3.15s}.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(9){animation-delay:3.6s}.ft-translatable-language-list .iso-code,.ft-translatable-language-list .name,.ft-translatable-language-list .separator{display:inline-block}.ft-translatable-language-list .iso-code{display:inline-block;padding:0 .25rem;text-align:right}.ft-translatable-language-list .separator{padding:0 .15rem}.ft-translatable-language-list .name{padding:0 .3rem}.button-donate{display:block;margin:2.5rem auto 1rem;width:180px}.button-donate img{width:100%} /*# sourceMappingURL=maps/fluency_module_config.min.css.map */ diff --git a/assets/styles/maps/fluency_module_config.min.css.map b/assets/styles/maps/fluency_module_config.min.css.map index b70a35d..4e7b515 100755 --- a/assets/styles/maps/fluency_module_config.min.css.map +++ b/assets/styles/maps/fluency_module_config.min.css.map @@ -1 +1 @@ -{"version":3,"sources":["global/_ft_variables.scss","components/_ft_activity_overlay.scss","fluency_module_config.css","components/_ft_translatable_language_list.scss","fluency_module_config.scss"],"names":[],"mappings":"AAqBA,MAEE,WAAA,mBAGA,aAAA,kBACA,mBAAA,QAEA,eAAA,kBACA,qBAAA,QACA,oBAAA,iBAEA,UAAA,gBAEA,gBAAA,yBACA,gBAAA,yBACA,gBAAA,yBAEA,mCAAA;;;;;;;CASA,aAAA,yBACA,aAAA,uBAEA,yCAAA;;;;;;;CASA,4BAAA,kBAEA,yCAAA,uBAEA,iCAAA,wBAEA,+BAAA,yBAEA,yBAAA,mBAEA,qCAAA,IAAA,MAAA,mBAEA,sCAAA,IAAA,MAAA,QAEA,uCAAA,mBAEA,qCAAA,mBAEA,iDAAA,mBAEA,kBAAA,mBAEA,gBAAA,mBClEF,+BACE,SAAA,SAEA,4BACE,GACE,oBAAA,KAAA,EAEF,KACE,oBAAA,MAAA,GAIJ,oDACE,YAAA,OACA,QAAA,IAAA,MAAA,gBACA,MAAA,8BACA,QAAA,KACA,OAAA,KACA,gBAAA,OACA,QAAA,EACA,eAAA,KACA,SAAA,SACA,KAAA,EACA,IAAA,EACA,WAAA,QAAA,IACA,MAAA,KACA,QAAA,GAEA,4DACE,QAAA,EACA,eAAA,QAGF,iECuCJ,yEDrCM,YAAA,OACA,QAAA,KACA,OAAA,KACA,gBAAA,OACA,QAAA,EACA,SAAA,SACA,MAAA,KACA,WAAA,QAAA,GACA,UAAA,OAGF,yEACE,iBAAA,sCACA,QAAA,KACA,WAAA,OAIA,iFACE,QAAA,EAKF,uFACE,UAAA,iBAAA,GAAA,QAAA,OAAA,SACA,WAAA,8CACA,gBAAA,KAAA,KAIA,6FACE,WAAA,iCAMJ,yFACE,iBAAA,8CACA,WAAA,QAAA,IAGF,0EACE,WAAA,QAAA,IAMF,0EACE,QAAA,EAMJ,iEACE,UAAA,iBAAA,KAAA,OAAA,SACA,WAAA,wCACA,gBAAA,KAAA,KACA,eAAA,OACA,UAAA,KACA,gBAAA,OACA,eAAA,IACA,QAAA,EAEA,mFACE,WAAA,OACA,UAAA,QACA,QAAA,EAAA,KAAA,MACA,cAAA,IAAA,MAAA,oCAGF,yBACE,GACE,QAAA,EAEF,GACE,QAAA,EACA,UAAA,kBAEF,KACE,QAAA,EACA,UAAA,cAEF,IACE,QAAA,EACA,UAAA,cAEF,MACE,QAAA,EACA,UAAA,iBAEF,IACE,QAAA,EAEF,KACE,QAAA,GAIJ,kGACE,QAAA,KACA,gBAAA,OACA,YAAA,MACA,OAAA,KAEA,8HACE,UAAA,cAAA,MAAA,YAAA,SAAA,GACA,UAAA,KACA,QAAA,EACA,SAAA,SACA,oBAAA,KAAA,iBAAA,KAAA,YAAA,KAEA,6IACE,gBAAA,KAEF,6IACE,gBAAA,IAEF,6IACE,gBAAA,MAEF,6IACE,gBAAA,KAEF,6IACE,gBAAA,MAEF,6IACE,gBAAA,KAEF,6IACE,gBAAA,MAEF,6IACE,gBAAA,KE3LV,yCDiNF,qCADA,0CC7MI,QAAA,aAGF,yCACE,QAAA,aACA,QAAA,EAAA,OACA,WAAA,MAGF,0CACE,QAAA,EAAA,OAGF,qCACE,QAAA,EAAA,MCXJ,eACE,OAAA,OAAA,KAAA,KACA,MAAA","file":"../fluency_module_config.min.css","sourcesContent":["// Colors\n\n// Reds\n$cerise-red: rgb(248, 30, 102); // ProcessWire Pink\n$crimson: rgb(210, 24, 70); // ProcessWire Pink (Dark)\n$brink-pink: rgb(255, 102, 108);\n\n// Greens\n$puerto-rico: rgb(62, 185, 152); // ProcessWire Teal\n$forest-green: rgb(34, 156, 53);\n\n// Blues\n$pickled-bluewood: rgb(53, 75, 96);\n$dodger-blue: rgb(51, 153, 255);\n$wedgewood: rgb(83, 121, 162);\n\n// Grayscales\n$white: rgb(255, 255, 255);\n$silver: rgb(201, 201, 201);\n$monsoon: rgb(135, 135, 135);\n\n:root {\n // Colors\n --ft-white: #{$white};\n\n // Theme\n --ft-primary: #{$puerto-rico};\n --ft-primary-light: #{lighten($puerto-rico, 10)};\n\n --ft-secondary: #{$cerise-red};\n --ft-secondary-light: #{lighten($cerise-red, 15)};\n --ft-secondary-dark: #{$crimson};\n\n --ft-text: #{$pickled-bluewood};\n\n --ft-activity-1: #{rgba(darken($puerto-rico, 5), 0.85)};\n --ft-activity-2: #{rgba($puerto-rico, 0.85)};\n --ft-activity-3: #{rgba(lighten($puerto-rico, 10), 0.85)};\n\n --ft-activity-animation-background: linear-gradient(\n 90deg,\n var(--ft-activity-1),\n var(--ft-activity-2),\n var(--ft-activity-3),\n var(--ft-activity-2),\n var(--ft-activity-1)\n );\n\n --ft-error-1: #{rgba($brink-pink, 0.8)};\n --ft-error-2: #{rgba(darken($brink-pink, 15), 0.8)};\n\n --ft-activity-animation-error-background: linear-gradient(\n 90deg,\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1)\n );\n\n --ft-flash-error-background: var(--ft-error-1);\n\n --ft-activity-message-success-background: #{rgba($forest-green, 0.6)};\n\n --ft-activity-message-background: #{rgba($wedgewood, 0.8)};\n\n --ft-activity-animation-accent: #{rgba($white, 0.3)};\n\n --ft-activity-text-color: #{$white};\n\n --ft-inputfield-state-default-border: 2px solid #{$white};\n\n --ft-inputfield-state-modified-border: 2px solid #{lighten($puerto-rico, 10)};\n\n --ft-inputfield-translate-status-color: #{$monsoon};\n\n --ft-inputfield-translate-icon-color: #{$monsoon};\n\n --ft-secondary-translate-button-container-border: #{$silver};\n\n --button-disabled: #{$silver};\n\n --text-disabled: #{$monsoon};\n}\n","/*\n Begin animated overlays\n - Overlays consist of a div element appended to a field/fieldset which is\n shown during a given operation. The animation is consistent with the\n name of the operation translated into 9 languages that rapidly cycle\n during the process to illustrate the multi-language capabilities as a design\n flare.\n\n*/\n\n// Classes are defined in FtActivityOverlay.js\n\n/*\n Allows the overlay to be contained with position: absolute to it's\n respective container\n*/\n.ft-activity-overlay-container {\n position: relative;\n\n @keyframes backround-scroll {\n 0% {\n background-position: 100% 0;\n }\n 100% {\n background-position: -100% 0;\n }\n }\n\n .ft-activity-overlay {\n align-items: center;\n outline: 1px solid var(--ft-white);\n color: var(--ft-activity-text-color);\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n position: absolute;\n left: 0;\n top: 0;\n transition: opacity 0.3s;\n width: 100%;\n z-index: 10;\n\n &.visible {\n opacity: 1;\n pointer-events: initial;\n }\n\n .ft-activity,\n .ft-activity-message {\n align-items: center;\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n position: absolute;\n width: 100%;\n transition: opacity 1s;\n font-size: 1.1rem;\n }\n\n .ft-activity-message {\n background-color: var(--ft-activity-message-background);\n padding: 1rem;\n text-align: center;\n }\n\n &.message {\n .ft-activity-message {\n opacity: 1;\n }\n }\n\n &.message.error {\n .ft-activity-message {\n animation: backround-scroll 7s reverse linear infinite;\n background: var(--ft-activity-animation-error-background);\n background-size: 200% 100%;\n }\n\n &.flash {\n .ft-activity-message {\n background: var(--ft-flash-error-background);\n }\n }\n }\n\n &.message.success {\n .ft-activity-message {\n background-color: var(--ft-activity-message-success-background);\n transition: opacity 0.1s;\n }\n\n &.flash {\n transition: opacity 0.1s;\n }\n }\n\n // Show the activity component\n &.activity {\n .ft-activity {\n opacity: 1;\n }\n }\n\n // Animated background for activity\n\n .ft-activity {\n animation: backround-scroll 3.5s linear infinite;\n background: var(--ft-activity-animation-background);\n background-size: 200% 100%;\n flex-direction: column;\n font-size: 1rem;\n justify-content: center;\n letter-spacing: 2px;\n opacity: 0;\n\n .ft-activity-text {\n text-align: center;\n font-size: 1.15rem;\n padding: 0 5rem 0.5rem;\n border-bottom: 1px solid var(--ft-activity-animation-accent);\n }\n\n @keyframes text-rotation {\n 0% {\n opacity: 0;\n }\n 1% {\n opacity: 0;\n transform: translateY(-20px);\n }\n 3.5% {\n opacity: 1;\n transform: translateY(0px);\n }\n 11% {\n opacity: 1;\n transform: translateY(0px);\n }\n 12.5% {\n opacity: 0;\n transform: translateY(20px);\n }\n 20% {\n opacity: 0;\n }\n 100% {\n opacity: 0;\n }\n }\n\n .ft-activity-animation-container {\n display: flex;\n justify-content: center;\n padding-top: 0.5rem;\n height: 2rem;\n\n .ft-activity-animation-item {\n animation: text-rotation 4.05s ease-in-out infinite 0s;\n font-size: 1rem;\n opacity: 0;\n position: absolute;\n user-select: none;\n\n &:nth-of-type(2) {\n animation-delay: 0.45s;\n }\n &:nth-of-type(3) {\n animation-delay: 0.9s;\n }\n &:nth-of-type(4) {\n animation-delay: 1.35s;\n }\n &:nth-of-type(5) {\n animation-delay: 1.8s;\n }\n &:nth-of-type(6) {\n animation-delay: 2.25s;\n }\n &:nth-of-type(7) {\n animation-delay: 2.7s;\n }\n &:nth-of-type(8) {\n animation-delay: 3.15s;\n }\n &:nth-of-type(9) {\n animation-delay: 3.6s;\n }\n }\n }\n }\n }\n}\n",":root {\n --ft-white: rgb(255, 255, 255);\n --ft-primary: rgb(62, 185, 152);\n --ft-primary-light: #60caad;\n --ft-secondary: rgb(248, 30, 102);\n --ft-secondary-light: #fa6898;\n --ft-secondary-dark: rgb(210, 24, 70);\n --ft-text: rgb(53, 75, 96);\n --ft-activity-1: rgba(56, 166, 136, 0.85);\n --ft-activity-2: rgba(62, 185, 152, 0.85);\n --ft-activity-3: rgba(96, 202, 173, 0.85);\n --ft-activity-animation-background: linear-gradient(\n 90deg,\n var(--ft-activity-1),\n var(--ft-activity-2),\n var(--ft-activity-3),\n var(--ft-activity-2),\n var(--ft-activity-1)\n );\n --ft-error-1: rgba(255, 102, 108, 0.8);\n --ft-error-2: rgba(255, 26, 35, 0.8);\n --ft-activity-animation-error-background: linear-gradient(\n 90deg,\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1)\n );\n --ft-flash-error-background: var(--ft-error-1);\n --ft-activity-message-success-background: rgba(34, 156, 53, 0.6);\n --ft-activity-message-background: rgba(83, 121, 162, 0.8);\n --ft-activity-animation-accent: rgba(255, 255, 255, 0.3);\n --ft-activity-text-color: rgb(255, 255, 255);\n --ft-inputfield-state-default-border: 2px solid rgb(255, 255, 255);\n --ft-inputfield-state-modified-border: 2px solid #60caad;\n --ft-inputfield-translate-status-color: rgb(135, 135, 135);\n --ft-inputfield-translate-icon-color: rgb(135, 135, 135);\n --ft-secondary-translate-button-container-border: rgb(201, 201, 201);\n --button-disabled: rgb(201, 201, 201);\n --text-disabled: rgb(135, 135, 135);\n}\n\n/*\n Begin animated overlays\n - Overlays consist of a div element appended to a field/fieldset which is\n shown during a given operation. The animation is consistent with the\n name of the operation translated into 9 languages that rapidly cycle\n during the process to illustrate the multi-language capabilities as a design\n flare.\n\n*/\n/*\n Allows the overlay to be contained with position: absolute to it's\n respective container\n*/\n.ft-activity-overlay-container {\n position: relative;\n}\n@keyframes backround-scroll {\n 0% {\n background-position: 100% 0;\n }\n 100% {\n background-position: -100% 0;\n }\n}\n.ft-activity-overlay-container .ft-activity-overlay {\n align-items: center;\n outline: 1px solid var(--ft-white);\n color: var(--ft-activity-text-color);\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n position: absolute;\n left: 0;\n top: 0;\n transition: opacity 0.3s;\n width: 100%;\n z-index: 10;\n}\n.ft-activity-overlay-container .ft-activity-overlay.visible {\n opacity: 1;\n pointer-events: initial;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity,\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message {\n align-items: center;\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n position: absolute;\n width: 100%;\n transition: opacity 1s;\n font-size: 1.1rem;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message {\n background-color: var(--ft-activity-message-background);\n padding: 1rem;\n text-align: center;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message .ft-activity-message {\n opacity: 1;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.error .ft-activity-message {\n animation: backround-scroll 7s reverse linear infinite;\n background: var(--ft-activity-animation-error-background);\n background-size: 200% 100%;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.error.flash .ft-activity-message {\n background: var(--ft-flash-error-background);\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.success .ft-activity-message {\n background-color: var(--ft-activity-message-success-background);\n transition: opacity 0.1s;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.success.flash {\n transition: opacity 0.1s;\n}\n.ft-activity-overlay-container .ft-activity-overlay.activity .ft-activity {\n opacity: 1;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity {\n animation: backround-scroll 3.5s linear infinite;\n background: var(--ft-activity-animation-background);\n background-size: 200% 100%;\n flex-direction: column;\n font-size: 1rem;\n justify-content: center;\n letter-spacing: 2px;\n opacity: 0;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-text {\n text-align: center;\n font-size: 1.15rem;\n padding: 0 5rem 0.5rem;\n border-bottom: 1px solid var(--ft-activity-animation-accent);\n}\n@keyframes text-rotation {\n 0% {\n opacity: 0;\n }\n 1% {\n opacity: 0;\n transform: translateY(-20px);\n }\n 3.5% {\n opacity: 1;\n transform: translateY(0px);\n }\n 11% {\n opacity: 1;\n transform: translateY(0px);\n }\n 12.5% {\n opacity: 0;\n transform: translateY(20px);\n }\n 20% {\n opacity: 0;\n }\n 100% {\n opacity: 0;\n }\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container {\n display: flex;\n justify-content: center;\n padding-top: 0.5rem;\n height: 2rem;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item {\n animation: text-rotation 4.05s ease-in-out infinite 0s;\n font-size: 1rem;\n opacity: 0;\n position: absolute;\n user-select: none;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(2) {\n animation-delay: 0.45s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(3) {\n animation-delay: 0.9s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(4) {\n animation-delay: 1.35s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(5) {\n animation-delay: 1.8s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(6) {\n animation-delay: 2.25s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(7) {\n animation-delay: 2.7s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(8) {\n animation-delay: 3.15s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(9) {\n animation-delay: 3.6s;\n}\n\n.ft-translatable-language-list .iso-code,\n.ft-translatable-language-list .separator,\n.ft-translatable-language-list .name {\n display: inline-block;\n}\n.ft-translatable-language-list .iso-code {\n display: inline-block;\n padding: 0 0.25rem;\n text-align: right;\n}\n.ft-translatable-language-list .separator {\n padding: 0 0.15rem;\n}\n.ft-translatable-language-list .name {\n padding: 0 0.3rem;\n}\n\n.button-donate {\n margin: 2.5rem auto 1rem;\n width: 180px;\n}",".ft-translatable-language-list {\n .iso-code,\n .separator,\n .name {\n display: inline-block;\n }\n\n .iso-code {\n display: inline-block;\n padding: 0 0.25rem;\n text-align: right;\n }\n\n .separator {\n padding: 0 0.15rem;\n }\n\n .name {\n padding: 0 0.3rem;\n }\n}\n","@charset \"utf-8\";\n\n@import 'global/ft_variables';\n\n@import 'components/ft_activity_overlay';\n@import 'components/ft_translatable_language_list';\n\n.button-donate {\n margin: 2.5rem auto 1rem;\n width: 180px;\n}\n"]} \ No newline at end of file +{"version":3,"sources":["global/_ft_variables.scss","components/_ft_activity_overlay.scss","fluency_module_config.css","components/_ft_translatable_language_list.scss","fluency_module_config.scss"],"names":[],"mappings":"AAqBA,MAEE,WAAA,mBAGA,aAAA,kBACA,mBAAA,QAEA,eAAA,kBACA,qBAAA,QACA,oBAAA,iBAEA,UAAA,gBAEA,gBAAA,yBACA,gBAAA,yBACA,gBAAA,yBAEA,mCAAA;;;;;;;CASA,aAAA,yBACA,aAAA,uBAEA,yCAAA;;;;;;;CASA,4BAAA,kBAEA,yCAAA,uBAEA,iCAAA,wBAEA,+BAAA,yBAEA,yBAAA,mBAEA,qCAAA,IAAA,MAAA,mBAEA,sCAAA,IAAA,MAAA,QAEA,uCAAA,mBAEA,qCAAA,mBAEA,iDAAA,mBAEA,kBAAA,mBAEA,gBAAA,mBClEF,+BACE,SAAA,SAEA,4BACE,GACE,oBAAA,KAAA,EAEF,KACE,oBAAA,MAAA,GAIJ,oDACE,YAAA,OACA,QAAA,IAAA,MAAA,gBACA,MAAA,8BACA,QAAA,KACA,OAAA,KACA,gBAAA,OACA,QAAA,EACA,eAAA,KACA,SAAA,SACA,KAAA,EACA,IAAA,EACA,WAAA,QAAA,IACA,MAAA,KACA,QAAA,GAEA,4DACE,QAAA,EACA,eAAA,QAGF,iECuCJ,yEDrCM,YAAA,OACA,QAAA,KACA,OAAA,KACA,gBAAA,OACA,QAAA,EACA,SAAA,SACA,MAAA,KACA,WAAA,QAAA,GACA,UAAA,OAGF,yEACE,iBAAA,sCACA,QAAA,KACA,WAAA,OAIA,iFACE,QAAA,EAKF,uFACE,UAAA,iBAAA,GAAA,QAAA,OAAA,SACA,WAAA,8CACA,gBAAA,KAAA,KAIA,6FACE,WAAA,iCAMJ,yFACE,iBAAA,8CACA,WAAA,QAAA,IAGF,0EACE,WAAA,QAAA,IAMF,0EACE,QAAA,EAMJ,iEACE,UAAA,iBAAA,KAAA,OAAA,SACA,WAAA,wCACA,gBAAA,KAAA,KACA,eAAA,OACA,UAAA,KACA,gBAAA,OACA,eAAA,IACA,QAAA,EAEA,mFACE,WAAA,OACA,UAAA,QACA,QAAA,EAAA,KAAA,MACA,cAAA,IAAA,MAAA,oCAGF,yBACE,GACE,QAAA,EAEF,GACE,QAAA,EACA,UAAA,kBAEF,KACE,QAAA,EACA,UAAA,cAEF,IACE,QAAA,EACA,UAAA,cAEF,MACE,QAAA,EACA,UAAA,iBAEF,IACE,QAAA,EAEF,KACE,QAAA,GAIJ,kGACE,QAAA,KACA,gBAAA,OACA,YAAA,MACA,OAAA,KAEA,8HACE,UAAA,cAAA,MAAA,YAAA,SAAA,GACA,UAAA,KACA,QAAA,EACA,SAAA,SACA,oBAAA,KAAA,iBAAA,KAAA,YAAA,KAEA,6IACE,gBAAA,KAEF,6IACE,gBAAA,IAEF,6IACE,gBAAA,MAEF,6IACE,gBAAA,KAEF,6IACE,gBAAA,MAEF,6IACE,gBAAA,KAEF,6IACE,gBAAA,MAEF,6IACE,gBAAA,KE3LV,yCDiNF,qCADA,0CC7MI,QAAA,aAGF,yCACE,QAAA,aACA,QAAA,EAAA,OACA,WAAA,MAGF,0CACE,QAAA,EAAA,OAGF,qCACE,QAAA,EAAA,MCXJ,eACE,QAAA,MACA,OAAA,OAAA,KAAA,KACA,MAAA,MAEA,mBACE,MAAA","file":"../fluency_module_config.min.css","sourcesContent":["// Colors\n\n// Reds\n$cerise-red: rgb(248, 30, 102); // ProcessWire Pink\n$crimson: rgb(210, 24, 70); // ProcessWire Pink (Dark)\n$brink-pink: rgb(255, 102, 108);\n\n// Greens\n$puerto-rico: rgb(62, 185, 152); // ProcessWire Teal\n$forest-green: rgb(34, 156, 53);\n\n// Blues\n$pickled-bluewood: rgb(53, 75, 96);\n$dodger-blue: rgb(51, 153, 255);\n$wedgewood: rgb(83, 121, 162);\n\n// Grayscales\n$white: rgb(255, 255, 255);\n$silver: rgb(201, 201, 201);\n$monsoon: rgb(135, 135, 135);\n\n:root {\n // Colors\n --ft-white: #{$white};\n\n // Theme\n --ft-primary: #{$puerto-rico};\n --ft-primary-light: #{lighten($puerto-rico, 10)};\n\n --ft-secondary: #{$cerise-red};\n --ft-secondary-light: #{lighten($cerise-red, 15)};\n --ft-secondary-dark: #{$crimson};\n\n --ft-text: #{$pickled-bluewood};\n\n --ft-activity-1: #{rgba(darken($puerto-rico, 5), 0.85)};\n --ft-activity-2: #{rgba($puerto-rico, 0.85)};\n --ft-activity-3: #{rgba(lighten($puerto-rico, 10), 0.85)};\n\n --ft-activity-animation-background: linear-gradient(\n 90deg,\n var(--ft-activity-1),\n var(--ft-activity-2),\n var(--ft-activity-3),\n var(--ft-activity-2),\n var(--ft-activity-1)\n );\n\n --ft-error-1: #{rgba($brink-pink, 0.8)};\n --ft-error-2: #{rgba(darken($brink-pink, 15), 0.8)};\n\n --ft-activity-animation-error-background: linear-gradient(\n 90deg,\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1)\n );\n\n --ft-flash-error-background: var(--ft-error-1);\n\n --ft-activity-message-success-background: #{rgba($forest-green, 0.6)};\n\n --ft-activity-message-background: #{rgba($wedgewood, 0.8)};\n\n --ft-activity-animation-accent: #{rgba($white, 0.3)};\n\n --ft-activity-text-color: #{$white};\n\n --ft-inputfield-state-default-border: 2px solid #{$white};\n\n --ft-inputfield-state-modified-border: 2px solid #{lighten($puerto-rico, 10)};\n\n --ft-inputfield-translate-status-color: #{$monsoon};\n\n --ft-inputfield-translate-icon-color: #{$monsoon};\n\n --ft-secondary-translate-button-container-border: #{$silver};\n\n --button-disabled: #{$silver};\n\n --text-disabled: #{$monsoon};\n}\n","/*\n Begin animated overlays\n - Overlays consist of a div element appended to a field/fieldset which is\n shown during a given operation. The animation is consistent with the\n name of the operation translated into 9 languages that rapidly cycle\n during the process to illustrate the multi-language capabilities as a design\n flare.\n\n*/\n\n// Classes are defined in FtActivityOverlay.js\n\n/*\n Allows the overlay to be contained with position: absolute to it's\n respective container\n*/\n.ft-activity-overlay-container {\n position: relative;\n\n @keyframes backround-scroll {\n 0% {\n background-position: 100% 0;\n }\n 100% {\n background-position: -100% 0;\n }\n }\n\n .ft-activity-overlay {\n align-items: center;\n outline: 1px solid var(--ft-white);\n color: var(--ft-activity-text-color);\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n position: absolute;\n left: 0;\n top: 0;\n transition: opacity 0.3s;\n width: 100%;\n z-index: 10;\n\n &.visible {\n opacity: 1;\n pointer-events: initial;\n }\n\n .ft-activity,\n .ft-activity-message {\n align-items: center;\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n position: absolute;\n width: 100%;\n transition: opacity 1s;\n font-size: 1.1rem;\n }\n\n .ft-activity-message {\n background-color: var(--ft-activity-message-background);\n padding: 1rem;\n text-align: center;\n }\n\n &.message {\n .ft-activity-message {\n opacity: 1;\n }\n }\n\n &.message.error {\n .ft-activity-message {\n animation: backround-scroll 7s reverse linear infinite;\n background: var(--ft-activity-animation-error-background);\n background-size: 200% 100%;\n }\n\n &.flash {\n .ft-activity-message {\n background: var(--ft-flash-error-background);\n }\n }\n }\n\n &.message.success {\n .ft-activity-message {\n background-color: var(--ft-activity-message-success-background);\n transition: opacity 0.1s;\n }\n\n &.flash {\n transition: opacity 0.1s;\n }\n }\n\n // Show the activity component\n &.activity {\n .ft-activity {\n opacity: 1;\n }\n }\n\n // Animated background for activity\n\n .ft-activity {\n animation: backround-scroll 3.5s linear infinite;\n background: var(--ft-activity-animation-background);\n background-size: 200% 100%;\n flex-direction: column;\n font-size: 1rem;\n justify-content: center;\n letter-spacing: 2px;\n opacity: 0;\n\n .ft-activity-text {\n text-align: center;\n font-size: 1.15rem;\n padding: 0 5rem 0.5rem;\n border-bottom: 1px solid var(--ft-activity-animation-accent);\n }\n\n @keyframes text-rotation {\n 0% {\n opacity: 0;\n }\n 1% {\n opacity: 0;\n transform: translateY(-20px);\n }\n 3.5% {\n opacity: 1;\n transform: translateY(0px);\n }\n 11% {\n opacity: 1;\n transform: translateY(0px);\n }\n 12.5% {\n opacity: 0;\n transform: translateY(20px);\n }\n 20% {\n opacity: 0;\n }\n 100% {\n opacity: 0;\n }\n }\n\n .ft-activity-animation-container {\n display: flex;\n justify-content: center;\n padding-top: 0.5rem;\n height: 2rem;\n\n .ft-activity-animation-item {\n animation: text-rotation 4.05s ease-in-out infinite 0s;\n font-size: 1rem;\n opacity: 0;\n position: absolute;\n user-select: none;\n\n &:nth-of-type(2) {\n animation-delay: 0.45s;\n }\n &:nth-of-type(3) {\n animation-delay: 0.9s;\n }\n &:nth-of-type(4) {\n animation-delay: 1.35s;\n }\n &:nth-of-type(5) {\n animation-delay: 1.8s;\n }\n &:nth-of-type(6) {\n animation-delay: 2.25s;\n }\n &:nth-of-type(7) {\n animation-delay: 2.7s;\n }\n &:nth-of-type(8) {\n animation-delay: 3.15s;\n }\n &:nth-of-type(9) {\n animation-delay: 3.6s;\n }\n }\n }\n }\n }\n}\n",":root {\n --ft-white: rgb(255, 255, 255);\n --ft-primary: rgb(62, 185, 152);\n --ft-primary-light: #60caad;\n --ft-secondary: rgb(248, 30, 102);\n --ft-secondary-light: #fa6898;\n --ft-secondary-dark: rgb(210, 24, 70);\n --ft-text: rgb(53, 75, 96);\n --ft-activity-1: rgba(56, 166, 136, 0.85);\n --ft-activity-2: rgba(62, 185, 152, 0.85);\n --ft-activity-3: rgba(96, 202, 173, 0.85);\n --ft-activity-animation-background: linear-gradient(\n 90deg,\n var(--ft-activity-1),\n var(--ft-activity-2),\n var(--ft-activity-3),\n var(--ft-activity-2),\n var(--ft-activity-1)\n );\n --ft-error-1: rgba(255, 102, 108, 0.8);\n --ft-error-2: rgba(255, 26, 35, 0.8);\n --ft-activity-animation-error-background: linear-gradient(\n 90deg,\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1),\n var(--ft-error-2),\n var(--ft-error-1)\n );\n --ft-flash-error-background: var(--ft-error-1);\n --ft-activity-message-success-background: rgba(34, 156, 53, 0.6);\n --ft-activity-message-background: rgba(83, 121, 162, 0.8);\n --ft-activity-animation-accent: rgba(255, 255, 255, 0.3);\n --ft-activity-text-color: rgb(255, 255, 255);\n --ft-inputfield-state-default-border: 2px solid rgb(255, 255, 255);\n --ft-inputfield-state-modified-border: 2px solid #60caad;\n --ft-inputfield-translate-status-color: rgb(135, 135, 135);\n --ft-inputfield-translate-icon-color: rgb(135, 135, 135);\n --ft-secondary-translate-button-container-border: rgb(201, 201, 201);\n --button-disabled: rgb(201, 201, 201);\n --text-disabled: rgb(135, 135, 135);\n}\n\n/*\n Begin animated overlays\n - Overlays consist of a div element appended to a field/fieldset which is\n shown during a given operation. The animation is consistent with the\n name of the operation translated into 9 languages that rapidly cycle\n during the process to illustrate the multi-language capabilities as a design\n flare.\n\n*/\n/*\n Allows the overlay to be contained with position: absolute to it's\n respective container\n*/\n.ft-activity-overlay-container {\n position: relative;\n}\n@keyframes backround-scroll {\n 0% {\n background-position: 100% 0;\n }\n 100% {\n background-position: -100% 0;\n }\n}\n.ft-activity-overlay-container .ft-activity-overlay {\n align-items: center;\n outline: 1px solid var(--ft-white);\n color: var(--ft-activity-text-color);\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n position: absolute;\n left: 0;\n top: 0;\n transition: opacity 0.3s;\n width: 100%;\n z-index: 10;\n}\n.ft-activity-overlay-container .ft-activity-overlay.visible {\n opacity: 1;\n pointer-events: initial;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity,\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message {\n align-items: center;\n display: flex;\n height: 100%;\n justify-content: center;\n opacity: 0;\n position: absolute;\n width: 100%;\n transition: opacity 1s;\n font-size: 1.1rem;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity-message {\n background-color: var(--ft-activity-message-background);\n padding: 1rem;\n text-align: center;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message .ft-activity-message {\n opacity: 1;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.error .ft-activity-message {\n animation: backround-scroll 7s reverse linear infinite;\n background: var(--ft-activity-animation-error-background);\n background-size: 200% 100%;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.error.flash .ft-activity-message {\n background: var(--ft-flash-error-background);\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.success .ft-activity-message {\n background-color: var(--ft-activity-message-success-background);\n transition: opacity 0.1s;\n}\n.ft-activity-overlay-container .ft-activity-overlay.message.success.flash {\n transition: opacity 0.1s;\n}\n.ft-activity-overlay-container .ft-activity-overlay.activity .ft-activity {\n opacity: 1;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity {\n animation: backround-scroll 3.5s linear infinite;\n background: var(--ft-activity-animation-background);\n background-size: 200% 100%;\n flex-direction: column;\n font-size: 1rem;\n justify-content: center;\n letter-spacing: 2px;\n opacity: 0;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-text {\n text-align: center;\n font-size: 1.15rem;\n padding: 0 5rem 0.5rem;\n border-bottom: 1px solid var(--ft-activity-animation-accent);\n}\n@keyframes text-rotation {\n 0% {\n opacity: 0;\n }\n 1% {\n opacity: 0;\n transform: translateY(-20px);\n }\n 3.5% {\n opacity: 1;\n transform: translateY(0px);\n }\n 11% {\n opacity: 1;\n transform: translateY(0px);\n }\n 12.5% {\n opacity: 0;\n transform: translateY(20px);\n }\n 20% {\n opacity: 0;\n }\n 100% {\n opacity: 0;\n }\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container {\n display: flex;\n justify-content: center;\n padding-top: 0.5rem;\n height: 2rem;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item {\n animation: text-rotation 4.05s ease-in-out infinite 0s;\n font-size: 1rem;\n opacity: 0;\n position: absolute;\n user-select: none;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(2) {\n animation-delay: 0.45s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(3) {\n animation-delay: 0.9s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(4) {\n animation-delay: 1.35s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(5) {\n animation-delay: 1.8s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(6) {\n animation-delay: 2.25s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(7) {\n animation-delay: 2.7s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(8) {\n animation-delay: 3.15s;\n}\n.ft-activity-overlay-container .ft-activity-overlay .ft-activity .ft-activity-animation-container .ft-activity-animation-item:nth-of-type(9) {\n animation-delay: 3.6s;\n}\n\n.ft-translatable-language-list .iso-code,\n.ft-translatable-language-list .separator,\n.ft-translatable-language-list .name {\n display: inline-block;\n}\n.ft-translatable-language-list .iso-code {\n display: inline-block;\n padding: 0 0.25rem;\n text-align: right;\n}\n.ft-translatable-language-list .separator {\n padding: 0 0.15rem;\n}\n.ft-translatable-language-list .name {\n padding: 0 0.3rem;\n}\n\n.button-donate {\n display: block;\n margin: 2.5rem auto 1rem;\n width: 180px;\n}\n.button-donate img {\n width: 100%;\n}",".ft-translatable-language-list {\n .iso-code,\n .separator,\n .name {\n display: inline-block;\n }\n\n .iso-code {\n display: inline-block;\n padding: 0 0.25rem;\n text-align: right;\n }\n\n .separator {\n padding: 0 0.15rem;\n }\n\n .name {\n padding: 0 0.3rem;\n }\n}\n","@charset \"utf-8\";\n\n@import 'global/ft_variables';\n\n@import 'components/ft_activity_overlay';\n@import 'components/ft_translatable_language_list';\n\n.button-donate {\n display: block;\n margin: 2.5rem auto 1rem;\n width: 180px;\n\n img {\n width: 100%;\n }\n}\n"]} \ No newline at end of file diff --git a/src/scss/fluency_module_config.scss b/src/scss/fluency_module_config.scss index 1343584..99918c7 100755 --- a/src/scss/fluency_module_config.scss +++ b/src/scss/fluency_module_config.scss @@ -6,6 +6,11 @@ @import 'components/ft_translatable_language_list'; .button-donate { + display: block; margin: 2.5rem auto 1rem; width: 180px; + + img { + width: 100%; + } }