From eff1bcbc2b88b2f6fdb1a853082454d95a855a79 Mon Sep 17 00:00:00 2001 From: "dennis.ludwig" Date: Wed, 16 Jun 2021 11:53:05 +0200 Subject: [PATCH] separate non featured articles on quadrant view --- .env | 2 +- dist_scripts/src/model.js | 6 +- src/animation.ts | 197 ++++++------ src/components/Item/Item.tsx | 58 ++-- src/components/Item/item.scss | 4 + src/components/ItemList/ItemList.tsx | 57 ++-- src/components/PageItem/PageItem.tsx | 356 ++++++++-------------- src/components/PageItem/item-page.scss | 4 + src/components/PageItem/useAnimations.tsx | 217 +++++++++++++ src/index.scss | 1 + src/logo.svg | 1 - src/model.js | 49 --- src/model.ts | 66 ++-- src/styles/components/headline.scss | 4 + 14 files changed, 581 insertions(+), 441 deletions(-) create mode 100644 src/components/PageItem/useAnimations.tsx delete mode 100644 src/logo.svg delete mode 100644 src/model.js diff --git a/.env b/.env index 3d6d6f7..0bcc887 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ REACT_APP_RADAR_NAME=AOE Technology Radar -PUBLIC_URL=/techradar \ No newline at end of file +PUBLIC_URL=/techradar diff --git a/dist_scripts/src/model.js b/dist_scripts/src/model.js index bb15587..615bc4d 100644 --- a/dist_scripts/src/model.js +++ b/dist_scripts/src/model.js @@ -16,15 +16,15 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from) { return to; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getFirstLetter = exports.groupByFirstLetter = exports.groupByQuadrants = exports.unfeaturedOnly = exports.featuredOnly = void 0; +exports.getFirstLetter = exports.groupByFirstLetter = exports.groupByQuadrants = exports.nonFeaturedOnly = exports.featuredOnly = void 0; var featuredOnly = function (items) { return items.filter(function (item) { return item.featured; }); }; exports.featuredOnly = featuredOnly; -var unfeaturedOnly = function (items) { +var nonFeaturedOnly = function (items) { return items.filter(function (item) { return !item.featured; }); }; -exports.unfeaturedOnly = unfeaturedOnly; +exports.nonFeaturedOnly = nonFeaturedOnly; var groupByQuadrants = function (items) { return items.reduce(function (quadrants, item) { var _a; diff --git a/src/animation.ts b/src/animation.ts index 279235d..ede4f8d 100644 --- a/src/animation.ts +++ b/src/animation.ts @@ -1,110 +1,135 @@ -import React from 'react'; +import React from "react"; + +export interface AnimationConfig { + [k: string]: Animation | Animation[]; +} export type Animations = { - [k: string]: Animation[] -} + [k: string]: Animation[]; +}; export type AnimationStates = { - [k: string]: React.CSSProperties[] -} + [k: string]: React.CSSProperties[]; +}; -type Animation = { - stateA: React.CSSProperties - stateB: React.CSSProperties - delay: number - run?(callback: (state: any) => any): any // todo fix - prepare?(callback: (state: any) => any): any // todo fix -} +export type Animation = { + stateA: React.CSSProperties; + stateB: React.CSSProperties; + delay: number; + run?(callback: (state: any) => any): any; // todo fix + prepare?(callback: (state: any) => any): any; // todo fix +}; export type AnimationRunner = { - getState(): AnimationStates - run(): any - awaitAnimationComplete(callback: () => void): any -} + getState(): AnimationStates; + run(): any; + awaitAnimationComplete(callback: () => void): any; +}; -export const createAnimation = (stateA: React.CSSProperties, stateB: React.CSSProperties, delay: number): Animation => ({ - stateA, - stateB, - delay, +export const createAnimation = ( + stateA: React.CSSProperties, + stateB: React.CSSProperties, + delay: number +): Animation => ({ + stateA, + stateB, + delay, }); -const getAnimationStates = (animations: Animation[], stateName: 'stateA' | 'stateB' = 'stateA'): React.CSSProperties[] => { - return animations.map(animation => animation[stateName]); +const getAnimationStates = ( + animations: Animation[], + stateName: "stateA" | "stateB" = "stateA" +): React.CSSProperties[] => { + return animations.map((animation) => animation[stateName]); }; const getMaxTransitionTime = (transition: string) => { - const re = /(\d+)ms/g; - const times: number[] = []; - let matches; - while ((matches = re.exec(transition)) != null) { - times.push(parseInt(matches[1], 10)); - } - return Math.max(...times); + const re = /(\d+)ms/g; + const times: number[] = []; + let matches; + while ((matches = re.exec(transition)) != null) { + times.push(parseInt(matches[1], 10)); + } + return Math.max(...times); }; const getAnimationDuration = (animation: Animation | Animation[]): number => { - if (animation instanceof Array) { - return animation.reduce((maxDuration, a) => { - const duration = getAnimationDuration(a); - if (duration > maxDuration) { - return duration; - } - return maxDuration; - }, 0); - } + if (animation instanceof Array) { + return animation.reduce((maxDuration, a) => { + const duration = getAnimationDuration(a); + if (duration > maxDuration) { + return duration; + } + return maxDuration; + }, 0); + } - const state = animation.stateB; - const maxTransition = state.transition ? getMaxTransitionTime(state.transition) : 0; - return maxTransition + animation.delay; + const state = animation.stateB; + const maxTransition = state.transition + ? getMaxTransitionTime(state.transition) + : 0; + return maxTransition + animation.delay; }; -const getMaxAnimationsDuration = (animations: Animations) => ( - Math.max(...Object.values(animations).map(animations => getAnimationDuration(Object.values(animations)))) -); +const getMaxAnimationsDuration = (animations: Animations) => + Math.max( + ...Object.values(animations).map((animations) => + getAnimationDuration(Object.values(animations)) + ) + ); -export const createAnimationRunner = (animationsIn: { [k: string]: (Animation | Animation[]) }, subscriber: () => void = () => { -}): AnimationRunner => { - const animations = Object.entries(animationsIn).reduce((state, [name, animation]) => ({ - ...state, - [name]: animation instanceof Array ? animation : [animation] as Animation[], - }), {} as Animations); +export const createAnimationRunner = ( + animationsIn: AnimationConfig, + subscriber: () => void = () => {} +): AnimationRunner => { + const animations = Object.entries(animationsIn).reduce( + (state, [name, animation]) => ({ + ...state, + [name]: + animation instanceof Array ? animation : ([animation] as Animation[]), + }), + {} as Animations + ); - let state = Object.entries(animations).reduce((state, [name, animation]) => ({ - ...state, - [name]: getAnimationStates(animation), - }), {} as AnimationStates); + let state = Object.entries(animations).reduce( + (state, [name, animation]) => ({ + ...state, + [name]: getAnimationStates(animation), + }), + {} as AnimationStates + ); - const animationsDuration = getMaxAnimationsDuration(animations); + const animationsDuration = getMaxAnimationsDuration(animations); - const animate = (name: string, animation: Animation[]) => { - animation.forEach((a, index) => { - window.requestAnimationFrame(() => { - window.setTimeout(() => { - state = { - ...state, - [name]: [ - ...(state[name]?.slice(0, index)), - a.stateB, - ...(state[name]?.slice(index + 1, state[name].length)), - ], - }; - subscriber(); - }, a.delay); - }); - }); - } + const animate = (name: string, animation: Animation[]) => { + animation.forEach((a, index) => { + window.requestAnimationFrame(() => { + window.setTimeout(() => { + state = { + ...state, + [name]: [ + ...state[name]?.slice(0, index), + a.stateB, + ...state[name]?.slice(index + 1, state[name].length), + ], + }; + subscriber(); + }, a.delay); + }); + }); + }; - return { - getState() { - return state; - }, - run() { - Object.entries(animations).forEach(([name, animation]) => { - animate(name, animation) - }); - }, - awaitAnimationComplete(callback) { - window.setTimeout(callback, animationsDuration); - }, - } -} + return { + getState() { + return state; + }, + run() { + Object.entries(animations).forEach(([name, animation]) => { + animate(name, animation); + }); + }, + awaitAnimationComplete(callback) { + window.setTimeout(callback, animationsDuration); + }, + }; +}; diff --git a/src/components/Item/Item.tsx b/src/components/Item/Item.tsx index dc47c0a..225d66b 100644 --- a/src/components/Item/Item.tsx +++ b/src/components/Item/Item.tsx @@ -1,31 +1,43 @@ -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 = { +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 Props = { item: mItem; noLeadingBorder?: boolean; active?: boolean; style: React.CSSProperties; + greyedOut?: boolean; }; -export default function Item({ item, noLeadingBorder = false, active = false, style = {} }: ItemProps) { - return ( - = ({ + item, + noLeadingBorder = false, + active = false, + style = {}, + greyedOut = false, +}) => ( + +
-
- {item.title} - -
- {item.info &&
{item.info}
} - - ); -} + {item.title} + +
+ {item.info &&
{item.info}
} + +); + +export default Item; diff --git a/src/components/Item/item.scss b/src/components/Item/item.scss index ef59282..da2e32b 100644 --- a/src/components/Item/item.scss +++ b/src/components/Item/item.scss @@ -39,6 +39,10 @@ &__title { font-size: 16px; color: var(--color-white); + + &.greyed-out { + color: var(--color-gray-light-alt); + } } &__info { diff --git a/src/components/ItemList/ItemList.tsx b/src/components/ItemList/ItemList.tsx index 4a77f28..e6dda88 100644 --- a/src/components/ItemList/ItemList.tsx +++ b/src/components/ItemList/ItemList.tsx @@ -1,32 +1,43 @@ -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; noLeadingBorder?: boolean; headerStyle?: React.CSSProperties; itemStyle?: React.CSSProperties[]; + greyedOut?: boolean; }; -export default function ItemList({ children, items, activeItem, noLeadingBorder, headerStyle = {}, itemStyle = [] }: React.PropsWithChildren) { - return ( -
-
- {children} -
-
- {items.map((item, i) => ( - - ))} -
+const ItemList: React.FC = ({ + children, + items, + activeItem, + noLeadingBorder, + headerStyle = {}, + itemStyle = [], + greyedOut = false, +}) => ( +
+
+ {children}
- ); -} +
+ {items.map((item, i) => ( + + ))} +
+
+); + +export default ItemList; diff --git a/src/components/PageItem/PageItem.tsx b/src/components/PageItem/PageItem.tsx index 485ba06..f7a49bd 100644 --- a/src/components/PageItem/PageItem.tsx +++ b/src/components/PageItem/PageItem.tsx @@ -1,239 +1,147 @@ -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, useMemo } 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 { useAnimations } from "./useAnimations"; +import "./item-page.scss"; +import { translate } from "../../config"; import { - AnimationStates, - createAnimation, - createAnimationRunner -} from '../../animation'; -import './item-page.scss'; -import {translate} from '../../config'; -import {groupByQuadrants, Item} from '../../model'; + featuredOnly, + nonFeaturedOnly, + 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; +type Props = { + pageName: string; + items: Item[]; + leaving: boolean; + onLeave: () => void; }; -export default function PageItem({pageName, items, leaving, onLeave}: PageItemProps) { - const itemsInRing = getItemsInRing(pageName, items); +const PageItem: React.FC = ({ pageName, items, leaving, onLeave }) => { + const itemsInRing = getItemsInRing(pageName, items); + const featuredItemsInRing = featuredOnly(itemsInRing); + const nonFeaturedItemsInRing = nonFeaturedOnly(itemsInRing); - 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 { getAnimationState, getAnimationStates } = useAnimations({ + itemsInRing, + featuredItemsInRing, + nonFeaturedItemsInRing, + onLeave, + leaving, + }); - 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 item = getItem(pageName, items); - const [animations, setAnimations] = useState(() => { - return leaving ? createAnimationRunner(animationsIn).getState() : {} - }); - - 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]; - } - - const getAnimationState = (name: string) => { - const animations = getAnimationStates(name) - if (animations === undefined || animations.length === 0) { - return undefined - } - return animations[0] - }; - - const item = getItem(pageName, items); - - return ( -
- -
-
-
-
-

{translate(item.quadrant)}

-
- - -
-
- - {item.ring} - -
-
- - - Quadrant Overview - -
-
-
-
- -
-
-
-
-
-
-
-
-

{item.title}

-
-
- - {item.ring} - -
-
-
-
- {item.revisions.length > 1 && } -
-
+ return ( + <> + +
+
+
+
+

{translate(item.quadrant)}

+ +
+
+ + {item.ring} + +
+
+ + + Quadrant Overview + +
+
+
+ + {nonFeaturedItemsInRing.length > 0 && ( +
+ +
+
+

Not featured anymore

+
+
+
+
+ )} + +
+ +
+
- ); -} +
+
+
+
+
+

+ {item.title} +

+
+
+ + {item.ring} + +
+
+
+
+ {item.revisions.length > 1 && ( + + )} +
+
+
+ + ); +}; + +export default PageItem; diff --git a/src/components/PageItem/item-page.scss b/src/components/PageItem/item-page.scss index 5098267..c7419b8 100644 --- a/src/components/PageItem/item-page.scss +++ b/src/components/PageItem/item-page.scss @@ -48,6 +48,10 @@ padding: 0 10px 0 100px; } } + + &__non-featured-items { + margin-top: 45px; + } } .mobile-item-page { diff --git a/src/components/PageItem/useAnimations.tsx b/src/components/PageItem/useAnimations.tsx new file mode 100644 index 0000000..dfef46f --- /dev/null +++ b/src/components/PageItem/useAnimations.tsx @@ -0,0 +1,217 @@ +import React, { useEffect, useState, useMemo } from "react"; +import { + Animation, + AnimationConfig as AbstractAnimationConfig, + AnimationStates, + createAnimation, + createAnimationRunner, +} from "../../animation"; +import { Item } from "../../model"; + +interface Props { + itemsInRing: Item[]; + featuredItemsInRing: Item[]; + nonFeaturedItemsInRing: Item[]; + leaving: boolean; + onLeave: () => void; +} + +export const useAnimations = ({ + itemsInRing, + featuredItemsInRing, + nonFeaturedItemsInRing, + leaving, + onLeave, +}: Props) => { + interface AnimationConfig extends AbstractAnimationConfig { + background: Animation; + navHeader: Animation; + text: Animation; + featuredItems: Animation[]; + nonFeaturedItems: Animation[]; + footer: Animation; + } + + type AnimationNames = keyof AnimationConfig; + + const animationsIn: AnimationConfig = useMemo( + () => ({ + 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 + ), + featuredItems: featuredItemsInRing.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 + ) + ), + nonFeaturedItems: nonFeaturedItemsInRing.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 * (featuredItemsInRing.length + 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 + ), + }), + [itemsInRing, featuredItemsInRing, nonFeaturedItemsInRing] + ); + + const animationsOut: AnimationConfig = useMemo( + () => ({ + 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 + ), + featuredItems: featuredItemsInRing.map((item, i) => + createAnimation( + animationsIn.featuredItems[i].stateB, + { + transition: "opacity 150ms ease-out, transform 300ms ease-out", + transform: "translateX(40px)", + opacity: "0", + }, + 100 + 50 * i + ) + ), + nonFeaturedItems: nonFeaturedItemsInRing.map((item, i) => + createAnimation( + animationsIn.nonFeaturedItems[i].stateB, + { + transition: "opacity 150ms ease-out, transform 300ms ease-out", + transform: "translateX(40px)", + opacity: "0", + }, + 100 + 50 * (featuredItemsInRing.length + i) + ) + ), + footer: createAnimation( + animationsIn.text.stateB, + { + transition: "opacity 150ms ease-out, transform 300ms ease-out", + transform: "translateX(40px)", + opacity: "0", + }, + 200 + itemsInRing.length * 50 + ), + }), + [itemsInRing, featuredItemsInRing, nonFeaturedItemsInRing, animationsIn] + ); + + const [animations, setAnimations] = useState(() => { + return leaving ? createAnimationRunner(animationsIn).getState() : {}; + }); + + 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: AnimationNames) => animations[name]; + + const getAnimationState = (name: AnimationNames) => { + const animations = getAnimationStates(name); + if (animations === undefined || animations.length === 0) { + return undefined; + } + return animations[0]; + }; + + return { + getAnimationStates, + getAnimationState, + }; +}; diff --git a/src/index.scss b/src/index.scss index 5e7632c..f7a7d1b 100644 --- a/src/index.scss +++ b/src/index.scss @@ -17,6 +17,7 @@ --color-gray-dark-alt2: #434D53; --color-gray-normal: #7f858a; --color-gray-light: #7D878D; + --color-gray-light-alt: #adadad; --color-white: #fff; --color-green: #5CB449; diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/model.js b/src/model.js deleted file mode 100644 index d34d885..0000000 --- a/src/model.js +++ /dev/null @@ -1,49 +0,0 @@ -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; -var __spreadArray = (this && this.__spreadArray) || function (to, from) { - for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) - to[j] = from[i]; - return to; -}; -export var featuredOnly = function (items) { return items.filter(function (item) { return item.featured; }); }; -export var groupByQuadrants = function (items) { - return items.reduce(function (quadrants, item) { - var _a; - return (__assign(__assign({}, quadrants), (_a = {}, _a[item.quadrant] = addItemToQuadrant(quadrants[item.quadrant], item), _a))); - }, {}); -}; -export var groupByFirstLetter = function (items) { - var index = items.reduce(function (letterIndex, item) { - var _a; - return (__assign(__assign({}, letterIndex), (_a = {}, _a[getFirstLetter(item)] = addItemToList(letterIndex[getFirstLetter(item)], item), _a))); - }, {}); - return Object.keys(index) - .sort() - .map(function (letter) { return ({ - letter: letter, - items: index[letter], - }); }); -}; -var addItemToQuadrant = function (quadrant, item) { - var _a; - if (quadrant === void 0) { quadrant = {}; } - return (__assign(__assign({}, quadrant), (_a = {}, _a[item.ring] = addItemToRing(quadrant[item.ring], item), _a))); -}; -var addItemToList = function (list, item) { - if (list === void 0) { list = []; } - return __spreadArray(__spreadArray([], list), [item]); -}; -var addItemToRing = function (ring, item) { - if (ring === void 0) { ring = []; } - return __spreadArray(__spreadArray([], ring), [item]); -}; -export var getFirstLetter = function (item) { return item.title.substr(0, 1).toUpperCase(); }; diff --git a/src/model.ts b/src/model.ts index a73f9f6..c8daac6 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1,43 +1,46 @@ -import { Ring } from "./config" +import { Ring } from "./config"; export type ItemAttributes = { - name: string - ring: Ring - quadrant: string - title: string - featured: boolean -} + name: string; + ring: Ring; + quadrant: string; + title: string; + featured: boolean; +}; -export type FlagType = 'new' | 'changed' | 'default' +export type FlagType = "new" | "changed" | "default"; export type Item = ItemAttributes & { - featured: boolean - body: string - info: string - flag: FlagType - revisions: Revision[] -} + featured: boolean; + body: string; + info: string; + flag: FlagType; + revisions: Revision[]; +}; export type Revision = ItemAttributes & { - body: string - fileName: string - release: string -} + body: string; + fileName: string; + release: string; +}; export type Quadrant = { - [name: string]: Item[] -} + [name: string]: Item[]; +}; export type Radar = { - items: Item[] - releases: string[] -} + items: Item[]; + releases: string[]; +}; export type Group = { - [quadrant: string]: Quadrant -} + [quadrant: string]: Quadrant; +}; -export const featuredOnly = (items: Item[]) => items.filter(item => item.featured); +export const featuredOnly = (items: Item[]) => + items.filter((item) => item.featured); +export const nonFeaturedOnly = (items: Item[]) => + items.filter((item) => !item.featured); export const groupByQuadrants = (items: Item[]): Group => items.reduce( @@ -45,7 +48,7 @@ export const groupByQuadrants = (items: Item[]): Group => ...quadrants, [item.quadrant]: addItemToQuadrant(quadrants[item.quadrant], item), }), - {} as {[k: string]: Quadrant}, + {} as { [k: string]: Quadrant } ); export const groupByFirstLetter = (items: Item[]) => { @@ -54,15 +57,15 @@ export const groupByFirstLetter = (items: Item[]) => { ...letterIndex, [getFirstLetter(item)]: addItemToList( letterIndex[getFirstLetter(item)], - item, + item ), }), - {} as {[k: string]: Item[]}, + {} as { [k: string]: Item[] } ); return Object.keys(index) .sort() - .map(letter => ({ + .map((letter) => ({ letter, items: index[letter], })); @@ -77,4 +80,5 @@ const addItemToList = (list: Item[] = [], item: Item) => [...list, item]; const addItemToRing = (ring: Item[] = [], item: Item) => [...ring, item]; -export const getFirstLetter = (item: Item) => item.title.substr(0, 1).toUpperCase(); +export const getFirstLetter = (item: Item) => + item.title.substr(0, 1).toUpperCase(); diff --git a/src/styles/components/headline.scss b/src/styles/components/headline.scss index 0803a8f..5452aa0 100644 --- a/src/styles/components/headline.scss +++ b/src/styles/components/headline.scss @@ -1,3 +1,7 @@ +h4.headline { + font-size: 18px; +} + .headline { margin: 0; padding: 0;