create symlink for node_modules in generateJson and buildRadar scripts
This commit is contained in:
@@ -1,23 +1,28 @@
|
||||
import React, { MouseEventHandler } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './badge.scss';
|
||||
import {Ring} from "../../config";
|
||||
import React, { MouseEventHandler } from "react";
|
||||
import classNames from "classnames";
|
||||
import "./badge.scss";
|
||||
import { Ring } from "../../config";
|
||||
type BadgeProps = {
|
||||
onClick?: MouseEventHandler;
|
||||
big?: boolean;
|
||||
type: 'big' | 'all' | 'empty' | Ring;
|
||||
type: "big" | "all" | "empty" | Ring;
|
||||
};
|
||||
|
||||
export default function Badge({ onClick, big, type, children }: React.PropsWithChildren<BadgeProps>) {
|
||||
const Comp = onClick ? 'a' : 'span';
|
||||
export default function Badge({
|
||||
onClick,
|
||||
big,
|
||||
type,
|
||||
children,
|
||||
}: React.PropsWithChildren<BadgeProps>) {
|
||||
const Comp = onClick ? "a" : "span";
|
||||
|
||||
return (
|
||||
<Comp
|
||||
className={classNames('badge', `badge--${type}`, {
|
||||
'badge--big': big === true,
|
||||
className={classNames("badge", `badge--${type}`, {
|
||||
"badge--big": big === true,
|
||||
})}
|
||||
onClick={onClick}
|
||||
href={Comp === 'a' ? '#' : undefined}
|
||||
href={Comp === "a" ? "#" : undefined}
|
||||
>
|
||||
{children}
|
||||
</Comp>
|
||||
|
||||
@@ -40,5 +40,4 @@
|
||||
background: var(--color-marine);
|
||||
border-color: var(--color-marine);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './branding.scss';
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import "./branding.scss";
|
||||
type BrandingProps = {
|
||||
logoContent: React.ReactNode;
|
||||
modifier?: 'backlink' | 'logo' | 'content' | 'footer';
|
||||
modifier?: "backlink" | "logo" | "content" | "footer";
|
||||
};
|
||||
|
||||
export default function Branding({ logoContent, modifier, children }: React.PropsWithChildren<BrandingProps>) {
|
||||
export default function Branding({
|
||||
logoContent,
|
||||
modifier,
|
||||
children,
|
||||
}: React.PropsWithChildren<BrandingProps>) {
|
||||
return (
|
||||
<div className={classNames('branding', { [`branding--${modifier}`]: modifier })}>
|
||||
<div className='branding__logo'>{logoContent}</div>
|
||||
<div className='branding__content'>{children}</div>
|
||||
<div
|
||||
className={classNames("branding", {
|
||||
[`branding--${modifier}`]: modifier,
|
||||
})}
|
||||
>
|
||||
<div className="branding__logo">{logoContent}</div>
|
||||
<div className="branding__content">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../styles/sccs-vars.scss';
|
||||
@import "../../styles/sccs-vars.scss";
|
||||
|
||||
.branding {
|
||||
margin: 40px 0;
|
||||
@@ -43,4 +43,4 @@
|
||||
@media (max-width: $until-xl) {
|
||||
margin: 15px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './fadeable.scss';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import classNames from "classnames";
|
||||
import "./fadeable.scss";
|
||||
|
||||
type FadeableProps = {
|
||||
leaving: boolean;
|
||||
onLeave: () => void;
|
||||
};
|
||||
|
||||
export default function Fadeable({ leaving, onLeave, children }: React.PropsWithChildren<FadeableProps>) {
|
||||
export default function Fadeable({
|
||||
leaving,
|
||||
onLeave,
|
||||
children,
|
||||
}: React.PropsWithChildren<FadeableProps>) {
|
||||
const [faded, setFaded] = useState(leaving);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -25,7 +29,10 @@ export default function Fadeable({ leaving, onLeave, children }: React.PropsWith
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames('fadable', { 'is-faded': faded })} onTransitionEnd={handleTransitionEnd}>
|
||||
<div
|
||||
className={classNames("fadable", { "is-faded": faded })}
|
||||
onTransitionEnd={handleTransitionEnd}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
transition: opacity 0.2s cubic-bezier(0.54, 0, 0.28, 1);
|
||||
|
||||
&.is-faded {
|
||||
opacity: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,37 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Branding from '../Branding/Branding';
|
||||
import FooterEnd from '../FooterEnd/FooterEnd';
|
||||
import { assetUrl, getItemPageNames, isMobileViewport } from '../../config';
|
||||
import { Item } from '../../model';
|
||||
import './footer.scss';
|
||||
export default function Footer({ items, pageName }: { items: Item[]; pageName: string }) {
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import Branding from "../Branding/Branding";
|
||||
import FooterEnd from "../FooterEnd/FooterEnd";
|
||||
import { assetUrl, getItemPageNames, isMobileViewport } from "../../config";
|
||||
import { Item } from "../../model";
|
||||
import "./footer.scss";
|
||||
export default function Footer({
|
||||
items,
|
||||
pageName,
|
||||
}: {
|
||||
items: Item[];
|
||||
pageName: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={classNames('footer', { 'is-hidden': !isMobileViewport() && getItemPageNames(items).includes(pageName) })}>
|
||||
<Branding modifier='footer' logoContent={<img src={assetUrl('logo.svg')} width='150px' height='60px' alt='' />}>
|
||||
<span className='footnote'>
|
||||
AOE is a leading global provider of services for digital transformation and digital business models. AOE relies exclusively on established Enterprise
|
||||
Open Source technologies. This leads to innovative solutions, digital products and portals in agile software projects, and helps build long-lasting,
|
||||
strategic partnerships with our customers.
|
||||
<div
|
||||
className={classNames("footer", {
|
||||
"is-hidden":
|
||||
!isMobileViewport() && getItemPageNames(items).includes(pageName),
|
||||
})}
|
||||
>
|
||||
<Branding
|
||||
modifier="footer"
|
||||
logoContent={
|
||||
<img src={assetUrl("logo.svg")} width="150px" height="60px" alt="" />
|
||||
}
|
||||
>
|
||||
<span className="footnote">
|
||||
AOE is a leading global provider of services for digital
|
||||
transformation and digital business models. AOE relies exclusively on
|
||||
established Enterprise Open Source technologies. This leads to
|
||||
innovative solutions, digital products and portals in agile software
|
||||
projects, and helps build long-lasting, strategic partnerships with
|
||||
our customers.
|
||||
</span>
|
||||
</Branding>
|
||||
<FooterEnd />
|
||||
|
||||
@@ -1,37 +1,75 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './footerend.scss';
|
||||
export default function FooterEnd({ modifier }: { modifier?: 'in-sidebar' }) {
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import "./footerend.scss";
|
||||
export default function FooterEnd({ modifier }: { modifier?: "in-sidebar" }) {
|
||||
return (
|
||||
<div className={classNames('footer-end', { [`footer-end__${modifier}`]: modifier })}>
|
||||
<div className='footer-social'>
|
||||
<div className='footer-social__label'>
|
||||
<div
|
||||
className={classNames("footer-end", {
|
||||
[`footer-end__${modifier}`]: modifier,
|
||||
})}
|
||||
>
|
||||
<div className="footer-social">
|
||||
<div className="footer-social__label">
|
||||
<p>Follow us:</p>
|
||||
</div>
|
||||
<div className='footer-social__links'>
|
||||
<a className='social-links-icon' href='https://www.facebook.com/aoepeople' target='_blank' rel='noopener noreferrer'>
|
||||
<i className='socicon-facebook social-icon'></i>
|
||||
<div className="footer-social__links">
|
||||
<a
|
||||
className="social-links-icon"
|
||||
href="https://www.facebook.com/aoepeople"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="socicon-facebook social-icon"></i>
|
||||
</a>
|
||||
<a className='social-links-icon' href='https://twitter.com/aoepeople' target='_blank' rel='noopener noreferrer'>
|
||||
<i className='socicon-twitter social-icon'></i>
|
||||
<a
|
||||
className="social-links-icon"
|
||||
href="https://twitter.com/aoepeople"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="socicon-twitter social-icon"></i>
|
||||
</a>
|
||||
<a className='social-links-icon' href='https://www.linkedin.com/company/aoe' target='_blank' rel='noopener noreferrer'>
|
||||
<i className='socicon-linkedin social-icon'></i>
|
||||
<a
|
||||
className="social-links-icon"
|
||||
href="https://www.linkedin.com/company/aoe"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="socicon-linkedin social-icon"></i>
|
||||
</a>
|
||||
<a className='social-links-icon' href='https://www.xing.com/company/aoe' target='_blank' rel='noopener noreferrer'>
|
||||
<i className='socicon-xing social-icon'></i>
|
||||
<a
|
||||
className="social-links-icon"
|
||||
href="https://www.xing.com/company/aoe"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="socicon-xing social-icon"></i>
|
||||
</a>
|
||||
<a className='social-links-icon' href='https://www.youtube.com/user/aoepeople' target='_blank' rel='noopener noreferrer'>
|
||||
<i className='socicon-youtube social-icon'></i>
|
||||
<a
|
||||
className="social-links-icon"
|
||||
href="https://www.youtube.com/user/aoepeople"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="socicon-youtube social-icon"></i>
|
||||
</a>
|
||||
<a className='social-links-icon' href='https://github.com/aoepeople' target='_blank' rel='noopener noreferrer'>
|
||||
<i className='socicon-github social-icon'></i>
|
||||
<a
|
||||
className="social-links-icon"
|
||||
href="https://github.com/aoepeople"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="socicon-github social-icon"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='footer-copyright'>
|
||||
<div className="footer-copyright">
|
||||
<p>
|
||||
<a href='https://www.aoe.com/en/copyright-meta/legal-information.html' target='_blank' rel='noopener noreferrer'>
|
||||
<a
|
||||
href="https://www.aoe.com/en/copyright-meta/legal-information.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Legal Information
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../styles/sccs-vars.scss';
|
||||
@import "../../styles/sccs-vars.scss";
|
||||
|
||||
.footer-end {
|
||||
font-size: 12px;
|
||||
@@ -35,4 +35,4 @@
|
||||
&__label {
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './headline-group.scss';
|
||||
export default function ({ children, secondary = false }: React.PropsWithChildren<{ secondary?: boolean }>) {
|
||||
return <div className={classNames('headline-group', { 'headline-group--secondary': secondary })}>{children}</div>;
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import "./headline-group.scss";
|
||||
export default function ({
|
||||
children,
|
||||
secondary = false,
|
||||
}: React.PropsWithChildren<{ secondary?: boolean }>) {
|
||||
return (
|
||||
<div
|
||||
className={classNames("headline-group", {
|
||||
"headline-group--secondary": secondary,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../styles/sccs-vars.scss';
|
||||
@import "../../styles/sccs-vars.scss";
|
||||
|
||||
.headline-group {
|
||||
margin: 0 0 60px;
|
||||
@@ -14,4 +14,4 @@
|
||||
margin: 5px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import React from 'react';
|
||||
import './hero-headline.scss';
|
||||
export default function ({ children, alt }: React.PropsWithChildren<{ alt?: string }>) {
|
||||
import React from "react";
|
||||
import "./hero-headline.scss";
|
||||
export default function ({
|
||||
children,
|
||||
alt,
|
||||
}: React.PropsWithChildren<{ alt?: string }>) {
|
||||
return (
|
||||
<div className='hero-headline'>
|
||||
<div className="hero-headline">
|
||||
{children}
|
||||
<span className='hero-headline__alt'>{alt}</span>
|
||||
<span className="hero-headline__alt">{alt}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../styles/sccs-vars.scss';
|
||||
@import "../../styles/sccs-vars.scss";
|
||||
|
||||
.hero-headline {
|
||||
font-size: 38px;
|
||||
@@ -23,4 +23,4 @@
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Link from '../Link/Link';
|
||||
import Flag from '../Flag/Flag';
|
||||
import { Item as mItem } from '../../model';
|
||||
import './item.scss';
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import Link from "../Link/Link";
|
||||
import Flag from "../Flag/Flag";
|
||||
import { Item as mItem } from "../../model";
|
||||
import "./item.scss";
|
||||
type ItemProps = {
|
||||
item: mItem;
|
||||
noLeadingBorder?: boolean;
|
||||
@@ -11,21 +11,26 @@ type ItemProps = {
|
||||
style: React.CSSProperties;
|
||||
};
|
||||
|
||||
export default function Item({ item, noLeadingBorder = false, active = false, style = {} }: ItemProps) {
|
||||
export default function Item({
|
||||
item,
|
||||
noLeadingBorder = false,
|
||||
active = false,
|
||||
style = {},
|
||||
}: ItemProps) {
|
||||
return (
|
||||
<Link
|
||||
className={classNames('item', {
|
||||
'item--no-leading-border': noLeadingBorder,
|
||||
'is-active': active,
|
||||
className={classNames("item", {
|
||||
"item--no-leading-border": noLeadingBorder,
|
||||
"is-active": active,
|
||||
})}
|
||||
pageName={`${item.quadrant}/${item.name}`}
|
||||
style={style}
|
||||
>
|
||||
<div className='item__title'>
|
||||
<div className="item__title">
|
||||
{item.title}
|
||||
<Flag item={item} />
|
||||
</div>
|
||||
{item.info && <div className='item__info'>{item.info}</div>}
|
||||
{item.info && <div className="item__info">{item.info}</div>}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import Item from '../Item/Item';
|
||||
import { Item as mItem } from '../../model';
|
||||
import './item-list.scss';
|
||||
import React from "react";
|
||||
import Item from "../Item/Item";
|
||||
import { Item as mItem } from "../../model";
|
||||
import "./item-list.scss";
|
||||
type ItemListProps = {
|
||||
items: mItem[];
|
||||
activeItem?: mItem;
|
||||
@@ -10,19 +10,30 @@ type ItemListProps = {
|
||||
itemStyle?: React.CSSProperties[];
|
||||
};
|
||||
|
||||
export default function ItemList({ children, items, activeItem, noLeadingBorder, headerStyle = {}, itemStyle = [] }: React.PropsWithChildren<ItemListProps>) {
|
||||
export default function ItemList({
|
||||
children,
|
||||
items,
|
||||
activeItem,
|
||||
noLeadingBorder,
|
||||
headerStyle = {},
|
||||
itemStyle = [],
|
||||
}: React.PropsWithChildren<ItemListProps>) {
|
||||
return (
|
||||
<div className='item-list'>
|
||||
<div className='item-list__header' style={headerStyle}>
|
||||
<div className="item-list">
|
||||
<div className="item-list__header" style={headerStyle}>
|
||||
{children}
|
||||
</div>
|
||||
<div className='item-list__list'>
|
||||
<div className="item-list__list">
|
||||
{items.map((item, i) => (
|
||||
<Item
|
||||
key={item.name}
|
||||
item={item}
|
||||
noLeadingBorder={noLeadingBorder}
|
||||
active={activeItem !== null && activeItem !== undefined && activeItem.name === item.name}
|
||||
active={
|
||||
activeItem !== null &&
|
||||
activeItem !== undefined &&
|
||||
activeItem.name === item.name
|
||||
}
|
||||
style={itemStyle[i]}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import React from 'react';
|
||||
import Badge from '../Badge/Badge';
|
||||
import { formatRelease } from '../../date';
|
||||
import { Revision } from '../../model';
|
||||
import React from "react";
|
||||
import Badge from "../Badge/Badge";
|
||||
import { formatRelease } from "../../date";
|
||||
import { Revision } from "../../model";
|
||||
|
||||
export default function ItemRevision({ revision }: { revision: Revision }) {
|
||||
return (
|
||||
<div className='item-revision'>
|
||||
<div className="item-revision">
|
||||
<div>
|
||||
<Badge type={revision.ring}>
|
||||
{revision.ring} | {formatRelease(revision.release)}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className='markdown' dangerouslySetInnerHTML={{ __html: revision.body }} />
|
||||
<div
|
||||
className="markdown"
|
||||
dangerouslySetInnerHTML={{ __html: revision.body }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.item-revision {
|
||||
&+.item-revision {
|
||||
& + .item-revision {
|
||||
margin-top: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import React from 'react';
|
||||
import HeadlineGroup from '../HeadlineGroup/HeadlineGroup';
|
||||
import ItemRevision from '../ItemRevision/ItemRevision';
|
||||
import { Revision } from '../../model';
|
||||
import './item-revisions.scss';
|
||||
export default function ItemRevisions({ revisions }: { revisions: Revision[] }) {
|
||||
import React from "react";
|
||||
import HeadlineGroup from "../HeadlineGroup/HeadlineGroup";
|
||||
import ItemRevision from "../ItemRevision/ItemRevision";
|
||||
import { Revision } from "../../model";
|
||||
import "./item-revisions.scss";
|
||||
export default function ItemRevisions({
|
||||
revisions,
|
||||
}: {
|
||||
revisions: Revision[];
|
||||
}) {
|
||||
return (
|
||||
<div className='item-revisions'>
|
||||
<div className="item-revisions">
|
||||
<HeadlineGroup secondary>
|
||||
<h4 className='headline headline--dark'>Revisions:</h4>
|
||||
<h4 className="headline headline--dark">Revisions:</h4>
|
||||
</HeadlineGroup>
|
||||
|
||||
{revisions.map((revision) => (
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Link from '../Link/Link';
|
||||
import { assetUrl, radarNameShort } from '../../config';
|
||||
import './logo-link.scss';
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import Link from "../Link/Link";
|
||||
import { assetUrl, radarNameShort } from "../../config";
|
||||
import "./logo-link.scss";
|
||||
export default function LogoLink({ small = false }: { small?: boolean }) {
|
||||
return (
|
||||
<Link pageName='index' className={classNames('logo-link', { 'logo-link--small': small })}>
|
||||
<span className='logo-link__icon icon icon--back'/>
|
||||
<span className='logo-link__slide'>
|
||||
<img className='logo-link__img' src={assetUrl('logo.svg')} width='150px' height='60px' alt={radarNameShort} />
|
||||
<span className='logo-link__text'>{radarNameShort}</span>
|
||||
<Link
|
||||
pageName="index"
|
||||
className={classNames("logo-link", { "logo-link--small": small })}
|
||||
>
|
||||
<span className="logo-link__icon icon icon--back" />
|
||||
<span className="logo-link__slide">
|
||||
<img
|
||||
className="logo-link__img"
|
||||
src={assetUrl("logo.svg")}
|
||||
width="150px"
|
||||
height="60px"
|
||||
alt={radarNameShort}
|
||||
/>
|
||||
<span className="logo-link__text">{radarNameShort}</span>
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -1,91 +1,139 @@
|
||||
import React from 'react';
|
||||
import HeroHeadline from '../HeroHeadline/HeroHeadline';
|
||||
import Fadeable from '../Fadeable/Fadeable';
|
||||
import SetTitle from '../SetTitle';
|
||||
import { radarName } from '../../config';
|
||||
import React from "react";
|
||||
import HeroHeadline from "../HeroHeadline/HeroHeadline";
|
||||
import Fadeable from "../Fadeable/Fadeable";
|
||||
import SetTitle from "../SetTitle";
|
||||
import { radarName } from "../../config";
|
||||
|
||||
export default function PageHelp({ leaving, onLeave }: { leaving: boolean; onLeave: () => void }) {
|
||||
export default function PageHelp({
|
||||
leaving,
|
||||
onLeave,
|
||||
}: {
|
||||
leaving: boolean;
|
||||
onLeave: () => void;
|
||||
}) {
|
||||
return (
|
||||
<Fadeable leaving={leaving} onLeave={onLeave}>
|
||||
<SetTitle title={'How to use the ' + radarName} />
|
||||
<SetTitle title={"How to use the " + radarName} />
|
||||
<HeroHeadline>How to use the {radarName}</HeroHeadline>
|
||||
<div className='fullpage-content'>
|
||||
<div className="fullpage-content">
|
||||
<h3>Introduction</h3>
|
||||
<p>Technology is moving fast and new technologies and innovations appear continuously.</p>
|
||||
<p>
|
||||
It's essential for a development and technology company such as AOE to constantly improve and keep track with the latest useful innovations. It is
|
||||
important to openly look for innovations and new technologies and to question established technologies and methods every now and then.
|
||||
Technology is moving fast and new technologies and innovations appear
|
||||
continuously.
|
||||
</p>
|
||||
<p>
|
||||
But, it is also important to wisely choose which technologies to use in our daily work and in the different projects we are carrying out. As we all
|
||||
know: There is no silver bullet.
|
||||
It's essential for a development and technology company such as AOE to
|
||||
constantly improve and keep track with the latest useful innovations.
|
||||
It is important to openly look for innovations and new technologies
|
||||
and to question established technologies and methods every now and
|
||||
then.
|
||||
</p>
|
||||
<p>
|
||||
But, it is also important to wisely choose which technologies to use
|
||||
in our daily work and in the different projects we are carrying out.
|
||||
As we all know: There is no silver bullet.
|
||||
</p>
|
||||
<h3>What is the {radarName}</h3>
|
||||
<p>
|
||||
The Tech Radar is an overview of different technologies - from languages, frameworks, tools and patterns to platforms - that we consider "new or
|
||||
mentionable". The radar therefore doesn't provide an overview of all established technologies - but it focuses on items that have recently gained in
|
||||
importance or changed.
|
||||
The Tech Radar is an overview of different technologies - from
|
||||
languages, frameworks, tools and patterns to platforms - that we
|
||||
consider "new or mentionable". The radar therefore doesn't provide an
|
||||
overview of all established technologies - but it focuses on items
|
||||
that have recently gained in importance or changed.
|
||||
</p>
|
||||
<h3>How it is created</h3>
|
||||
<p>
|
||||
The items in the technology radar are raised by the different teams and therefore a lot of the items are related to the work and challenges the teams
|
||||
face in the different projects. In fact, we don't include anything on the radar, which we haven't already tried ourselves at least once.
|
||||
The items in the technology radar are raised by the different teams
|
||||
and therefore a lot of the items are related to the work and
|
||||
challenges the teams face in the different projects. In fact, we don't
|
||||
include anything on the radar, which we haven't already tried
|
||||
ourselves at least once.
|
||||
</p>
|
||||
<p>
|
||||
There have been a lot of valuable discussions in different expert groups about the classification and details of each of technologies and innovations.
|
||||
And the result of all this can be found in the latest technology radar.
|
||||
There have been a lot of valuable discussions in different expert
|
||||
groups about the classification and details of each of technologies
|
||||
and innovations. And the result of all this can be found in the latest
|
||||
technology radar.
|
||||
</p>
|
||||
<h3>How should it be used</h3>
|
||||
<p>The radar acts as an overview of technologies that we think everyone in the teams should currently know about.</p>
|
||||
<p>
|
||||
Its goal is to act as a guide and inspiration for the daily work in the teams. Its purpose is also to provide helpful information and a bird's-eye
|
||||
perspective - so that decisions can be taken with a much deeper understanding of the subject matter. This results in more-informed and better-aligned
|
||||
decisions.
|
||||
The radar acts as an overview of technologies that we think everyone
|
||||
in the teams should currently know about.
|
||||
</p>
|
||||
<p>
|
||||
Its goal is to act as a guide and inspiration for the daily work in
|
||||
the teams. Its purpose is also to provide helpful information and a
|
||||
bird's-eye perspective - so that decisions can be taken with a much
|
||||
deeper understanding of the subject matter. This results in
|
||||
more-informed and better-aligned decisions.
|
||||
</p>
|
||||
<p>
|
||||
We also hope that developers outside of AOE find the informations in
|
||||
our technologie overview inspirational.
|
||||
</p>
|
||||
<p>
|
||||
We group or categorize the items in 4 quadrants - (sometimes, when
|
||||
it's not 100% clear where a item belongs, we choose the best fit).
|
||||
</p>
|
||||
<p>We also hope that developers outside of AOE find the informations in our technologie overview inspirational.</p>
|
||||
<p>We group or categorize the items in 4 quadrants - (sometimes, when it's not 100% clear where a item belongs, we choose the best fit).</p>
|
||||
<p>The quadrants are:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Languages and Frameworks:</strong> We've placed development languages (such as Scala or Golang) here, as well as more low-level development
|
||||
frameworks (such as Play or Symfony), which are useful for implementing custom software of all kinds.{' '}
|
||||
<strong>Languages and Frameworks:</strong> We've placed development
|
||||
languages (such as Scala or Golang) here, as well as more low-level
|
||||
development frameworks (such as Play or Symfony), which are useful
|
||||
for implementing custom software of all kinds.{" "}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Tools:</strong> Here we put different software tools - from small helpers to bigger software projects
|
||||
<strong>Tools:</strong> Here we put different software tools - from
|
||||
small helpers to bigger software projects
|
||||
</li>
|
||||
<li>
|
||||
<strong>Methods and Patterns:</strong> Patterns are so important, and a lot of them are valid for a long time (compared to some tools or
|
||||
frameworks). So, this is the category where we put information on methods and patterns concerning development, continuous x, testing, organization,
|
||||
architecture, etc.
|
||||
<strong>Methods and Patterns:</strong> Patterns are so important,
|
||||
and a lot of them are valid for a long time (compared to some tools
|
||||
or frameworks). So, this is the category where we put information on
|
||||
methods and patterns concerning development, continuous x, testing,
|
||||
organization, architecture, etc.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Platforms and Services</strong> (including AOE internal Services): Here we include infrastructure platforms and services. We also use this
|
||||
category to communicate news about AOE services that we want all AOE teams to be aware of.
|
||||
<strong>Platforms and Services</strong> (including AOE internal
|
||||
Services): Here we include infrastructure platforms and services. We
|
||||
also use this category to communicate news about AOE services that
|
||||
we want all AOE teams to be aware of.
|
||||
</li>
|
||||
</ul>
|
||||
<p>Each of the items is classified in one of these rings:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Adopt:</strong> We can clearly recommend this technology. We have used it for longer period of time in many teams and it has proven to be
|
||||
stable and useful.
|
||||
<strong>Adopt:</strong> We can clearly recommend this technology. We
|
||||
have used it for longer period of time in many teams and it has
|
||||
proven to be stable and useful.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Trial:</strong> We have used it with success and recommend to have a closer look at the technology in this ring. The goal of items here is
|
||||
to look at them more closely, with the goal to bring them to the adopt level.
|
||||
<strong>Trial:</strong> We have used it with success and recommend
|
||||
to have a closer look at the technology in this ring. The goal of
|
||||
items here is to look at them more closely, with the goal to bring
|
||||
them to the adopt level.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Assess:</strong> We have tried it out and we find it promising. We recommend having a look at these items when you face a specific need for
|
||||
the technology in your project.
|
||||
<strong>Assess:</strong> We have tried it out and we find it
|
||||
promising. We recommend having a look at these items when you face a
|
||||
specific need for the technology in your project.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hold:</strong> This category is a bit special. Unlike the others, we recommend to stop doing or using something. That does not mean that
|
||||
they are bad and it often might be ok to use them in existing projects. But we move things here if we think we shouldn't do them anymore - because
|
||||
we see better options or alternatives now.
|
||||
<strong>Hold:</strong> This category is a bit special. Unlike the
|
||||
others, we recommend to stop doing or using something. That does not
|
||||
mean that they are bad and it often might be ok to use them in
|
||||
existing projects. But we move things here if we think we shouldn't
|
||||
do them anymore - because we see better options or alternatives now.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Contributions and source code of the radar are on github:{' '}
|
||||
<a href='https://github.com/AOEpeople/aoe_technology_radar' target='_blank' rel='noopener noreferrer'>
|
||||
Contributions and source code of the radar are on github:{" "}
|
||||
<a
|
||||
href="https://github.com/AOEpeople/aoe_technology_radar"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
AOE Tech Radar on Github
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import { formatRelease } from '../../date';
|
||||
import { featuredOnly, Item } from '../../model';
|
||||
import HeroHeadline from '../HeroHeadline/HeroHeadline';
|
||||
import QuadrantGrid from '../QuadrantGrid/QuadrantGrid';
|
||||
import Fadeable from '../Fadeable/Fadeable';
|
||||
import SetTitle from '../SetTitle';
|
||||
import { radarName, radarNameShort } from '../../config';
|
||||
import { MomentInput } from 'moment';
|
||||
import React from "react";
|
||||
import { formatRelease } from "../../date";
|
||||
import { featuredOnly, Item } from "../../model";
|
||||
import HeroHeadline from "../HeroHeadline/HeroHeadline";
|
||||
import QuadrantGrid from "../QuadrantGrid/QuadrantGrid";
|
||||
import Fadeable from "../Fadeable/Fadeable";
|
||||
import SetTitle from "../SetTitle";
|
||||
import { radarName, radarNameShort } from "../../config";
|
||||
import { MomentInput } from "moment";
|
||||
|
||||
type PageIndexProps = {
|
||||
leaving: boolean;
|
||||
@@ -15,17 +15,26 @@ type PageIndexProps = {
|
||||
releases: MomentInput[];
|
||||
};
|
||||
|
||||
export default function PageIndex({ leaving, onLeave, items, releases }: PageIndexProps) {
|
||||
export default function PageIndex({
|
||||
leaving,
|
||||
onLeave,
|
||||
items,
|
||||
releases,
|
||||
}: PageIndexProps) {
|
||||
const newestRelease = releases.slice(-1)[0];
|
||||
const numberOfReleases = releases.length;
|
||||
return (
|
||||
<Fadeable leaving={leaving} onLeave={onLeave}>
|
||||
<SetTitle title={radarNameShort} />
|
||||
<div className='headline-group'>
|
||||
<HeroHeadline alt={`Version #${numberOfReleases}`}>{radarName}</HeroHeadline>
|
||||
<div className="headline-group">
|
||||
<HeroHeadline alt={`Version #${numberOfReleases}`}>
|
||||
{radarName}
|
||||
</HeroHeadline>
|
||||
</div>
|
||||
<QuadrantGrid items={featuredOnly(items)} />
|
||||
<div className='publish-date'>Published {formatRelease(newestRelease)}</div>
|
||||
<div className="publish-date">
|
||||
Published {formatRelease(newestRelease)}
|
||||
</div>
|
||||
</Fadeable>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,239 +1,271 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import Badge from '../Badge/Badge';
|
||||
import ItemList from '../ItemList/ItemList';
|
||||
import Link from '../Link/Link';
|
||||
import FooterEnd from '../FooterEnd/FooterEnd';
|
||||
import SetTitle from '../SetTitle';
|
||||
import ItemRevisions from '../ItemRevisions/ItemRevisions';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Badge from "../Badge/Badge";
|
||||
import ItemList from "../ItemList/ItemList";
|
||||
import Link from "../Link/Link";
|
||||
import FooterEnd from "../FooterEnd/FooterEnd";
|
||||
import SetTitle from "../SetTitle";
|
||||
import ItemRevisions from "../ItemRevisions/ItemRevisions";
|
||||
import {
|
||||
AnimationStates,
|
||||
createAnimation,
|
||||
createAnimationRunner
|
||||
} from '../../animation';
|
||||
import './item-page.scss';
|
||||
import {translate} from '../../config';
|
||||
import {groupByQuadrants, Item} from '../../model';
|
||||
AnimationStates,
|
||||
createAnimation,
|
||||
createAnimationRunner,
|
||||
} from "../../animation";
|
||||
import "./item-page.scss";
|
||||
import { translate } from "../../config";
|
||||
import { groupByQuadrants, Item } from "../../model";
|
||||
|
||||
const getItem = (pageName: string, items: Item[]) => {
|
||||
const [quadrantName, itemName] = pageName.split('/');
|
||||
return items.filter((item) => item.quadrant === quadrantName && item.name === itemName)[0];
|
||||
const [quadrantName, itemName] = pageName.split("/");
|
||||
return items.filter(
|
||||
(item) => item.quadrant === quadrantName && item.name === itemName
|
||||
)[0];
|
||||
};
|
||||
|
||||
const getItemsInRing = (pageName: string, items: Item[]) => {
|
||||
const item = getItem(pageName, items);
|
||||
return groupByQuadrants(items)[item.quadrant][item.ring];
|
||||
const item = getItem(pageName, items);
|
||||
return groupByQuadrants(items)[item.quadrant][item.ring];
|
||||
};
|
||||
|
||||
type PageItemProps = {
|
||||
pageName: string;
|
||||
items: Item[];
|
||||
leaving: boolean;
|
||||
onLeave: () => void;
|
||||
pageName: string;
|
||||
items: Item[];
|
||||
leaving: boolean;
|
||||
onLeave: () => void;
|
||||
};
|
||||
|
||||
export default function PageItem({pageName, items, leaving, onLeave}: PageItemProps) {
|
||||
const itemsInRing = getItemsInRing(pageName, items);
|
||||
export default function PageItem({
|
||||
pageName,
|
||||
items,
|
||||
leaving,
|
||||
onLeave,
|
||||
}: PageItemProps) {
|
||||
const itemsInRing = getItemsInRing(pageName, items);
|
||||
|
||||
const animationsIn = {
|
||||
background: createAnimation(
|
||||
{
|
||||
transform: 'translateX(calc((100vw - 1200px) / 2 + 800px))',
|
||||
transition: 'transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)',
|
||||
},
|
||||
{
|
||||
transition: 'transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)',
|
||||
transform: 'translateX(0)',
|
||||
},
|
||||
0
|
||||
),
|
||||
navHeader: createAnimation(
|
||||
{
|
||||
transform: 'translateX(-40px)',
|
||||
opacity: '0',
|
||||
},
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateX(0px)',
|
||||
opacity: '1',
|
||||
},
|
||||
300
|
||||
),
|
||||
text: createAnimation(
|
||||
{
|
||||
transform: 'translateY(-20px)',
|
||||
opacity: '0',
|
||||
},
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateY(0px)',
|
||||
opacity: '1',
|
||||
},
|
||||
600
|
||||
),
|
||||
items: itemsInRing.map((item, i) =>
|
||||
createAnimation(
|
||||
{
|
||||
transform: 'translateX(-40px)',
|
||||
opacity: '0',
|
||||
},
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateX(0px)',
|
||||
opacity: '1',
|
||||
},
|
||||
400 + 100 * i
|
||||
)
|
||||
),
|
||||
footer: createAnimation(
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateX(-40px)',
|
||||
opacity: '0',
|
||||
},
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateX(0px)',
|
||||
opacity: '1',
|
||||
},
|
||||
600 + itemsInRing.length * 100
|
||||
),
|
||||
};
|
||||
const animationsIn = {
|
||||
background: createAnimation(
|
||||
{
|
||||
transform: "translateX(calc((100vw - 1200px) / 2 + 800px))",
|
||||
transition: "transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)",
|
||||
},
|
||||
{
|
||||
transition: "transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)",
|
||||
transform: "translateX(0)",
|
||||
},
|
||||
0
|
||||
),
|
||||
navHeader: createAnimation(
|
||||
{
|
||||
transform: "translateX(-40px)",
|
||||
opacity: "0",
|
||||
},
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateX(0px)",
|
||||
opacity: "1",
|
||||
},
|
||||
300
|
||||
),
|
||||
text: createAnimation(
|
||||
{
|
||||
transform: "translateY(-20px)",
|
||||
opacity: "0",
|
||||
},
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateY(0px)",
|
||||
opacity: "1",
|
||||
},
|
||||
600
|
||||
),
|
||||
items: itemsInRing.map((item, i) =>
|
||||
createAnimation(
|
||||
{
|
||||
transform: "translateX(-40px)",
|
||||
opacity: "0",
|
||||
},
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateX(0px)",
|
||||
opacity: "1",
|
||||
},
|
||||
400 + 100 * i
|
||||
)
|
||||
),
|
||||
footer: createAnimation(
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateX(-40px)",
|
||||
opacity: "0",
|
||||
},
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateX(0px)",
|
||||
opacity: "1",
|
||||
},
|
||||
600 + itemsInRing.length * 100
|
||||
),
|
||||
};
|
||||
|
||||
const animationsOut = {
|
||||
background: createAnimation(animationsIn.background.stateB, animationsIn.background.stateA, 300 + itemsInRing.length * 50),
|
||||
navHeader: createAnimation(
|
||||
animationsIn.navHeader.stateB,
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateX(40px)',
|
||||
opacity: '0',
|
||||
},
|
||||
0
|
||||
),
|
||||
text: createAnimation(
|
||||
animationsIn.text.stateB,
|
||||
{
|
||||
transform: 'translateY(20px)',
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
opacity: '0',
|
||||
},
|
||||
0
|
||||
),
|
||||
items: itemsInRing.map((item, i) =>
|
||||
createAnimation(
|
||||
animationsIn.items[i].stateB,
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateX(40px)',
|
||||
opacity: '0',
|
||||
},
|
||||
100 + 50 * i
|
||||
)
|
||||
),
|
||||
footer: createAnimation(
|
||||
animationsIn.text.stateB,
|
||||
{
|
||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||
transform: 'translateX(40px)',
|
||||
opacity: '0',
|
||||
},
|
||||
200 + itemsInRing.length * 50
|
||||
),
|
||||
};
|
||||
const animationsOut = {
|
||||
background: createAnimation(
|
||||
animationsIn.background.stateB,
|
||||
animationsIn.background.stateA,
|
||||
300 + itemsInRing.length * 50
|
||||
),
|
||||
navHeader: createAnimation(
|
||||
animationsIn.navHeader.stateB,
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateX(40px)",
|
||||
opacity: "0",
|
||||
},
|
||||
0
|
||||
),
|
||||
text: createAnimation(
|
||||
animationsIn.text.stateB,
|
||||
{
|
||||
transform: "translateY(20px)",
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
opacity: "0",
|
||||
},
|
||||
0
|
||||
),
|
||||
items: itemsInRing.map((item, i) =>
|
||||
createAnimation(
|
||||
animationsIn.items[i].stateB,
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateX(40px)",
|
||||
opacity: "0",
|
||||
},
|
||||
100 + 50 * i
|
||||
)
|
||||
),
|
||||
footer: createAnimation(
|
||||
animationsIn.text.stateB,
|
||||
{
|
||||
transition: "opacity 150ms ease-out, transform 300ms ease-out",
|
||||
transform: "translateX(40px)",
|
||||
opacity: "0",
|
||||
},
|
||||
200 + itemsInRing.length * 50
|
||||
),
|
||||
};
|
||||
|
||||
const [animations, setAnimations] = useState<AnimationStates>(() => {
|
||||
return leaving ? createAnimationRunner(animationsIn).getState() : {}
|
||||
});
|
||||
const [animations, setAnimations] = useState<AnimationStates>(() => {
|
||||
return leaving ? createAnimationRunner(animationsIn).getState() : {};
|
||||
});
|
||||
|
||||
const [stateLeaving, setStateLeaving] = useState(leaving);
|
||||
const [stateLeaving, setStateLeaving] = useState(leaving);
|
||||
|
||||
useEffect(() => {
|
||||
if (!stateLeaving && leaving) {
|
||||
let animationRunner = createAnimationRunner(
|
||||
animationsOut,
|
||||
() => setAnimations(animationRunner.getState),
|
||||
)
|
||||
animationRunner.run();
|
||||
animationRunner.awaitAnimationComplete(onLeave);
|
||||
setStateLeaving(true)
|
||||
}
|
||||
if (stateLeaving && !leaving) {
|
||||
let animationRunner = createAnimationRunner(
|
||||
animationsIn,
|
||||
() => setAnimations(animationRunner.getState),
|
||||
)
|
||||
animationRunner.run();
|
||||
setStateLeaving(false)
|
||||
}
|
||||
}, [stateLeaving, leaving, animationsIn, animationsOut, onLeave])
|
||||
|
||||
const getAnimationStates = (name: string) => {
|
||||
if (!animations) {
|
||||
return undefined;
|
||||
}
|
||||
return animations[name];
|
||||
useEffect(() => {
|
||||
if (!stateLeaving && leaving) {
|
||||
let animationRunner = createAnimationRunner(animationsOut, () =>
|
||||
setAnimations(animationRunner.getState)
|
||||
);
|
||||
animationRunner.run();
|
||||
animationRunner.awaitAnimationComplete(onLeave);
|
||||
setStateLeaving(true);
|
||||
}
|
||||
if (stateLeaving && !leaving) {
|
||||
let animationRunner = createAnimationRunner(animationsIn, () =>
|
||||
setAnimations(animationRunner.getState)
|
||||
);
|
||||
animationRunner.run();
|
||||
setStateLeaving(false);
|
||||
}
|
||||
}, [stateLeaving, leaving, animationsIn, animationsOut, onLeave]);
|
||||
|
||||
const getAnimationState = (name: string) => {
|
||||
const animations = getAnimationStates(name)
|
||||
if (animations === undefined || animations.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
return animations[0]
|
||||
};
|
||||
const getAnimationStates = (name: string) => {
|
||||
if (!animations) {
|
||||
return undefined;
|
||||
}
|
||||
return animations[name];
|
||||
};
|
||||
|
||||
const item = getItem(pageName, items);
|
||||
const getAnimationState = (name: string) => {
|
||||
const animations = getAnimationStates(name);
|
||||
if (animations === undefined || animations.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return animations[0];
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SetTitle title={item.title}/>
|
||||
<div className='item-page'>
|
||||
<div className='item-page__nav'>
|
||||
<div className='item-page__nav__inner'>
|
||||
<div className='item-page__header' style={getAnimationState('navHeader')}>
|
||||
<h3 className='headline'>{translate(item.quadrant)}</h3>
|
||||
</div>
|
||||
const item = getItem(pageName, items);
|
||||
|
||||
<ItemList items={itemsInRing} activeItem={item} headerStyle={getAnimationState('navHeader')}
|
||||
itemStyle={getAnimationStates('items')}>
|
||||
<div className='split'>
|
||||
<div className='split__left'>
|
||||
<Badge big type={item.ring}>
|
||||
{item.ring}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className='split__right'>
|
||||
<Link className='icon-link' pageName={item.quadrant}>
|
||||
<span className='icon icon--pie icon-link__icon'/>
|
||||
Quadrant Overview
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</ItemList>
|
||||
<div className='item-page__footer' style={getAnimationState('footer')}>
|
||||
<FooterEnd modifier='in-sidebar'/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='item-page__content' style={getAnimationState('background')}>
|
||||
<div className='item-page__content__inner' style={getAnimationState('text')}>
|
||||
<div className='item-page__header'>
|
||||
<div className='split'>
|
||||
<div className='split__left'>
|
||||
<h1 className='hero-headline hero-headline--inverse'>{item.title}</h1>
|
||||
</div>
|
||||
<div className='split__right'>
|
||||
<Badge big type={item.ring}>
|
||||
{item.ring}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='markdown' dangerouslySetInnerHTML={{__html: item.body}}/>
|
||||
{item.revisions.length > 1 && <ItemRevisions revisions={item.revisions.slice(1)}/>}
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<div>
|
||||
<SetTitle title={item.title} />
|
||||
<div className="item-page">
|
||||
<div className="item-page__nav">
|
||||
<div className="item-page__nav__inner">
|
||||
<div
|
||||
className="item-page__header"
|
||||
style={getAnimationState("navHeader")}
|
||||
>
|
||||
<h3 className="headline">{translate(item.quadrant)}</h3>
|
||||
</div>
|
||||
|
||||
<ItemList
|
||||
items={itemsInRing}
|
||||
activeItem={item}
|
||||
headerStyle={getAnimationState("navHeader")}
|
||||
itemStyle={getAnimationStates("items")}
|
||||
>
|
||||
<div className="split">
|
||||
<div className="split__left">
|
||||
<Badge big type={item.ring}>
|
||||
{item.ring}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="split__right">
|
||||
<Link className="icon-link" pageName={item.quadrant}>
|
||||
<span className="icon icon--pie icon-link__icon" />
|
||||
Quadrant Overview
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</ItemList>
|
||||
<div
|
||||
className="item-page__footer"
|
||||
style={getAnimationState("footer")}
|
||||
>
|
||||
<FooterEnd modifier="in-sidebar" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
<div
|
||||
className="item-page__content"
|
||||
style={getAnimationState("background")}
|
||||
>
|
||||
<div
|
||||
className="item-page__content__inner"
|
||||
style={getAnimationState("text")}
|
||||
>
|
||||
<div className="item-page__header">
|
||||
<div className="split">
|
||||
<div className="split__left">
|
||||
<h1 className="hero-headline hero-headline--inverse">
|
||||
{item.title}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="split__right">
|
||||
<Badge big type={item.ring}>
|
||||
{item.ring}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="markdown"
|
||||
dangerouslySetInnerHTML={{ __html: item.body }}
|
||||
/>
|
||||
{item.revisions.length > 1 && (
|
||||
<ItemRevisions revisions={item.revisions.slice(1)} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,6 @@
|
||||
min-height: 300px;
|
||||
|
||||
&__aside {
|
||||
padding: 20px 0
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import Badge from '../Badge/Badge';
|
||||
import ItemList from '../ItemList/ItemList';
|
||||
import Link from '../Link/Link';
|
||||
import Fadeable from '../Fadeable/Fadeable';
|
||||
import SetTitle from '../SetTitle';
|
||||
import ItemRevisions from '../ItemRevisions/ItemRevisions';
|
||||
import React from "react";
|
||||
import Badge from "../Badge/Badge";
|
||||
import ItemList from "../ItemList/ItemList";
|
||||
import Link from "../Link/Link";
|
||||
import Fadeable from "../Fadeable/Fadeable";
|
||||
import SetTitle from "../SetTitle";
|
||||
import ItemRevisions from "../ItemRevisions/ItemRevisions";
|
||||
|
||||
import { translate } from '../../config';
|
||||
import { groupByQuadrants, Item } from '../../model';
|
||||
import { translate } from "../../config";
|
||||
import { groupByQuadrants, Item } from "../../model";
|
||||
|
||||
type PageItemMobileProps = {
|
||||
pageName: string;
|
||||
@@ -16,10 +16,17 @@ type PageItemMobileProps = {
|
||||
onLeave: () => void;
|
||||
};
|
||||
|
||||
export default function PageItemMobile({ pageName, items, leaving, onLeave }: PageItemMobileProps) {
|
||||
export default function PageItemMobile({
|
||||
pageName,
|
||||
items,
|
||||
leaving,
|
||||
onLeave,
|
||||
}: PageItemMobileProps) {
|
||||
const getItem = (pageName: string, items: Item[]) => {
|
||||
const [quadrantName, itemName] = pageName.split('/');
|
||||
const item = items.filter((item) => item.quadrant === quadrantName && item.name === itemName)[0];
|
||||
const [quadrantName, itemName] = pageName.split("/");
|
||||
const item = items.filter(
|
||||
(item) => item.quadrant === quadrantName && item.name === itemName
|
||||
)[0];
|
||||
return item;
|
||||
};
|
||||
|
||||
@@ -34,36 +41,43 @@ export default function PageItemMobile({ pageName, items, leaving, onLeave }: Pa
|
||||
return (
|
||||
<Fadeable leaving={leaving} onLeave={onLeave}>
|
||||
<SetTitle title={item.title} />
|
||||
<div className='mobile-item-page'>
|
||||
<div className='mobile-item-page__content'>
|
||||
<div className='mobile-item-page__content__inner'>
|
||||
<div className='mobile-item-page__header'>
|
||||
<div className='split'>
|
||||
<div className='split__left'>
|
||||
<h3 className='headline'>{translate(item.quadrant)}</h3>
|
||||
<h1 className='hero-headline hero-headline--inverse'>{item.title}</h1>
|
||||
<div className="mobile-item-page">
|
||||
<div className="mobile-item-page__content">
|
||||
<div className="mobile-item-page__content__inner">
|
||||
<div className="mobile-item-page__header">
|
||||
<div className="split">
|
||||
<div className="split__left">
|
||||
<h3 className="headline">{translate(item.quadrant)}</h3>
|
||||
<h1 className="hero-headline hero-headline--inverse">
|
||||
{item.title}
|
||||
</h1>
|
||||
</div>
|
||||
<div className='split__right'>
|
||||
<div className="split__right">
|
||||
<Badge big type={item.ring}>
|
||||
{item.ring}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='markdown' dangerouslySetInnerHTML={{ __html: item.body }} />
|
||||
{item.revisions.length > 1 && <ItemRevisions revisions={item.revisions.slice(1)} />}
|
||||
<div
|
||||
className="markdown"
|
||||
dangerouslySetInnerHTML={{ __html: item.body }}
|
||||
/>
|
||||
{item.revisions.length > 1 && (
|
||||
<ItemRevisions revisions={item.revisions.slice(1)} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<aside className='mobile-item-page__aside'>
|
||||
<aside className="mobile-item-page__aside">
|
||||
<ItemList items={itemsInRing} activeItem={item}>
|
||||
<div className='split'>
|
||||
<div className='split__left'>
|
||||
<h3 className='headline'>{translate(item.quadrant)}</h3>
|
||||
<div className="split">
|
||||
<div className="split__left">
|
||||
<h3 className="headline">{translate(item.quadrant)}</h3>
|
||||
</div>
|
||||
<div className='split__right'>
|
||||
<Link className='icon-link' pageName={item.quadrant}>
|
||||
<span className='icon icon--pie icon-link__icon'></span>Zoom In
|
||||
<div className="split__right">
|
||||
<Link className="icon-link" pageName={item.quadrant}>
|
||||
<span className="icon icon--pie icon-link__icon"></span>Zoom In
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import HeadlineGroup from '../HeadlineGroup/HeadlineGroup';
|
||||
import HeroHeadline from '../HeroHeadline/HeroHeadline';
|
||||
import Badge from '../Badge/Badge';
|
||||
import Link from '../Link/Link';
|
||||
import Search from '../Search/Search';
|
||||
import Fadeable from '../Fadeable/Fadeable';
|
||||
import SetTitle from '../SetTitle';
|
||||
import Flag from '../Flag/Flag';
|
||||
import { groupByFirstLetter, Item } from '../../model';
|
||||
import { translate, Ring } from '../../config';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import HeadlineGroup from "../HeadlineGroup/HeadlineGroup";
|
||||
import HeroHeadline from "../HeroHeadline/HeroHeadline";
|
||||
import Badge from "../Badge/Badge";
|
||||
import Link from "../Link/Link";
|
||||
import Search from "../Search/Search";
|
||||
import Fadeable from "../Fadeable/Fadeable";
|
||||
import SetTitle from "../SetTitle";
|
||||
import Flag from "../Flag/Flag";
|
||||
import { groupByFirstLetter, Item } from "../../model";
|
||||
import { translate, Ring } from "../../config";
|
||||
|
||||
const containsSearchTerm = (text = '', term = '') => {
|
||||
const containsSearchTerm = (text = "", term = "") => {
|
||||
// TODO search refinement
|
||||
return text.trim().toLocaleLowerCase().indexOf(term.trim().toLocaleLowerCase()) !== -1;
|
||||
return (
|
||||
text.trim().toLocaleLowerCase().indexOf(term.trim().toLocaleLowerCase()) !==
|
||||
-1
|
||||
);
|
||||
};
|
||||
|
||||
type PageOverviewProps = {
|
||||
rings: readonly ('all' | Ring)[];
|
||||
rings: readonly ("all" | Ring)[];
|
||||
search: string;
|
||||
items: Item[];
|
||||
leaving: boolean;
|
||||
onLeave: () => void;
|
||||
};
|
||||
|
||||
export default function PageOverview({ rings, search: searchProp, items, leaving, onLeave }: PageOverviewProps) {
|
||||
const [ring, setRing] = useState<Ring | 'all'>('all');
|
||||
export default function PageOverview({
|
||||
rings,
|
||||
search: searchProp,
|
||||
items,
|
||||
leaving,
|
||||
onLeave,
|
||||
}: PageOverviewProps) {
|
||||
const [ring, setRing] = useState<Ring | "all">("all");
|
||||
const [search, setSearch] = useState(searchProp);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -40,13 +49,19 @@ export default function PageOverview({ rings, search: searchProp, items, leaving
|
||||
|
||||
const isRingActive = (ringName: string) => ring === ringName;
|
||||
|
||||
const itemMatchesRing = (item: Item) => ring === 'all' || item.ring === ring;
|
||||
const itemMatchesRing = (item: Item) => ring === "all" || item.ring === ring;
|
||||
|
||||
const itemMatchesSearch = (item: Item) => {
|
||||
return search.trim() === '' || containsSearchTerm(item.title, search) || containsSearchTerm(item.body, search) || containsSearchTerm(item.info, search);
|
||||
return (
|
||||
search.trim() === "" ||
|
||||
containsSearchTerm(item.title, search) ||
|
||||
containsSearchTerm(item.body, search) ||
|
||||
containsSearchTerm(item.info, search)
|
||||
);
|
||||
};
|
||||
|
||||
const isItemVisible = (item: Item) => itemMatchesRing(item) && itemMatchesSearch(item);
|
||||
const isItemVisible = (item: Item) =>
|
||||
itemMatchesRing(item) && itemMatchesSearch(item);
|
||||
|
||||
const getFilteredAndGroupedItems = () => {
|
||||
const groups = groupByFirstLetter(items);
|
||||
@@ -54,7 +69,9 @@ export default function PageOverview({ rings, search: searchProp, items, leaving
|
||||
...group,
|
||||
items: group.items.filter(isItemVisible),
|
||||
}));
|
||||
const nonEmptyGroups = groupsFiltered.filter((group) => group.items.length > 0);
|
||||
const nonEmptyGroups = groupsFiltered.filter(
|
||||
(group) => group.items.length > 0
|
||||
);
|
||||
return nonEmptyGroups;
|
||||
};
|
||||
|
||||
@@ -64,20 +81,24 @@ export default function PageOverview({ rings, search: searchProp, items, leaving
|
||||
|
||||
return (
|
||||
<Fadeable leaving={leaving} onLeave={onLeave}>
|
||||
<SetTitle title='Technologies Overview' />
|
||||
<SetTitle title="Technologies Overview" />
|
||||
<HeadlineGroup>
|
||||
<HeroHeadline>Technologies Overview</HeroHeadline>
|
||||
</HeadlineGroup>
|
||||
<div className='filter'>
|
||||
<div className='split split--filter'>
|
||||
<div className='split__left'>
|
||||
<div className="filter">
|
||||
<div className="split split--filter">
|
||||
<div className="split__left">
|
||||
<Search onChange={handleSearchTermChange} value={search} />
|
||||
</div>
|
||||
<div className='split__right'>
|
||||
<div className='nav'>
|
||||
<div className="split__right">
|
||||
<div className="nav">
|
||||
{rings.map((ringName) => (
|
||||
<div className='nav__item' key={ringName}>
|
||||
<Badge big onClick={handleRingClick(ringName)} type={isRingActive(ringName) ? ringName : 'empty'}>
|
||||
<div className="nav__item" key={ringName}>
|
||||
<Badge
|
||||
big
|
||||
onClick={handleRingClick(ringName)}
|
||||
type={isRingActive(ringName) ? ringName : "empty"}
|
||||
>
|
||||
{ringName}
|
||||
</Badge>
|
||||
</div>
|
||||
@@ -87,30 +108,32 @@ export default function PageOverview({ rings, search: searchProp, items, leaving
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='letter-index'>
|
||||
<div className="letter-index">
|
||||
{groups.map(({ letter, items }) => (
|
||||
<div key={letter} className='letter-index__group'>
|
||||
<div className='letter-index__letter'>{letter}</div>
|
||||
<div className='letter-index__items'>
|
||||
<div className='item-list'>
|
||||
<div className='item-list__list'>
|
||||
<div key={letter} className="letter-index__group">
|
||||
<div className="letter-index__letter">{letter}</div>
|
||||
<div className="letter-index__items">
|
||||
<div className="item-list">
|
||||
<div className="item-list__list">
|
||||
{items.map((item) => (
|
||||
<Link
|
||||
key={item.name}
|
||||
className='item item--big item--no-leading-border item--no-trailing-border'
|
||||
className="item item--big item--no-leading-border item--no-trailing-border"
|
||||
pageName={`${item.quadrant}/${item.name}`}
|
||||
>
|
||||
<div className='split split--overview'>
|
||||
<div className='split__left'>
|
||||
<div className='item__title'>
|
||||
<div className="split split--overview">
|
||||
<div className="split__left">
|
||||
<div className="item__title">
|
||||
{item.title}
|
||||
<Flag item={item} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='split__right'>
|
||||
<div className='nav nav--relations'>
|
||||
<div className='nav__item'>{translate(item.quadrant)}</div>
|
||||
<div className='nav__item'>
|
||||
<div className="split__right">
|
||||
<div className="nav nav--relations">
|
||||
<div className="nav__item">
|
||||
{translate(item.quadrant)}
|
||||
</div>
|
||||
<div className="nav__item">
|
||||
<Badge type={item.ring}>{item.ring}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import HeroHeadline from '../HeroHeadline/HeroHeadline';
|
||||
import HeadlineGroup from '../HeadlineGroup/HeadlineGroup';
|
||||
import QuadrantSection from '../QuadrantSection/QuadrantSection';
|
||||
import Fadeable from '../Fadeable/Fadeable';
|
||||
import SetTitle from '../SetTitle';
|
||||
import React from "react";
|
||||
import HeroHeadline from "../HeroHeadline/HeroHeadline";
|
||||
import HeadlineGroup from "../HeadlineGroup/HeadlineGroup";
|
||||
import QuadrantSection from "../QuadrantSection/QuadrantSection";
|
||||
import Fadeable from "../Fadeable/Fadeable";
|
||||
import SetTitle from "../SetTitle";
|
||||
|
||||
import { translate } from '../../config';
|
||||
import { featuredOnly, groupByQuadrants, Item } from '../../model';
|
||||
import { translate } from "../../config";
|
||||
import { featuredOnly, groupByQuadrants, Item } from "../../model";
|
||||
|
||||
type PageQuadrantProps = {
|
||||
leaving: boolean;
|
||||
@@ -15,7 +15,12 @@ type PageQuadrantProps = {
|
||||
items: Item[];
|
||||
};
|
||||
|
||||
export default function PageQuadrant({ leaving, onLeave, pageName, items }: PageQuadrantProps) {
|
||||
export default function PageQuadrant({
|
||||
leaving,
|
||||
onLeave,
|
||||
pageName,
|
||||
items,
|
||||
}: PageQuadrantProps) {
|
||||
const groups = groupByQuadrants(featuredOnly(items));
|
||||
return (
|
||||
<Fadeable leaving={leaving} onLeave={onLeave}>
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
import React from 'react';
|
||||
import HeroHeadline from '../HeroHeadline/HeroHeadline';
|
||||
import Fadeable from '../Fadeable/Fadeable';
|
||||
import SetTitle from '../SetTitle';
|
||||
import React from "react";
|
||||
import HeroHeadline from "../HeroHeadline/HeroHeadline";
|
||||
import Fadeable from "../Fadeable/Fadeable";
|
||||
import SetTitle from "../SetTitle";
|
||||
|
||||
export default function PageToolbox({ leaving, onLeave }: { leaving: boolean; onLeave: () => void }) {
|
||||
export default function PageToolbox({
|
||||
leaving,
|
||||
onLeave,
|
||||
}: {
|
||||
leaving: boolean;
|
||||
onLeave: () => void;
|
||||
}) {
|
||||
return (
|
||||
<Fadeable leaving={leaving} onLeave={onLeave}>
|
||||
<SetTitle title='Small AOE Toolbox' />
|
||||
<SetTitle title="Small AOE Toolbox" />
|
||||
<HeroHeadline>Small AOE Toolbox</HeroHeadline>
|
||||
<div className='fullpage-content'>
|
||||
<div className="fullpage-content">
|
||||
<h3>Useful Tools</h3>
|
||||
|
||||
<ul>
|
||||
<li>Fiddler - free web debugging proxy ( http://www.telerik.com/fiddler )</li>
|
||||
<li>
|
||||
Fiddler - free web debugging proxy ( http://www.telerik.com/fiddler
|
||||
)
|
||||
</li>
|
||||
<li>SoapUI - Webservice Test Tool (https://www.soapui.org/ )</li>
|
||||
<li>Postman - API Test Tool ( https://www.getpostman.com/ )</li>
|
||||
<li> Modelio - Simple free UML Modelling tool ( https://www.modelio.org/ )</li>
|
||||
<li>
|
||||
{" "}
|
||||
Modelio - Simple free UML Modelling tool ( https://www.modelio.org/
|
||||
)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Useful Tools (commercial)</h3>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { groupByQuadrants, Item, Group } from '../../model';
|
||||
import { quadrants } from '../../config';
|
||||
import QuadrantSection from '../QuadrantSection/QuadrantSection';
|
||||
import './quadrant-grid.scss';
|
||||
import React from "react";
|
||||
import { groupByQuadrants, Item, Group } from "../../model";
|
||||
import { quadrants } from "../../config";
|
||||
import QuadrantSection from "../QuadrantSection/QuadrantSection";
|
||||
import "./quadrant-grid.scss";
|
||||
const renderQuadrant = (quadrantName: string, groups: Group) => {
|
||||
return (
|
||||
<div key={quadrantName} className='quadrant-grid__quadrant'>
|
||||
<div key={quadrantName} className="quadrant-grid__quadrant">
|
||||
<QuadrantSection quadrantName={quadrantName} groups={groups} />
|
||||
</div>
|
||||
);
|
||||
@@ -13,5 +13,9 @@ const renderQuadrant = (quadrantName: string, groups: Group) => {
|
||||
|
||||
export default function QuadrantGrid({ items }: { items: Item[] }) {
|
||||
const groups = groupByQuadrants(items);
|
||||
return <div className='quadrant-grid'>{quadrants.map((quadrantName) => renderQuadrant(quadrantName, groups))}</div>;
|
||||
return (
|
||||
<div className="quadrant-grid">
|
||||
{quadrants.map((quadrantName) => renderQuadrant(quadrantName, groups))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../styles/sccs-vars.scss';
|
||||
@import "../../styles/sccs-vars.scss";
|
||||
|
||||
.quadrant-grid {
|
||||
display: flex;
|
||||
@@ -13,4 +13,4 @@
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import React from 'react';
|
||||
import { translate, rings, Ring, showEmptyRings } from '../../config';
|
||||
import Badge from '../Badge/Badge';
|
||||
import Link from '../Link/Link';
|
||||
import ItemList from '../ItemList/ItemList';
|
||||
import Flag from '../Flag/Flag';
|
||||
import { Group } from '../../model';
|
||||
import './quadrant-section.scss';
|
||||
const renderList = (ringName: Ring, quadrantName: string, groups: Group, big: boolean) => {
|
||||
import React from "react";
|
||||
import { translate, rings, Ring, showEmptyRings } from "../../config";
|
||||
import Badge from "../Badge/Badge";
|
||||
import Link from "../Link/Link";
|
||||
import ItemList from "../ItemList/ItemList";
|
||||
import Flag from "../Flag/Flag";
|
||||
import { Group } from "../../model";
|
||||
import "./quadrant-section.scss";
|
||||
const renderList = (
|
||||
ringName: Ring,
|
||||
quadrantName: string,
|
||||
groups: Group,
|
||||
big: boolean
|
||||
) => {
|
||||
const itemsInRing = groups[quadrantName][ringName] || [];
|
||||
|
||||
if (big) {
|
||||
@@ -20,13 +25,13 @@ const renderList = (ringName: Ring, quadrantName: string, groups: Group, big: bo
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='ring-list'>
|
||||
<div className='ring-list__header'>
|
||||
<div className="ring-list">
|
||||
<div className="ring-list__header">
|
||||
<Badge type={ringName}>{ringName}</Badge>
|
||||
</div>
|
||||
{itemsInRing.map((item) => (
|
||||
<span key={item.name} className='ring-list__item'>
|
||||
<Link className='link' pageName={`${item.quadrant}/${item.name}`}>
|
||||
<span key={item.name} className="ring-list__item">
|
||||
<Link className="link" pageName={`${item.quadrant}/${item.name}`}>
|
||||
{item.title}
|
||||
<Flag item={item} short />
|
||||
</Link>
|
||||
@@ -36,36 +41,58 @@ const renderList = (ringName: Ring, quadrantName: string, groups: Group, big: bo
|
||||
);
|
||||
};
|
||||
|
||||
const renderRing = (ringName: Ring, quadrantName: string, groups: Group, big: boolean) => {
|
||||
if (!showEmptyRings && (!groups[quadrantName] || !groups[quadrantName][ringName] || groups[quadrantName][ringName].length === 0)) {
|
||||
const renderRing = (
|
||||
ringName: Ring,
|
||||
quadrantName: string,
|
||||
groups: Group,
|
||||
big: boolean
|
||||
) => {
|
||||
if (
|
||||
!showEmptyRings &&
|
||||
(!groups[quadrantName] ||
|
||||
!groups[quadrantName][ringName] ||
|
||||
groups[quadrantName][ringName].length === 0)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div key={ringName} className='quadrant-section__ring'>
|
||||
<div key={ringName} className="quadrant-section__ring">
|
||||
{renderList(ringName, quadrantName, groups, big)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function QuadrantSection({ quadrantName, groups, big = false }: { quadrantName: string; groups: Group; big?: boolean }) {
|
||||
export default function QuadrantSection({
|
||||
quadrantName,
|
||||
groups,
|
||||
big = false,
|
||||
}: {
|
||||
quadrantName: string;
|
||||
groups: Group;
|
||||
big?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className='quadrant-section'>
|
||||
<div className='quadrant-section__header'>
|
||||
<div className='split'>
|
||||
<div className='split__left'>
|
||||
<h4 className='headline'>{translate(quadrantName)}</h4>
|
||||
<div className="quadrant-section">
|
||||
<div className="quadrant-section__header">
|
||||
<div className="split">
|
||||
<div className="split__left">
|
||||
<h4 className="headline">{translate(quadrantName)}</h4>
|
||||
</div>
|
||||
{!big && (
|
||||
<div className='split__right'>
|
||||
<Link className='icon-link' pageName={`${quadrantName}`}>
|
||||
<span className='icon icon--pie icon-link__icon' />
|
||||
<div className="split__right">
|
||||
<Link className="icon-link" pageName={`${quadrantName}`}>
|
||||
<span className="icon icon--pie icon-link__icon" />
|
||||
Zoom In
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='quadrant-section__rings'>{rings.map((ringName) => renderRing(ringName, quadrantName, groups, big))}</div>
|
||||
<div className="quadrant-section__rings">
|
||||
{rings.map((ringName) =>
|
||||
renderRing(ringName, quadrantName, groups, big)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import '../../styles/sccs-vars.scss';
|
||||
@import "../../styles/sccs-vars.scss";
|
||||
|
||||
.quadrant-section {
|
||||
&__header {
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
@media (max-width: $until-md) {
|
||||
flex-basis: 50%;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,137 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import PageIndex from './PageIndex/PageIndex';
|
||||
import PageOverview from './PageOverview/PageOverview';
|
||||
import PageHelp from './PageHelp/PageHelp';
|
||||
import PageQuadrant from './PageQuadrant/PageQuadrant';
|
||||
import PageItem from './PageItem/PageItem';
|
||||
import PageItemMobile from './PageItemMobile/PageItemMobile';
|
||||
import {quadrants, getItemPageNames, isMobileViewport, rings} from '../config';
|
||||
import {Item} from '../model';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import PageIndex from "./PageIndex/PageIndex";
|
||||
import PageOverview from "./PageOverview/PageOverview";
|
||||
import PageHelp from "./PageHelp/PageHelp";
|
||||
import PageQuadrant from "./PageQuadrant/PageQuadrant";
|
||||
import PageItem from "./PageItem/PageItem";
|
||||
import PageItemMobile from "./PageItemMobile/PageItemMobile";
|
||||
import {
|
||||
quadrants,
|
||||
getItemPageNames,
|
||||
isMobileViewport,
|
||||
rings,
|
||||
} from "../config";
|
||||
import { Item } from "../model";
|
||||
|
||||
type RouterProps = {
|
||||
pageName: string
|
||||
items: Item[]
|
||||
releases: string[]
|
||||
search: string
|
||||
}
|
||||
pageName: string;
|
||||
items: Item[];
|
||||
releases: string[];
|
||||
search: string;
|
||||
};
|
||||
|
||||
enum page {
|
||||
index,
|
||||
overview,
|
||||
help,
|
||||
quadrant,
|
||||
itemMobile,
|
||||
item,
|
||||
notFound,
|
||||
index,
|
||||
overview,
|
||||
help,
|
||||
quadrant,
|
||||
itemMobile,
|
||||
item,
|
||||
notFound,
|
||||
}
|
||||
|
||||
const getPageByName = (items: Item[], pageName: string): page => {
|
||||
if (pageName === 'index') {
|
||||
return page.index;
|
||||
}
|
||||
if (pageName === 'overview') {
|
||||
return page.overview;
|
||||
}
|
||||
if (pageName === 'help-and-about-tech-radar') {
|
||||
return page.help;
|
||||
}
|
||||
if (quadrants.includes(pageName)) {
|
||||
return page.quadrant;
|
||||
}
|
||||
if (getItemPageNames(items).includes(pageName)) {
|
||||
return isMobileViewport() ? page.itemMobile : page.item;
|
||||
}
|
||||
if (pageName === "index") {
|
||||
return page.index;
|
||||
}
|
||||
if (pageName === "overview") {
|
||||
return page.overview;
|
||||
}
|
||||
if (pageName === "help-and-about-tech-radar") {
|
||||
return page.help;
|
||||
}
|
||||
if (quadrants.includes(pageName)) {
|
||||
return page.quadrant;
|
||||
}
|
||||
if (getItemPageNames(items).includes(pageName)) {
|
||||
return isMobileViewport() ? page.itemMobile : page.item;
|
||||
}
|
||||
|
||||
return page.notFound;
|
||||
return page.notFound;
|
||||
};
|
||||
|
||||
export default function Router({pageName, items, releases, search}: RouterProps) {
|
||||
const [statePageName, setStatePageName] = useState(pageName);
|
||||
const [leaving, setLeaving] = useState(false);
|
||||
const [nextPageName, setNextPageName] = useState<string>('');
|
||||
export default function Router({
|
||||
pageName,
|
||||
items,
|
||||
releases,
|
||||
search,
|
||||
}: RouterProps) {
|
||||
const [statePageName, setStatePageName] = useState(pageName);
|
||||
const [leaving, setLeaving] = useState(false);
|
||||
const [nextPageName, setNextPageName] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
const nowLeaving = getPageByName(items, pageName) !== getPageByName(items, statePageName);
|
||||
if (nowLeaving) {
|
||||
setLeaving(true);
|
||||
setNextPageName(pageName);
|
||||
} else {
|
||||
setStatePageName(pageName);
|
||||
}
|
||||
}, [pageName, items, statePageName]);
|
||||
|
||||
const handlePageLeave = () => {
|
||||
setStatePageName(nextPageName);
|
||||
setNextPageName('');
|
||||
|
||||
window.setTimeout(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
setLeaving(false);
|
||||
});
|
||||
}, 0);
|
||||
};
|
||||
|
||||
switch (getPageByName(items, statePageName)) {
|
||||
case page.index:
|
||||
return <PageIndex leaving={leaving} items={items} onLeave={handlePageLeave} releases={releases}/>;
|
||||
case page.overview:
|
||||
return <PageOverview items={items} rings={rings} search={search} leaving={leaving}
|
||||
onLeave={handlePageLeave}/>;
|
||||
case page.help:
|
||||
return <PageHelp leaving={leaving} onLeave={handlePageLeave}/>;
|
||||
case page.quadrant:
|
||||
return <PageQuadrant leaving={leaving} onLeave={handlePageLeave} items={items} pageName={statePageName}/>;
|
||||
case page.itemMobile:
|
||||
return <PageItemMobile items={items} pageName={statePageName} leaving={leaving} onLeave={handlePageLeave}/>;
|
||||
case page.item:
|
||||
return <PageItem items={items} pageName={statePageName} leaving={leaving} onLeave={handlePageLeave}/>;
|
||||
default:
|
||||
return <div/>;
|
||||
useEffect(() => {
|
||||
const nowLeaving =
|
||||
getPageByName(items, pageName) !== getPageByName(items, statePageName);
|
||||
if (nowLeaving) {
|
||||
setLeaving(true);
|
||||
setNextPageName(pageName);
|
||||
} else {
|
||||
setStatePageName(pageName);
|
||||
}
|
||||
}, [pageName, items, statePageName]);
|
||||
|
||||
const handlePageLeave = () => {
|
||||
setStatePageName(nextPageName);
|
||||
setNextPageName("");
|
||||
|
||||
window.setTimeout(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
setLeaving(false);
|
||||
});
|
||||
}, 0);
|
||||
};
|
||||
|
||||
switch (getPageByName(items, statePageName)) {
|
||||
case page.index:
|
||||
return (
|
||||
<PageIndex
|
||||
leaving={leaving}
|
||||
items={items}
|
||||
onLeave={handlePageLeave}
|
||||
releases={releases}
|
||||
/>
|
||||
);
|
||||
case page.overview:
|
||||
return (
|
||||
<PageOverview
|
||||
items={items}
|
||||
rings={rings}
|
||||
search={search}
|
||||
leaving={leaving}
|
||||
onLeave={handlePageLeave}
|
||||
/>
|
||||
);
|
||||
case page.help:
|
||||
return <PageHelp leaving={leaving} onLeave={handlePageLeave} />;
|
||||
case page.quadrant:
|
||||
return (
|
||||
<PageQuadrant
|
||||
leaving={leaving}
|
||||
onLeave={handlePageLeave}
|
||||
items={items}
|
||||
pageName={statePageName}
|
||||
/>
|
||||
);
|
||||
case page.itemMobile:
|
||||
return (
|
||||
<PageItemMobile
|
||||
items={items}
|
||||
pageName={statePageName}
|
||||
leaving={leaving}
|
||||
onLeave={handlePageLeave}
|
||||
/>
|
||||
);
|
||||
case page.item:
|
||||
return (
|
||||
<PageItem
|
||||
items={items}
|
||||
pageName={statePageName}
|
||||
leaving={leaving}
|
||||
onLeave={handlePageLeave}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { FormEvent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './search.scss';
|
||||
import React, { FormEvent } from "react";
|
||||
import classNames from "classnames";
|
||||
import "./search.scss";
|
||||
|
||||
type SearchProps = {
|
||||
onClose?: () => void;
|
||||
@@ -14,7 +14,10 @@ export default React.forwardRef((props: SearchProps, ref) => {
|
||||
return Search(props, ref);
|
||||
});
|
||||
|
||||
function Search({ value, onChange, onClose, open = false, onSubmit = () => {} }: SearchProps, ref: any) {
|
||||
function Search(
|
||||
{ value, onChange, onClose, open = false, onSubmit = () => {} }: SearchProps,
|
||||
ref: any
|
||||
) {
|
||||
const closable = onClose !== undefined;
|
||||
|
||||
const handleSubmit = (e: FormEvent) => {
|
||||
@@ -30,26 +33,34 @@ function Search({ value, onChange, onClose, open = false, onSubmit = () => {} }:
|
||||
};
|
||||
|
||||
return (
|
||||
<form className={classNames('search', { 'search--closable': closable })} onSubmit={handleSubmit}>
|
||||
<form
|
||||
className={classNames("search", { "search--closable": closable })}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<input
|
||||
value={value}
|
||||
type='text'
|
||||
type="text"
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
className='search__field'
|
||||
placeholder='What are you looking for?'
|
||||
className="search__field"
|
||||
placeholder="What are you looking for?"
|
||||
ref={ref}
|
||||
/>
|
||||
<span className={classNames('search__button', { 'is-open': open })}>
|
||||
<button type='submit' className='button'>
|
||||
<span className='icon icon--search button__icon' />
|
||||
<span className={classNames("search__button", { "is-open": open })}>
|
||||
<button type="submit" className="button">
|
||||
<span className="icon icon--search button__icon" />
|
||||
Search
|
||||
</button>
|
||||
</span>
|
||||
{closable && (
|
||||
<button className={classNames('search__close link-button', { 'is-open': open })} onClick={handleClose}>
|
||||
<span className='icon icon--close' />
|
||||
<button
|
||||
className={classNames("search__close link-button", {
|
||||
"is-open": open,
|
||||
})}
|
||||
onClick={handleClose}
|
||||
>
|
||||
<span className="icon icon--close" />
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 10px 120px 10px 20px;
|
||||
background: #3A444A;
|
||||
background: #3a444a;
|
||||
display: block;
|
||||
border: none;
|
||||
color: var(--color-white);
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
font-family: 'DIN';
|
||||
font-family: "DIN";
|
||||
font-weight: normal;
|
||||
|
||||
&::placeholder {
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
background: #2F393F;
|
||||
background: #2f393f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {useEffect} from "react";
|
||||
import {radarName} from "../config";
|
||||
import { useEffect } from "react";
|
||||
import { radarName } from "../config";
|
||||
|
||||
type SetTitleProps = {
|
||||
title: string
|
||||
}
|
||||
title: string;
|
||||
};
|
||||
|
||||
export default function SetTitle({title}: SetTitleProps) {
|
||||
export default function SetTitle({ title }: SetTitleProps) {
|
||||
useEffect(() => {
|
||||
document.title = `${title} | ${radarName}`
|
||||
}, [title])
|
||||
document.title = `${title} | ${radarName}`;
|
||||
}, [title]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user