From: Daniel Karbach Date: Mon, 6 Feb 2023 14:49:52 +0000 (+0100) Subject: tech attribution & requirements X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=f1c8c3cc53a09d1c261875d2f482b6e19bc48a9a;p=alttp.git tech attribution & requirements --- diff --git a/app/Models/Technique.php b/app/Models/Technique.php index c8ad91b..4469671 100644 --- a/app/Models/Technique.php +++ b/app/Models/Technique.php @@ -30,6 +30,7 @@ class Technique extends Model protected $casts = [ 'index' => 'boolean', + 'requirements' => 'array', 'rulesets' => 'array', ]; diff --git a/database/migrations/2023_02_06_124402_more_technique_properties.php b/database/migrations/2023_02_06_124402_more_technique_properties.php new file mode 100644 index 0000000..803fcc5 --- /dev/null +++ b/database/migrations/2023_02_06_124402_more_technique_properties.php @@ -0,0 +1,40 @@ +text('requirements')->nullable()->default(null); + $table->text('attribution')->default(''); + }); + Schema::table('technique_translations', function(Blueprint $table) { + $table->text('attribution')->default(''); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('techniques', function(Blueprint $table) { + $table->dropColumn('requirements'); + $table->dropColumn('attribution'); + }); + Schema::table('technique_translations', function(Blueprint $table) { + $table->dropColumn('attribution'); + }); + } +}; diff --git a/resources/js/components/common/Icon.js b/resources/js/components/common/Icon.js index 3e094cc..dd88669 100644 --- a/resources/js/components/common/Icon.js +++ b/resources/js/components/common/Icon.js @@ -81,6 +81,7 @@ Icon.REMOVE = makePreset('RemoveIcon', 'square-xmark'); Icon.RESULT = makePreset('ResultIcon', 'clock'); Icon.SECOND_PLACE = makePreset('SecondPlaceIcon', 'medal'); Icon.SETTINGS = makePreset('SettingsIcon', 'cog'); +Icon.SLASH = makePreset('SlashIcon', 'slash'); Icon.STREAM = makePreset('StreamIcon', ['fab', 'twitch']); Icon.THIRD_PLACE = makePreset('ThirdPlaceIcon', 'award'); Icon.TWITCH = makePreset('TwitchIcon', ['fab', 'twitch']); diff --git a/resources/js/components/common/ZeldaIcon.js b/resources/js/components/common/ZeldaIcon.js index 84f2220..c53f4fd 100644 --- a/resources/js/components/common/ZeldaIcon.js +++ b/resources/js/components/common/ZeldaIcon.js @@ -1,8 +1,8 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; -import i18n from '../../i18n'; +import Icon from './Icon'; const getIconURL = name => { switch (name) { @@ -64,17 +64,29 @@ const getIconURL = name => { } }; -const ZeldaIcon = ({ name }) => - - {i18n.t(`icon.zelda.${name}`)} -; +const ZeldaIcon = ({ name }) => { + const { t } = useTranslation(); + + const invert = name.startsWith('not-'); + const strippedName = invert ? name.substr(4) : name; + const title = t(`icon.zelda.${name}`); + + return + {title} + {invert ? + + + + : null} + ; +}; ZeldaIcon.propTypes = { name: PropTypes.string, }; -export default withTranslation()(ZeldaIcon); +export default ZeldaIcon; diff --git a/resources/js/components/techniques/Detail.js b/resources/js/components/techniques/Detail.js index 6653923..9d9534e 100644 --- a/resources/js/components/techniques/Detail.js +++ b/resources/js/components/techniques/Detail.js @@ -1,10 +1,11 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { Container } from 'react-bootstrap'; +import { Alert, Container } from 'react-bootstrap'; import { withTranslation } from 'react-i18next'; import List from './List'; import Outline from './Outline'; +import Requirements from './Requirements'; import Rulesets from './Rulesets'; import RawHTML from '../common/RawHTML'; import { @@ -23,6 +24,7 @@ const Detail = ({ technique }) => : null} + {technique.chapters ? technique.chapters.map(chapter =>
@@ -40,6 +42,11 @@ const Detail = ({ technique }) =>

{i18n.t('techniques.seeAlso')}

: null} + {getTranslation(technique, 'attribution', i18n.language) ? + + + + : null}
; Detail.propTypes = { diff --git a/resources/js/components/techniques/Requirement.js b/resources/js/components/techniques/Requirement.js new file mode 100644 index 0000000..5faa372 --- /dev/null +++ b/resources/js/components/techniques/Requirement.js @@ -0,0 +1,17 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +import ZeldaIcon from '../common/ZeldaIcon'; + +const Requirement = ({ requirement }) => +
+ {requirement.map(r => + + )} +
; + +Requirement.propTypes = { + requirement: PropTypes.arrayOf(PropTypes.string), +}; + +export default Requirement; diff --git a/resources/js/components/techniques/Requirements.js b/resources/js/components/techniques/Requirements.js new file mode 100644 index 0000000..0d4501e --- /dev/null +++ b/resources/js/components/techniques/Requirements.js @@ -0,0 +1,34 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import Requirement from './Requirement'; + +const Requirements = ({ technique }) => { + const { t } = useTranslation(); + + if (!technique.requirements || !technique.requirements.length) { + return null; + } + + return

+ {t('techniques.requirements')} +

    + {technique.requirements.map((r, i) => +
  • + +
  • + )} +
+

; +}; + +Requirements.propTypes = { + technique: PropTypes.shape({ + requirements: PropTypes.arrayOf( + PropTypes.arrayOf(PropTypes.string), + ), + }), +}; + +export default Requirements; diff --git a/resources/js/i18n/de.js b/resources/js/i18n/de.js index 02adc9d..f130c08 100644 --- a/resources/js/i18n/de.js +++ b/resources/js/i18n/de.js @@ -363,6 +363,8 @@ export default { mitts: 'Titan \'s Mitts', moonpearl: 'Moonpearl', mushroom: 'Mushroom', + 'not-flippers': 'Keine Flippers', + 'not-moonpearl': 'Keine Moonpearl', powder: 'Powder', quake: 'Quake', 'red-bomb': 'Red Bomb', @@ -508,6 +510,8 @@ export default { }, techniques: { heading: 'Techniken', + lastModified: 'Zuletzt geändert: {{ date, L }}', + requirements: 'Erfordert: ', rulesetCodes: { competitive: 'COM', mg: 'MG', diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js index efb99b3..a7ca19c 100644 --- a/resources/js/i18n/en.js +++ b/resources/js/i18n/en.js @@ -363,6 +363,8 @@ export default { mitts: 'Titan \'s Mitts', moonpearl: 'Moonpearl', mushroom: 'Mushroom', + 'not-flippers': 'No Flippers', + 'not-moonpearl': 'No Moonpearl', powder: 'Powder', quake: 'Quake', 'red-bomb': 'Red Bomb', @@ -508,6 +510,8 @@ export default { }, techniques: { heading: 'Techniques', + lastModified: 'Last modified: {{ date, L }}', + requirements: 'Requires: ', rulesetCodes: { competitive: 'COM', mg: 'MG', diff --git a/resources/sass/common.scss b/resources/sass/common.scss index 83e5b90..879253c 100644 --- a/resources/sass/common.scss +++ b/resources/sass/common.scss @@ -193,6 +193,7 @@ h1 { } .zelda-icon { + position: relative; display: inline-flex; align-items: center; width: 2em; @@ -203,4 +204,27 @@ h1 { max-width: 100%; max-height: 100%; } + .strike { + position: absolute; + top: 0; + left: 0; + width: 2em; + height: 2em; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + + svg { + width: 100%; + height: 100%; + } + + path { + fill: red; + stroke: black; + stroke-width: 1px; + vector-effect: non-scaling-stroke; + } + } } diff --git a/resources/sass/map.scss b/resources/sass/map.scss index 599cd15..38376a1 100644 --- a/resources/sass/map.scss +++ b/resources/sass/map.scss @@ -2,7 +2,7 @@ path { fill: red; stroke: black; - stroke-width: 2px; + stroke-width: 1px; vector-effect: non-scaling-stroke; } } diff --git a/resources/sass/techniques.scss b/resources/sass/techniques.scss index 8355e70..eff0c62 100644 --- a/resources/sass/techniques.scss +++ b/resources/sass/techniques.scss @@ -34,6 +34,33 @@ } } +.tech-requirements { + ul { + margin: 0; + padding: 0; + list-style: none; + } + li { + display: inline; + list-style: none; + margin: 0 1ex; + padding: 0; + + &::before { + display: inline; + content: " / "; + margin-right: 1ex; + } + &:first-child::before { + display: none; + } + } + .requirement { + display: inline-flex; + vertical-align: middle; + } +} + .tech-outline { float: right; }