protected $casts = [
'index' => 'boolean',
+ 'rulesets' => 'array',
];
protected $with = [
*/
public function down()
{
- Schema::table('rounds', function(Blueprint $table) {
+ Schema::table('techniques', function(Blueprint $table) {
$table->dropColumn('index');
$table->dropColumn('priority');
});
--- /dev/null
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::table('techniques', function(Blueprint $table) {
+ $table->text('rulesets')->nullable()->default(null);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('techniques', function(Blueprint $table) {
+ $table->dropColumn('rulesets');
+ });
+ }
+};
Icon.ACCEPT = makePreset('AcceptIcon', 'square-check');
Icon.ADD = makePreset('AddIcon', 'circle-plus');
+Icon.ALLOWED = makePreset('AllowedIcon', 'square-check');
Icon.APPLY = makePreset('ApplyIcon', 'right-to-bracket');
Icon.APPLICATIONS = makePreset('ApplicationsIcon', 'person-running');
Icon.CHART = makePreset('ChartIcon', 'chart-line');
Icon.EDIT = makePreset('EditIcon', 'edit');
Icon.FINISHED = makePreset('FinishedIcon', 'square-check');
Icon.FIRST_PLACE = makePreset('FirstPlaceIcon', 'trophy');
+Icon.FORBIDDEN = makePreset('ForbiddenIcon', 'square-xmark');
Icon.FORFEIT = makePreset('ForfeitIcon', 'square-xmark');
Icon.LANGUAGE = makePreset('LanguageIcon', 'language');
Icon.LOCKED = makePreset('LockedIcon', 'lock');
Icon.STREAM = makePreset('StreamIcon', ['fab', 'twitch']);
Icon.THIRD_PLACE = makePreset('ThirdPlaceIcon', 'award');
Icon.TWITCH = makePreset('TwitchIcon', ['fab', 'twitch']);
+Icon.UNKNOWN = makePreset('UnknownIcon', 'square-question');
Icon.UNLOCKED = makePreset('UnlockedIcon', 'lock-open');
Icon.VIDEO = makePreset('VideoIcon', 'video');
Icon.YOUTUBE = makePreset('YoutubeIcon', ['fab', 'youtube']);
import List from './List';
import Outline from './Outline';
+import Rulesets from './Rulesets';
import RawHTML from '../common/RawHTML';
import {
getRelations,
import i18n from '../../i18n';
const Detail = ({ technique }) => <Container as="article">
- <h1>{getTranslation(technique, 'title', i18n.language)}</h1>
+ <div className="d-flex align-items-center justify-content-between">
+ <h1>{getTranslation(technique, 'title', i18n.language)}</h1>
+ {technique && technique.rulesets ?
+ <Rulesets technique={technique} />
+ : null}
+ </div>
<Outline technique={technique} />
<RawHTML html={getTranslation(technique, 'description', i18n.language)} />
{technique.chapters ? technique.chapters.map(chapter =>
chapters: PropTypes.arrayOf(PropTypes.shape({
})),
description: PropTypes.string,
+ rulesets: PropTypes.shape({
+ }),
title: PropTypes.string,
}),
};
import React from 'react';
import { Link } from 'react-router-dom';
+import Rulesets from './Rulesets';
import {
getLink,
getTranslation,
const List = ({ techniques }) => <ul className="tech-list">
{techniques.map(tech =>
- <li key={tech.id}>
- <h2>
- <Link to={getLink(tech)}>
- {getTranslation(tech, 'title', i18n.language)}
- </Link>
- </h2>
- <p>{getTranslation(tech, 'short', i18n.language)}</p>
+ <li className="d-flex align-items-start justify-content-between" key={tech.id}>
+ <div>
+ <h2>
+ <Link to={getLink(tech)}>
+ {getTranslation(tech, 'title', i18n.language)}
+ </Link>
+ </h2>
+ <p>{getTranslation(tech, 'short', i18n.language)}</p>
+ </div>
+ {tech.rulesets ?
+ <Rulesets technique={tech} />
+ : null}
</li>
)}
</ul>;
--- /dev/null
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+
+const Rulesets = ({ technique }) => {
+ const { t } = useTranslation();
+
+ return <div className="ruleset-box">
+ {['competitive', 'owg', 'mg', 'nl'].map(r =>
+ <span key={r} title={t(`techniques.rulesetDescriptions.${r}`)}>
+ {technique && technique.rulesets && technique.rulesets[r] ?
+ <Icon.ALLOWED className="text-success" />
+ : null}
+ {technique && technique.rulesets && !technique.rulesets[r] ?
+ <Icon.FORBIDDEN className="text-danger" />
+ : null}
+ {!technique || !technique.rulesets ?
+ <Icon.UNKNOWN />
+ : null}
+ {' '}
+ {t(`techniques.rulesetCodes.${r}`)}
+ </span>
+ )}
+ </div>;
+};
+
+Rulesets.propTypes = {
+ technique: PropTypes.shape({
+ rulesets: PropTypes.shape({
+ }),
+ }),
+};
+
+export default Rulesets;
},
icon: {
AddIcon: 'Hinzufügen',
+ AllowedIcon: 'Erlaubt',
ApplicationsIcon: 'Anträge',
ApplyIcon: 'Beantragen',
ChartIcon: 'Diagramm',
EditIcon: 'Bearbeiten',
FinishedIcon: 'Abgeschlossen',
FirstPlaceIcon: 'Erster Platz',
+ ForbiddenIcon: 'Verboten',
ForfeitIcon: 'Aufgegeben',
LanguageIcon: 'Sprache',
LockedIcon: 'Gesperrt',
StreamIcon: 'Stream',
ThirdPlaceIcon: 'Dritter Platz',
TwitchIcon: 'Twitch',
+ UnknownIcon: 'Unbekannt',
UnlockedIcon: 'Offen',
YoutubeIcon: 'YouTube',
VideoIcon: 'Video',
},
techniques: {
heading: 'Techniken',
+ rulesetCodes: {
+ competitive: 'COM',
+ mg: 'MG',
+ nl: 'NL',
+ owg: 'OWG',
+ },
+ rulesetDescriptions: {
+ competitive: 'Competitive',
+ mg: 'Major Glitches',
+ nl: 'No Logic',
+ owg: 'Overworld Glitches',
+ },
seeAlso: 'Siehe auch',
},
tournaments: {
},
icon: {
AddIcon: 'Add',
+ AllowedIcon: 'Allowed',
ApplicationsIcon: 'Applications',
ApplyIcon: 'Apply',
ChartIcon: 'Chart',
EditIcon: 'Edit',
FinishedIcon: 'Finished',
FirstPlaceIcon: 'First Place',
+ ForbiddenIcon: 'Forbidden',
ForfeitIcon: 'Forfeit',
LanguageIcon: 'Language',
LockedIcon: 'Locked',
StreamIcon: 'Stream',
ThirdPlaceIcon: 'Third Place',
TwitchIcon: 'Twitch',
+ UnknownIcon: 'Unknown',
UnlockedIcon: 'Unlocked',
YoutubeIcon: 'YouTube',
VideoIcon: 'Video',
},
techniques: {
heading: 'Techniques',
+ rulesetCodes: {
+ competitive: 'COM',
+ mg: 'MG',
+ nl: 'NL',
+ owg: 'OWG',
+ },
+ rulesetDescriptions: {
+ competitive: 'Competitive',
+ mg: 'Major Glitches',
+ nl: 'No Logic',
+ owg: 'Overworld Glitches',
+ },
seeAlso: 'See also',
},
tournaments: {
+.ruleset-box {
+ display: inline-grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 0 1ex;
+ padding: 0.5ex;
+ border-radius: 0.5ex;
+}
+
.tech-list {
margin: 1em 0;
padding: 0;