├── .babelrc
├── .eslintrc.json
├── .github
├── ISSUE_TEMPLATE
│ └── config.yml
└── workflows
│ ├── build.yml
│ └── push.yml
├── .gitignore
├── .nvmrc
├── .prettierrc
├── LICENSE
├── README.md
├── app.json
├── editor.js
├── package-lock.json
├── package.json
├── public
├── index.html
└── static
│ ├── 50Jahre_Frauenwahlrecht_negativ.svg
│ ├── 50Jahre_Frauenwahlrecht_positiv.svg
│ ├── USA_Farblos_665px-Farblos_665px.png
│ ├── apple-touch-icon.png
│ ├── bordell.jpeg
│ ├── brigitte_meyer.jpg
│ ├── carousel
│ ├── berg.png
│ ├── binswanger.png
│ ├── binswanger_dark.png
│ ├── calle.png
│ ├── eth.png
│ ├── homestory.gif
│ ├── homestory.png
│ ├── jackson.png
│ ├── mike.png
│ ├── murdoch.png
│ ├── niggli.png
│ ├── rinck.png
│ ├── solstad.png
│ ├── strahlen.png
│ ├── test.png
│ └── vault.png
│ ├── christof_moser.jpg
│ ├── dada.jpg
│ ├── dada_dark.png
│ ├── desert.jpg
│ ├── dynamic_hello.js
│ ├── fonts
│ ├── gt-america-standard-medium.eot
│ ├── gt-america-standard-medium.ttf
│ ├── gt-america-standard-medium.woff
│ ├── gt-america-standard-regular.eot
│ ├── gt-america-standard-regular.ttf
│ ├── gt-america-standard-regular.woff
│ ├── rubis-bold.eot
│ ├── rubis-bold.ttf
│ ├── rubis-bold.woff
│ ├── rubis-bold.woff2
│ ├── rubis-regular.eot
│ ├── rubis-regular.ttf
│ ├── rubis-regular.woff
│ └── rubis-regular.woff2
│ ├── geo
│ ├── bfs-g3g12.json
│ ├── ch-cantons-wo-lakes.json
│ ├── ch-cantons.json
│ ├── countries2016-20m-europe.json
│ ├── country-names.csv
│ ├── epsg2056-projected-ch-cantons-wo-lakes.json
│ ├── epsg2056-projected-ch-cantons.json
│ ├── nuts2013-20m-l2-custom-gdp.json
│ ├── nuts2016-20m-l2.json
│ ├── solar.png
│ ├── world-atlas-110m-without-antarctic.json
│ └── world-atlas-110m.json
│ ├── im-gespr-3.gif
│ ├── landscape.jpg
│ ├── main.vtt
│ ├── nl-chart.png
│ ├── profilePicture1.png
│ ├── profilePicture2.png
│ ├── rothaus_landscape.jpg
│ ├── rothaus_portrait.jpg
│ ├── sample.mp3
│ ├── skilifte-front.svg
│ ├── top-story-badge.png
│ ├── tweet_preview.jpg
│ ├── twitter_icon.jpg
│ └── video.jpg
├── rollup.config.js
├── scripts
└── renderNewsletter.js
├── src
├── README.md
├── catalogTheme.css
├── catalogTheme.js
├── chart.ts
├── components
│ ├── AudioPlayer
│ │ ├── Player.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── BlockQuote
│ │ ├── BlockQuote.js
│ │ ├── BlockQuoteParagraph.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Button
│ │ ├── docs.md
│ │ └── index.tsx
│ ├── Callout
│ │ ├── CalloutMenu.tsx
│ │ ├── docs.md
│ │ └── index.tsx
│ ├── Center
│ │ ├── docs.md
│ │ └── index.js
│ ├── Chart
│ │ ├── Bars.docs.md
│ │ ├── Bars.js
│ │ ├── Bars.schema.js
│ │ ├── ChartContext.js
│ │ ├── ChartContext.utils.js
│ │ ├── ColorLegend.js
│ │ ├── ContextBox.js
│ │ ├── Csv.js
│ │ ├── Editor
│ │ │ ├── AxisFormatDropdown.js
│ │ │ ├── ColorDropdownElement.js
│ │ │ ├── ColorField.js
│ │ │ ├── ColorPickerCallout.js
│ │ │ ├── CustomValueDropdown.js
│ │ │ ├── FormFields.js
│ │ │ ├── TickField.js
│ │ │ ├── docs.data.js
│ │ │ ├── docs.md
│ │ │ ├── index.js
│ │ │ └── utils.js
│ │ ├── Hemicycle.docs.md
│ │ ├── Hemicycle.js
│ │ ├── Hemicycle.schema.js
│ │ ├── LICENSE
│ │ ├── Layout.constants.js
│ │ ├── LineGroup.js
│ │ ├── Lines.context.js
│ │ ├── Lines.docs.md
│ │ ├── Lines.js
│ │ ├── Lines.schema.js
│ │ ├── Lines.utils.js
│ │ ├── Lollipops.docs.md
│ │ ├── Maps.docs.data.js
│ │ ├── Maps.docs.md
│ │ ├── Maps.js
│ │ ├── Maps.layout.js
│ │ ├── Maps.schema.js
│ │ ├── ScatterPlotCanvas.js
│ │ ├── ScatterPlotContextBox.js
│ │ ├── ScatterPlotElements.js
│ │ ├── ScatterPlotGroup.js
│ │ ├── ScatterPlots.docs.md
│ │ ├── ScatterPlots.js
│ │ ├── ScatterPlots.schema.js
│ │ ├── ScatterPlots.utils.js
│ │ ├── Slopes.docs.md
│ │ ├── Table.docs.md
│ │ ├── Table.js
│ │ ├── Table.schema.js
│ │ ├── TimeBarGroup.js
│ │ ├── TimeBars.context.js
│ │ ├── TimeBars.docs.md
│ │ ├── TimeBars.js
│ │ ├── TimeBars.schema.js
│ │ ├── TimeBars.utils.js
│ │ ├── TimeBarsAnnotations.js
│ │ ├── XAxis.js
│ │ ├── colorMaps.js
│ │ ├── docs.js
│ │ ├── index.js
│ │ ├── utils.js
│ │ └── utils.test.js
│ ├── Collapsable
│ │ ├── Collapsable.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Colors
│ │ ├── ColorContext.tsx
│ │ ├── docs.md
│ │ └── useColorContext.js
│ ├── CommentBody
│ │ ├── email
│ │ │ ├── BlockCode.js
│ │ │ ├── Blockquote.js
│ │ │ ├── Container.js
│ │ │ ├── List.js
│ │ │ ├── Paragraph.js
│ │ │ └── index.js
│ │ └── web
│ │ │ ├── BlockCode.js
│ │ │ ├── Blockquote.js
│ │ │ ├── Container.js
│ │ │ ├── List.js
│ │ │ ├── Paragraph.js
│ │ │ └── index.js
│ ├── CommentTeaser
│ │ ├── CommentTeaser.js
│ │ ├── DiscussionFooter.js
│ │ ├── docs.imports.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Discussion
│ │ ├── Composer
│ │ │ ├── CommentComposer.js
│ │ │ ├── CommentComposerPlaceholder.tsx
│ │ │ ├── CommentDraftHelper.js
│ │ │ ├── docs.imports.js
│ │ │ ├── docs.md
│ │ │ └── index.js
│ │ ├── DiscussionCommentsWrapper.tsx
│ │ ├── DiscussionContext.docs.js
│ │ ├── DiscussionContext.js
│ │ ├── Internal
│ │ │ ├── Comment
│ │ │ │ ├── ActionsMenu.tsx
│ │ │ │ ├── Body.js
│ │ │ │ ├── CommentActions.tsx
│ │ │ │ ├── CommentEmbed.js
│ │ │ │ ├── Context.js
│ │ │ │ ├── Header.js
│ │ │ │ ├── HeaderMetaLine.tsx
│ │ │ │ ├── IconLink.js
│ │ │ │ ├── RelativeTime.js
│ │ │ │ ├── VoteButtons.tsx
│ │ │ │ ├── index.js
│ │ │ │ └── render.js
│ │ │ ├── Composer
│ │ │ │ ├── Actions.js
│ │ │ │ ├── Error.js
│ │ │ │ ├── Header.tsx
│ │ │ │ ├── Tags.js
│ │ │ │ └── index.js
│ │ │ ├── PropTypes.js
│ │ │ ├── docs.imports.js
│ │ │ └── docs.md
│ │ ├── Statements
│ │ │ ├── StatementNode.js
│ │ │ ├── helpers
│ │ │ │ ├── ColorContextHelper.js
│ │ │ │ ├── colorHelper.js
│ │ │ │ └── tagHelper.js
│ │ │ └── index.js
│ │ ├── Tree
│ │ │ ├── BoardComment.tsx
│ │ │ ├── CommentNode.tsx
│ │ │ ├── LoadMore.js
│ │ │ ├── docs.imports.js
│ │ │ ├── docs.md
│ │ │ └── index.ts
│ │ ├── __docs__
│ │ │ ├── comments.js
│ │ │ └── exampleMdast.js
│ │ ├── config.js
│ │ └── docs.md
│ ├── Dossier
│ │ ├── Headline.js
│ │ ├── Lead.js
│ │ ├── More.js
│ │ ├── Subheader.js
│ │ ├── Tag.js
│ │ ├── Teaser.js
│ │ ├── Teaser.md
│ │ ├── TeaserIntro.js
│ │ ├── TileHeadline.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── DynamicComponent
│ │ ├── docs.md
│ │ ├── index.js
│ │ └── require.js
│ ├── ErrorBoundary
│ │ └── index.js
│ ├── Figure
│ │ ├── Byline.js
│ │ ├── Caption.js
│ │ ├── Image.js
│ │ ├── SwitchImage.js
│ │ ├── docs.md
│ │ ├── index.js
│ │ ├── utils.js
│ │ └── utils.test.js
│ ├── Form
│ │ ├── Autocomplete.docs.md
│ │ ├── Autocomplete.js
│ │ ├── Checkbox.docs.md
│ │ ├── Checkbox.tsx
│ │ ├── Dropdown.docs.md
│ │ ├── Dropdown.tsx
│ │ ├── DropdownLabel.tsx
│ │ ├── Field.docs.js
│ │ ├── Field.tsx
│ │ ├── FieldSet.js
│ │ ├── NativeDropdown.tsx
│ │ ├── Radio.docs.md
│ │ ├── Radio.tsx
│ │ ├── Slider.docs.md
│ │ ├── Slider.tsx
│ │ ├── VirtualDropdown.tsx
│ │ ├── constants.ts
│ │ └── docs.md
│ ├── Format
│ │ ├── Tag.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Grid
│ │ ├── docs.md
│ │ └── index.js
│ ├── IconButton
│ │ ├── docs.md
│ │ └── index.tsx
│ ├── Icons
│ │ ├── CustomIcons
│ │ │ ├── BackIcon.js
│ │ │ ├── CustomIconBase.js
│ │ │ ├── DiscussionIcon.js
│ │ │ ├── FontSizeIcon.js
│ │ │ ├── MarkdownIcon.js
│ │ │ ├── MdCheckCircleOutlined.js
│ │ │ ├── MdCheckSmall.js
│ │ │ ├── MdInsertChartOutlined.js
│ │ │ ├── SearchMenuIcon.js
│ │ │ ├── ShareIcon.js
│ │ │ ├── SpotifyIcon.js
│ │ │ ├── SubscriptIcon.js
│ │ │ └── SuperscriptIcon.js
│ │ ├── IconContext.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── IllustrationHtml
│ │ ├── docs.md
│ │ └── index.js
│ ├── InfoBox
│ │ ├── InfoBox.js
│ │ ├── ListItem.js
│ │ ├── Subhead.js
│ │ ├── Text.js
│ │ ├── Title.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── LazyLoad
│ │ ├── Image.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── List
│ │ ├── List.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Loader
│ │ ├── docs.md
│ │ └── index.js
│ ├── Logo
│ │ ├── BrandMark.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Overlay
│ │ ├── Overlay.tsx
│ │ ├── OverlayBody.tsx
│ │ ├── OverlayToolbar.tsx
│ │ ├── docs.imports.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Progress
│ │ ├── Circle.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── PullQuote
│ │ ├── PullQuote.js
│ │ ├── Source.js
│ │ ├── Text.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── RawHtml
│ │ ├── docs.md
│ │ └── index.js
│ ├── SeriesNav
│ │ ├── SeriesNav.js
│ │ ├── SeriesNavTile.js
│ │ ├── SeriesNavTileContent.js
│ │ ├── __docs__
│ │ │ ├── index.js
│ │ │ └── seriesNavExample.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── ShareImage
│ │ ├── ShareImagePreview.js
│ │ ├── SharePreviewFacebook.js
│ │ ├── SharePreviewTwitter.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Social
│ │ ├── Header.js
│ │ ├── Tweet.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── Spinner
│ │ ├── docs.md
│ │ └── index.js
│ ├── Tabs
│ │ ├── Scroller.tsx
│ │ ├── TabButton.tsx
│ │ └── docs.md
│ ├── TeaserActiveDebates
│ │ ├── ActiveDebates.js
│ │ ├── DebateComment.js
│ │ ├── DebateHeader.js
│ │ ├── DebateTeaser.js
│ │ ├── __docs__
│ │ │ ├── activeDebatesExample.js
│ │ │ └── index.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── TeaserCarousel
│ │ ├── ArticleCount.js
│ │ ├── Carousel.js
│ │ ├── Context.js
│ │ ├── Format.js
│ │ ├── Grid.js
│ │ ├── Headline.js
│ │ ├── Lead.js
│ │ ├── Row.js
│ │ ├── Subject.js
│ │ ├── Tile.js
│ │ ├── TileContainer.js
│ │ ├── constants.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── TeaserEmbedComment
│ │ └── index.js
│ ├── TeaserFeed
│ │ ├── Container.js
│ │ ├── Credit.js
│ │ ├── Format.js
│ │ ├── Headline.js
│ │ ├── Highlight.js
│ │ ├── InternalOnlyTag.js
│ │ ├── Lead.js
│ │ ├── docs.md
│ │ ├── index.js
│ │ └── utils.js
│ ├── TeaserFront
│ │ ├── Credit.js
│ │ ├── CreditLink.js
│ │ ├── Format.js
│ │ ├── Image.js
│ │ ├── Image.md
│ │ ├── ImageHeadline.js
│ │ ├── Lead.js
│ │ ├── Logo.js
│ │ ├── Split.js
│ │ ├── Split.md
│ │ ├── SplitHeadline.js
│ │ ├── Subject.js
│ │ ├── Text.js
│ │ ├── Tile.js
│ │ ├── Tile.md
│ │ ├── TileHeadline.js
│ │ ├── TileRow.js
│ │ ├── Typo.js
│ │ ├── Typo.md
│ │ ├── TypoHeadline.js
│ │ ├── index.js
│ │ └── mediaQueries.js
│ ├── TeaserMyMagazine
│ │ ├── TeaserMyMagazine.js
│ │ ├── __docs__
│ │ │ ├── index.js
│ │ │ └── myMagazineExamples.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── TeaserShared
│ │ ├── SectionTitle.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── TitleBlock
│ │ ├── docs.md
│ │ └── index.js
│ ├── Typography
│ │ ├── Editorial.js
│ │ ├── Interaction.js
│ │ ├── Meta.js
│ │ ├── Scribble.js
│ │ ├── docs.md
│ │ ├── fontRules.js
│ │ ├── index.js
│ │ ├── styles.js
│ │ └── utils.js
│ ├── Variables
│ │ └── index.js
│ ├── Video
│ │ ├── Image.js
│ │ ├── Meta.js
│ │ ├── Video.js
│ │ ├── docs.md
│ │ └── index.js
│ ├── VideoPlayer
│ │ ├── Icons
│ │ │ ├── Fullscreen.js
│ │ │ ├── Play.js
│ │ │ ├── Rewind.js
│ │ │ ├── Subtitles.js
│ │ │ └── Volume.js
│ │ ├── Player.js
│ │ ├── docs.md
│ │ ├── fullscreen.js
│ │ └── index.js
│ └── globalMediaState.js
├── development
│ ├── process.docs.md
│ └── typescript.docs.md
├── editor.ts
├── global.css
├── index.js
├── lib.ts
├── lib
│ ├── globalMediaState.js
│ ├── helpers.js
│ ├── inQuotes.docs.md
│ ├── inQuotes.js
│ ├── slug.docs.md
│ ├── slug.js
│ ├── slug.test.js
│ ├── styleMixins.js
│ ├── textGauger.js
│ ├── timeFormat.js
│ ├── timeago.js
│ ├── timeago.test.js
│ ├── timeahead.js
│ ├── timeahead.test.js
│ ├── timeduration.js
│ ├── timeduration.test.js
│ ├── translate.docs.md
│ ├── translate.ts
│ ├── translations.json
│ ├── useBodyScrollLock.js
│ ├── useBoundingClientRect.js
│ ├── useCurrentMinute.js
│ ├── useDebounce.js
│ ├── useHeaderHeight.docs.md
│ ├── useHeaderHeight.js
│ ├── useMediaQuery.js
│ ├── usePrevious.js
│ └── warn.js
├── react-app-env.d.ts
├── templates.ts
├── templates
│ ├── Article
│ │ ├── Container.js
│ │ ├── base.js
│ │ ├── blocks.js
│ │ ├── docs.md
│ │ ├── dynamicComponent.js
│ │ ├── email
│ │ │ ├── docs.md
│ │ │ └── index.js
│ │ ├── index.js
│ │ ├── teasers.js
│ │ ├── test
│ │ │ ├── article.stub.js
│ │ │ └── render.test.js
│ │ ├── utils.js
│ │ └── utils.test.js
│ ├── Comment
│ │ ├── docs.md
│ │ ├── email.js
│ │ ├── index.js
│ │ ├── schema.js
│ │ └── web.js
│ ├── Discussion
│ │ ├── docs.md
│ │ └── index.js
│ ├── Dossier
│ │ ├── docs.md
│ │ └── index.js
│ ├── EditorialNewsletter
│ │ ├── docs.md
│ │ ├── email
│ │ │ ├── Blockquote.js
│ │ │ ├── Button.js
│ │ │ ├── Center.js
│ │ │ ├── Container.js
│ │ │ ├── Cover.js
│ │ │ ├── Figure.js
│ │ │ ├── Footer.js
│ │ │ ├── HR.js
│ │ │ ├── Header.js
│ │ │ ├── Headlines.js
│ │ │ ├── List.js
│ │ │ ├── Paragraph.js
│ │ │ ├── SubSup.js
│ │ │ └── index.js
│ │ ├── index.js
│ │ ├── schema.js
│ │ └── web
│ │ │ ├── Button.js
│ │ │ ├── Container.js
│ │ │ ├── Figure.js
│ │ │ ├── ListP.js
│ │ │ └── index.js
│ ├── Format
│ │ ├── docs.md
│ │ └── index.js
│ ├── Front
│ │ ├── docs.md
│ │ ├── index.js
│ │ └── liveTeasers.js
│ ├── Page
│ │ ├── docs.md
│ │ └── index.js
│ ├── Section
│ │ ├── docs.md
│ │ └── index.js
│ ├── docs.js
│ └── shared
│ │ └── email
│ │ ├── components
│ │ ├── BlockQuote.js
│ │ ├── Caption.js
│ │ ├── Center.js
│ │ ├── Figure.js
│ │ ├── Heading.js
│ │ ├── HorizontalRule.js
│ │ ├── InfoBox.js
│ │ ├── Link.js
│ │ ├── List.js
│ │ ├── Note.js
│ │ ├── Paragraph.js
│ │ ├── PullQuote.js
│ │ ├── Sub.js
│ │ ├── Sup.js
│ │ └── TitleBlock.js
│ │ ├── rules
│ │ ├── articleCollectionRule.js
│ │ ├── blockQuoteRule.js
│ │ ├── centerRule.js
│ │ ├── figureGroupRule.js
│ │ ├── figureRule.js
│ │ ├── hrRule.js
│ │ ├── infoBoxRule.js
│ │ ├── inlineHeadingsRule.js
│ │ ├── inlineRules.js
│ │ ├── legendRules.js
│ │ ├── linkRule.js
│ │ ├── listRule.js
│ │ ├── noteRule.js
│ │ ├── paragraphRule.js
│ │ ├── pullQuoteRule.js
│ │ ├── teaserGroupRule.js
│ │ └── titleBlockRule.js
│ │ └── util
│ │ ├── ImageSizingUtil.js
│ │ └── NodeDepthUtil.js
└── theme
│ ├── colors.docs.js
│ ├── colors.js
│ ├── env.js
│ ├── fonts.js
│ ├── mediaQueries.js
│ ├── zIndex.docs.md
│ └── zIndex.js
├── static.json
└── tsconfig.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/react", "@babel/preset-env"],
3 | "plugins": [
4 | // Stage 2
5 | // ["@babel/plugin-proposal-decorators", { "legacy": true }],
6 | "@babel/plugin-proposal-function-sent",
7 | "@babel/plugin-proposal-export-namespace-from",
8 | "@babel/plugin-proposal-numeric-separator",
9 | "@babel/plugin-proposal-throw-expressions",
10 |
11 | // Stage 3
12 | "@babel/plugin-syntax-dynamic-import",
13 | "@babel/plugin-syntax-import-meta",
14 | ["@babel/plugin-proposal-class-properties", { "loose": false }],
15 | "@babel/plugin-proposal-json-strings"
16 | ]
17 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react", "react-hooks", "prettier", "jsx-a11y"],
3 | "extends": [
4 | "eslint:recommended",
5 | "plugin:react/recommended",
6 | "plugin:prettier/recommended"
7 | ],
8 | "parser": "babel-eslint",
9 | "env": {
10 | "browser": true,
11 | "es6": true,
12 | "node": true,
13 | "jest": true
14 | },
15 | "rules": {
16 | "react-hooks/rules-of-hooks": "error",
17 | "react-hooks/exhaustive-deps": "off",
18 | "react/react-in-jsx-scope": "off",
19 | "react/jsx-no-target-blank": "off",
20 | "react/display-name": "off",
21 | "react/prop-types": "off",
22 | "no-unused-vars": "warn",
23 | "no-empty": "warn"
24 | },
25 | "settings": {
26 | "react": {
27 | "version": "detect"
28 | }
29 | },
30 | "overrides": [
31 | {
32 | "files": ["*.ts", "*.tsx"],
33 | "extends": [
34 | "eslint:recommended",
35 | "plugin:react/recommended",
36 | "plugin:@typescript-eslint/recommended",
37 | "plugin:prettier/recommended"
38 | ],
39 | "parser": "@typescript-eslint/parser",
40 | "rules": {
41 | "@typescript-eslint/no-loss-of-precision": "off",
42 | "react/prop-types": "off",
43 | "react/display-name": "off"
44 | }
45 | }
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Bug report
4 | url: https://github.com/republik/plattform/issues/new/choose
5 | about: This repository has been moved into republik/plattform.
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build, Test & Release Styleguide
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: actions/setup-node@v2-beta
14 | with:
15 | node-version: '12'
16 | - run: npm prune
17 | - run: npm install
18 | - run: npm run test
19 | - run: npm run build:lib
20 | - name: Release
21 | env:
22 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
23 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
24 | run: npm run semantic-release
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /dist
12 |
13 | # misc
14 | .DS_Store
15 | .env
16 | npm-debug.log*
17 | yarn-debug.log*
18 | yarn-error.log*
19 | .idea
20 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 14
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "jsxSingleQuote": true,
4 | "semi": false,
5 | "trailingComma": "none",
6 | "arrowParens": "avoid"
7 | }
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "styleguide",
3 | "scripts": {},
4 | "env": {
5 | "REACT_APP_SG_BRAND_MARK_PATH": {
6 | "required": true
7 | },
8 | "REACT_APP_SG_BRAND_MARK_VIEWBOX": {
9 | "required": true
10 | },
11 | "REACT_APP_SG_COLORS": {
12 | "required": true
13 | },
14 | "REACT_APP_SG_FONT_FACES": {
15 | "required": true
16 | },
17 | "REACT_APP_SG_FONT_FAMILIES": {
18 | "required": true
19 | },
20 | "REACT_APP_SG_LOGO_PATH": {
21 | "required": true
22 | },
23 | "REACT_APP_SG_LOGO_VIEWBOX": {
24 | "required": true
25 | }
26 | },
27 | "formation": {},
28 | "addons": [],
29 | "buildpacks": [
30 | {
31 | "url": "https://github.com/mars/create-react-app-buildpack"
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/editor.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./dist/cjs/editor/editor')
2 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Styleguide
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/public/static/USA_Farblos_665px-Farblos_665px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/USA_Farblos_665px-Farblos_665px.png
--------------------------------------------------------------------------------
/public/static/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/static/bordell.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/bordell.jpeg
--------------------------------------------------------------------------------
/public/static/brigitte_meyer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/brigitte_meyer.jpg
--------------------------------------------------------------------------------
/public/static/carousel/berg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/berg.png
--------------------------------------------------------------------------------
/public/static/carousel/binswanger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/binswanger.png
--------------------------------------------------------------------------------
/public/static/carousel/binswanger_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/binswanger_dark.png
--------------------------------------------------------------------------------
/public/static/carousel/calle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/calle.png
--------------------------------------------------------------------------------
/public/static/carousel/eth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/eth.png
--------------------------------------------------------------------------------
/public/static/carousel/homestory.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/homestory.gif
--------------------------------------------------------------------------------
/public/static/carousel/homestory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/homestory.png
--------------------------------------------------------------------------------
/public/static/carousel/jackson.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/jackson.png
--------------------------------------------------------------------------------
/public/static/carousel/mike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/mike.png
--------------------------------------------------------------------------------
/public/static/carousel/murdoch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/murdoch.png
--------------------------------------------------------------------------------
/public/static/carousel/niggli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/niggli.png
--------------------------------------------------------------------------------
/public/static/carousel/rinck.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/rinck.png
--------------------------------------------------------------------------------
/public/static/carousel/solstad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/solstad.png
--------------------------------------------------------------------------------
/public/static/carousel/strahlen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/strahlen.png
--------------------------------------------------------------------------------
/public/static/carousel/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/test.png
--------------------------------------------------------------------------------
/public/static/carousel/vault.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/carousel/vault.png
--------------------------------------------------------------------------------
/public/static/christof_moser.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/christof_moser.jpg
--------------------------------------------------------------------------------
/public/static/dada.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/dada.jpg
--------------------------------------------------------------------------------
/public/static/dada_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/dada_dark.png
--------------------------------------------------------------------------------
/public/static/desert.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/desert.jpg
--------------------------------------------------------------------------------
/public/static/dynamic_hello.js:
--------------------------------------------------------------------------------
1 | define(['react', 'glamor'], function(React, glamor) {
2 | 'use strict'
3 |
4 | React = React && React.hasOwnProperty('default') ? React['default'] : React
5 |
6 | return props =>
7 | React.createElement(
8 | 'div',
9 | glamor.css({
10 | backgroundColor: 'purple',
11 | color: 'white'
12 | }),
13 | props.text || 'other side'
14 | )
15 | })
16 |
--------------------------------------------------------------------------------
/public/static/fonts/gt-america-standard-medium.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/gt-america-standard-medium.eot
--------------------------------------------------------------------------------
/public/static/fonts/gt-america-standard-medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/gt-america-standard-medium.ttf
--------------------------------------------------------------------------------
/public/static/fonts/gt-america-standard-medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/gt-america-standard-medium.woff
--------------------------------------------------------------------------------
/public/static/fonts/gt-america-standard-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/gt-america-standard-regular.eot
--------------------------------------------------------------------------------
/public/static/fonts/gt-america-standard-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/gt-america-standard-regular.ttf
--------------------------------------------------------------------------------
/public/static/fonts/gt-america-standard-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/gt-america-standard-regular.woff
--------------------------------------------------------------------------------
/public/static/fonts/rubis-bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-bold.eot
--------------------------------------------------------------------------------
/public/static/fonts/rubis-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-bold.ttf
--------------------------------------------------------------------------------
/public/static/fonts/rubis-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-bold.woff
--------------------------------------------------------------------------------
/public/static/fonts/rubis-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-bold.woff2
--------------------------------------------------------------------------------
/public/static/fonts/rubis-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-regular.eot
--------------------------------------------------------------------------------
/public/static/fonts/rubis-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-regular.ttf
--------------------------------------------------------------------------------
/public/static/fonts/rubis-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-regular.woff
--------------------------------------------------------------------------------
/public/static/fonts/rubis-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/fonts/rubis-regular.woff2
--------------------------------------------------------------------------------
/public/static/geo/solar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/geo/solar.png
--------------------------------------------------------------------------------
/public/static/im-gespr-3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/im-gespr-3.gif
--------------------------------------------------------------------------------
/public/static/landscape.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/landscape.jpg
--------------------------------------------------------------------------------
/public/static/nl-chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/nl-chart.png
--------------------------------------------------------------------------------
/public/static/profilePicture1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/profilePicture1.png
--------------------------------------------------------------------------------
/public/static/profilePicture2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/profilePicture2.png
--------------------------------------------------------------------------------
/public/static/rothaus_landscape.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/rothaus_landscape.jpg
--------------------------------------------------------------------------------
/public/static/rothaus_portrait.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/rothaus_portrait.jpg
--------------------------------------------------------------------------------
/public/static/sample.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/sample.mp3
--------------------------------------------------------------------------------
/public/static/top-story-badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/top-story-badge.png
--------------------------------------------------------------------------------
/public/static/tweet_preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/tweet_preview.jpg
--------------------------------------------------------------------------------
/public/static/twitter_icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/twitter_icon.jpg
--------------------------------------------------------------------------------
/public/static/video.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbiting/styleguide/c45510fba197fbc4f103184bbf060ab6ff2269be/public/static/video.jpg
--------------------------------------------------------------------------------
/scripts/renderNewsletter.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // Usage
4 | // cd ~/Code/styleguide
5 | // cat ~/Articles/newsletter-editorial-x/article.md | scripts/renderNewsletter.js > ~/Desktop/email.html
6 |
7 | require('dotenv').config()
8 |
9 | const { renderEmail } = require('mdast-react-render/lib/email')
10 | const { parse } = require('@orbiting/remark-preset')
11 | const rw = require('rw')
12 | const editorialNewsletterSchema = require('../lib/templates/EditorialNewsletter/email').default()
13 |
14 | const mdast = parse(rw.readFileSync('/dev/stdin', 'utf8'))
15 |
16 | rw.writeFileSync(
17 | '/dev/stdout',
18 | renderEmail(mdast, editorialNewsletterSchema),
19 | 'utf8'
20 | )
21 |
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 | ../README.md
--------------------------------------------------------------------------------
/src/catalogTheme.css:
--------------------------------------------------------------------------------
1 | /* tmp hack */
2 | svg g[fill="#FFFFFF"] {
3 | fill: #000;
4 | }
5 |
6 | #root ul[class^="catalog"][class*="ul-Styled"] ul[class^="catalog"][class*="ul-Styled"] {
7 | margin-top: 0 !important;
8 | font-size: 18px;
9 | }
10 |
11 | /* code area of catalog */
12 | pre.css-o6vvb1, pre.css-1xyfnhc {
13 | max-height: 60vh;
14 | overflow: auto;
15 | }
16 |
17 | .dark-mode svg g[fill="#FFFFFF"] {
18 | fill: #fff;
19 | }
20 |
21 | .dark-mode code, .dark-mode section, .dark-mode section > div:nth-child(2), .dark-mode section > div:nth-child(3) {
22 | border-color: #4C4D4C !important;
23 | border-radius: 0 !important;
24 | }
25 |
26 | .dark-mode pre {
27 | background: #191919 !important;
28 | }
29 |
30 | .dark-mode div.css-eplqeh, .dark-mode div.css-zty0sa {
31 | background: #1F1F1F !important;
32 | }
33 |
34 | .dark-mode div.css-invpxs {
35 | background: #292929 !important;
36 | }
37 |
38 | iframe.css-755oq1 {
39 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAAAAACoWZBhAAAAF0lEQVQI12P4BAI/QICBFCaYBPNJYQIAkUZftTbC4sIAAAAASUVORK5CYII=') !important;
40 | }
41 |
42 | [class*="ReactSpecimen"] {
43 | background-color: transparent !important;
44 | }
45 |
--------------------------------------------------------------------------------
/src/chart.ts:
--------------------------------------------------------------------------------
1 | export {
2 | default as Chart,
3 | ChartTitle,
4 | ChartLead,
5 | ChartLegend
6 | } from './components/Chart'
7 |
--------------------------------------------------------------------------------
/src/components/AudioPlayer/index.js:
--------------------------------------------------------------------------------
1 | export { default as AudioPlayer } from './Player'
2 |
--------------------------------------------------------------------------------
/src/components/BlockQuote/BlockQuote.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 |
5 | import { mUp } from '../../theme/mediaQueries'
6 |
7 | const styles = {
8 | container: css({
9 | margin: '30px auto',
10 | [mUp]: {
11 | margin: '40px auto'
12 | },
13 | '& figcaption': {
14 | marginLeft: 0,
15 | marginRight: 0
16 | }
17 | })
18 | }
19 |
20 | const BlockQuote = ({ children, attributes }) => {
21 | return (
22 |
23 | {children}
24 |
25 | )
26 | }
27 |
28 | BlockQuote.propTypes = {
29 | children: PropTypes.node.isRequired,
30 | attributes: PropTypes.object
31 | }
32 |
33 | export default BlockQuote
34 |
--------------------------------------------------------------------------------
/src/components/BlockQuote/BlockQuoteParagraph.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 |
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { fontRule } from '../Typography/Interaction'
7 | import { sansSerifRegular15, sansSerifRegular18 } from '../Typography/styles'
8 | import { convertStyleToRem } from '../Typography/utils'
9 | import { useColorContext } from '../Colors/useColorContext'
10 |
11 | const styles = {
12 | quote: css({
13 | margin: 0,
14 | padding: '0 15px 12px 15px',
15 | fontSize: '15px',
16 | ...convertStyleToRem(sansSerifRegular15),
17 | [mUp]: {
18 | ...convertStyleToRem(sansSerifRegular18),
19 | padding: '0 25px 20px 25px',
20 | '&:first-child': {
21 | paddingTop: '20px'
22 | }
23 | },
24 | '&:first-child': {
25 | paddingTop: '12px'
26 | }
27 | })
28 | }
29 |
30 | const BlockQuoteParagraph = ({ children, attributes }) => {
31 | const [colorScheme] = useColorContext()
32 | return (
33 |
40 | {children}
41 |
42 | )
43 | }
44 |
45 | BlockQuoteParagraph.propTypes = {
46 | children: PropTypes.node.isRequired,
47 | attributes: PropTypes.object
48 | }
49 |
50 | export default BlockQuoteParagraph
51 |
--------------------------------------------------------------------------------
/src/components/BlockQuote/docs.md:
--------------------------------------------------------------------------------
1 | ### ` `
2 |
3 | A ` ` can contain an arbitrary number of ` `.
4 |
5 | Optionally you can provide a ` ` to describe the quote source.
6 |
7 |
8 | ```react|responsive
9 |
10 |
11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin auctor felis tortor, at cursus metus interdum nec. Praesent tristique ante ut est ultrices, sed condimentum ipsum ullamcorper. Ut tempus vulputate cursus. Cras vitae varius sem. Fusce quis diam odio. Suspendisse ultrices est orci, quis ornare risus tempus ut. Morbi quis orci faucibus, aliquam nisl quis, pellentesque magna. Curabitur pellentesque nisi id ultricies efficitur. Cras facilisis volutpat purus eu viverra.
12 |
13 |
14 | Nunc a eleifend nulla, non condimentum felis. Vestibulum eu efficitur ex. Nunc egestas ullamcorper euismod. In odio nulla, posuere gravida faucibus et, rhoncus non purus. Cras eget justo sed dolor auctor suscipit. Quisque consequat tempus nisl. Curabitur a metus id mi varius vulputate. Nulla quis diam vitae elit scelerisque dapibus. Aliquam tincidunt sem nec nulla semper pulvinar. In posuere accumsan nunc vitae lacinia. Praesent et mollis elit. Proin quis massa feugiat augue dapibus convallis. Mauris sollicitudin libero non varius varius.
15 |
16 |
17 | Dummy Text{' '}
18 | lipsum.org
19 |
20 |
21 | ```
22 |
--------------------------------------------------------------------------------
/src/components/BlockQuote/index.js:
--------------------------------------------------------------------------------
1 | export { default as BlockQuote } from './BlockQuote'
2 | export { default as BlockQuoteParagraph } from './BlockQuoteParagraph'
3 |
--------------------------------------------------------------------------------
/src/components/Callout/docs.md:
--------------------------------------------------------------------------------
1 | ## Callout
2 |
3 | A fixed callout animating in from the bottom on mobile and a in place callout on desktop.
4 |
5 | - `initiallyOpen`: boolean, note: after a click outside of it, it hides again
6 | - `icon`: React element
7 | - `align`: `left` (default) or `right`, alignment on desktop
8 | - `contentPaddingMobile`: set padding of callout content. (Defaults to "safari safe": `'15px 15px 50px'`).
9 |
10 | ```react|responsive
11 |
12 | } initiallyOpen contentPadding={16}>
13 | Hello World
14 |
15 |
16 | ```
17 |
18 | ### Right Aligned
19 |
20 | ```react
21 |
22 |
23 | } align='right' initiallyOpen>
24 | Hello World
25 |
26 |
27 |
28 | ```
29 |
--------------------------------------------------------------------------------
/src/components/Chart/ChartContext.utils.js:
--------------------------------------------------------------------------------
1 | import { isValuePresent, unsafeDatumFn } from './utils'
2 |
3 | export const normalizeData = (x, xNormalizer) => d => ({
4 | datum: d,
5 | x: xNormalizer(d[x]),
6 | value: isValuePresent(d.value) ? +d.value : undefined
7 | })
8 |
9 | export const getAnnotationsXValues = (annotations, xNormalizer) =>
10 | annotations
11 | ? annotations
12 | .reduce(
13 | (years, annotation) =>
14 | years.concat(annotation.x, annotation.x1, annotation.x2),
15 | []
16 | )
17 | .filter(Boolean)
18 | .map(xNormalizer) // ensure format
19 | : []
20 |
21 | export const categorizeData = category => d => {
22 | if (category) {
23 | const categorize = unsafeDatumFn(category)
24 | return {
25 | ...d,
26 | category: categorize(d.datum)
27 | }
28 | }
29 | return d
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/Chart/Csv.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Chart from './'
3 | import { csvParse } from 'd3-dsv'
4 |
5 | export default ({ values, ...rest }) => (
6 |
7 | )
8 |
--------------------------------------------------------------------------------
/src/components/Chart/Editor/AxisFormatDropdown.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomValueDropdown from './CustomValueDropdown'
3 |
4 | import { numberFormats, timeFormats, timeParsing } from './utils'
5 |
6 | export const AxisFormatDropdown = props => {
7 | const {
8 | property,
9 | context,
10 | value,
11 | onChange,
12 | timeParse,
13 | xNumberFormat,
14 | parent,
15 | defaultProps
16 | } = props
17 | if (context === 'time') {
18 | return (
19 | <>
20 |
26 |
32 | >
33 | )
34 | }
35 | if (context === 'number') {
36 | const isOnXAxis = parent.match(/^x/)
37 | return (
38 |
44 | )
45 | }
46 | return null
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/Chart/Editor/ColorDropdownElement.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontStyles } from '../../Typography'
3 |
4 | export const ColorDropdownElement = props => {
5 | const { colorRange, name } = props
6 | return (
7 |
8 |
9 | {name}
10 |
11 |
12 | {colorRange.map((d, i) => (
13 |
21 | ))}
22 |
23 |
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/Chart/Editor/ColorPickerCallout.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BlockPicker as ColorPicker } from 'react-color'
3 | import { plainButtonRule } from '../../Button'
4 | import CalloutMenu from '../../Callout/CalloutMenu'
5 | import {
6 | useColorContext
7 | } from '../../Colors/ColorContext'
8 |
9 | const ColorPickerCallout = ({ mode, pickableColors, color, onChange }) => {
10 | const [colorScheme] = useColorContext()
11 |
12 | return (
13 |
21 | (
23 |
34 | )}
35 | align='right'
36 | >
37 |
43 |
44 |
45 | )
46 | }
47 |
48 | export default ColorPickerCallout
49 |
--------------------------------------------------------------------------------
/src/components/Chart/Editor/CustomValueDropdown.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Dropdown from '../../Form/Dropdown'
3 |
4 | const CustomValueDropdown = ({ value, items, ...props }) => {
5 | const itemsHasValue = items.find(item => item.value === value)
6 | const itemsWithValue = itemsHasValue
7 | ? items
8 | : items.concat({
9 | value,
10 | text: `Spezial: ${value}`
11 | })
12 |
13 | return
18 | }
19 |
20 | export default CustomValueDropdown
21 |
--------------------------------------------------------------------------------
/src/components/Chart/Editor/TickField.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import Field from '../../Form/Field'
4 | import { useCommaField } from './utils'
5 | import { timeParse } from '../../../lib/timeFormat'
6 |
7 | export const TickField = props => {
8 | const {
9 | property,
10 | groupObject,
11 | createOnFieldChange,
12 | value,
13 | config,
14 | context,
15 | timeParseDefault
16 | } = props
17 |
18 | const timeFormatParser = timeParse(
19 | config.timeParse || config.timeFormat || timeParseDefault
20 | )
21 |
22 | const parser =
23 | context === 'time'
24 | ? timeFormatParser
25 | : context === 'number'
26 | ? d => +d
27 | : undefined
28 |
29 | const [ticksField, onTicksChange] = useCommaField(
30 | value,
31 | createOnFieldChange(property),
32 | parser,
33 | context
34 | )
35 |
36 | return (
37 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/Chart/Editor/docs.data.js:
--------------------------------------------------------------------------------
1 | export const chartData = `
2 | facet,facet_value,year,value,confidence95_lower,confidence95_upper
3 | Altersgruppen,unter 10 Jahre,2014,0.219,0.207,0.232
4 | Altersgruppen,10-17 Jahre,2014,0.201,0.183,0.219
5 | Altersgruppen,18-24 Jahre,2014,0.243,0.194,0.292
6 | Altersgruppen,25-34 Jahre,2014,0.208,0.189,0.226
7 | Altersgruppen,35-44 Jahre,2014,0.128,0.113,0.144
8 | Altersgruppen,45-54 Jahre,2014,0.106,0.083,0.130
9 | Altersgruppen,55-64 Jahre,2014,0.132,0.112,0.151
10 | Altersgruppen,65-74 Jahre,2014,0.141,0.110,0.171
11 | Altersgruppen,über 74 Jahre,2014,0.133,0.120,0.146`.trim()
12 |
--------------------------------------------------------------------------------
/src/components/Chart/Editor/docs.md:
--------------------------------------------------------------------------------
1 | ```react
2 | state: {
3 | type: 'TimeBar',
4 | activeTab: 'basic',
5 | tabs: [
6 | { value: 'basic', text: 'Grundeinstellungen' },
7 | {
8 | value: 'advanced',
9 | text: 'Erweiterte Optionen'
10 | }
11 | ]
12 | }
13 | ---
14 |
15 | value === state.activeTab)}>
16 | {state.tabs.map(({ value, text }) => (
17 | {
22 | setState({ activeTab: value })
23 | }}
24 | />
25 | ))}
26 |
27 |
28 |
33 |
37 |
40 |
41 |
42 | ```
43 |
--------------------------------------------------------------------------------
/src/components/Chart/Hemicycle.schema.js:
--------------------------------------------------------------------------------
1 | export const hemicycleEditorSchema = ({
2 | optionalDataColumnEnum,
3 | defaults,
4 | colorDropdownItems,
5 | chartSizes
6 | }) => {
7 | return {
8 | defaultProps: defaults,
9 | properties: {
10 | basic: {
11 | color: {
12 | title: 'Farbe',
13 | properties: {
14 | color: {
15 | title: 'Spalte auswählen',
16 | type: 'string',
17 | enum: optionalDataColumnEnum
18 | },
19 | colorRange: {
20 | title: 'Farbschema auswählen',
21 | type: 'string',
22 | enum: colorDropdownItems
23 | }
24 | }
25 | }
26 | },
27 | advanced: {
28 | layout: {
29 | title: 'Layout',
30 | properties: {
31 | size: {
32 | title: 'Darstellung im Beitrag',
33 | type: 'string',
34 | enum: chartSizes
35 | }
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Chart/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Bundesregierung
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/src/components/Chart/Layout.constants.js:
--------------------------------------------------------------------------------
1 | export const COLUMN_TITLE_HEIGHT = 24
2 | export const COLUMN_PADDING = 20
3 |
4 | export const AXIS_TOP_HEIGHT = 24
5 | export const AXIS_BOTTOM_HEIGHT = 24
6 | export const X_UNIT_PADDING = 30
7 | export const AXIS_BOTTOM_CUTOFF_HEIGHT = 40
8 | export const AXIS_BOTTOM_XUNIT_HEIGHT = 12
9 |
10 | export const PADDING_TOP = 24
11 | export const PADDING_SIDES = 20
12 |
13 | export const Y_CONNECTOR = 7
14 | export const Y_CONNECTOR_PADDING = 4
15 | export const Y_LABEL_HEIGHT = 14
16 | export const Y_END_LABEL_SPACE = 3 // width of space between label and value
17 | export const X_TICK_HEIGHT = 4
18 | export const Y_GROUP_MARGIN = 20
19 |
--------------------------------------------------------------------------------
/src/components/Chart/ScatterPlotCanvas.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useEffect } from 'react'
2 |
3 | const ScatterPlotCanvas = ({ symbols, width, height, getColor, opacity }) => {
4 | const canvasRef = useRef()
5 |
6 | useEffect(() => {
7 | const canvas = canvasRef.current
8 |
9 | const devicePixelRatio = window.devicePixelRatio || 1
10 | canvas.width = width * devicePixelRatio
11 | canvas.height = height * devicePixelRatio
12 |
13 | const ctx = canvas.getContext('2d')
14 | ctx.save()
15 | ctx.scale(devicePixelRatio, devicePixelRatio)
16 | ctx.clearRect(0, 0, width, height)
17 |
18 | ctx.globalAlpha = opacity
19 | symbols.forEach(({ cx, cy, r, value }) => {
20 | ctx.beginPath()
21 | ctx.moveTo(cx + r, cy)
22 | ctx.arc(cx, cy, r, 0, 2 * Math.PI)
23 |
24 | ctx.fillStyle = getColor(value)
25 | ctx.fill()
26 | })
27 |
28 | ctx.restore()
29 | }, [symbols, width, height, opacity, getColor])
30 |
31 | return (
32 |
42 | )
43 | }
44 |
45 | export default ScatterPlotCanvas
46 |
--------------------------------------------------------------------------------
/src/components/Chart/ScatterPlots.schema.js:
--------------------------------------------------------------------------------
1 | export const scatterPlotEditorSchema = ({
2 | optionalDataColumnEnum,
3 | defaults,
4 | colorDropdownItems,
5 | chartSizes,
6 | columnAmount
7 | }) => {
8 | return {
9 | defaultProps: defaults,
10 | properties: {
11 | basic: {
12 | color: {
13 | title: 'Farbe',
14 | properties: {
15 | color: {
16 | title: 'Spalte auswählen',
17 | type: 'string',
18 | enum: optionalDataColumnEnum
19 | },
20 | colorRange: {
21 | title: 'Farbschema auswählen',
22 | type: 'string',
23 | enum: colorDropdownItems
24 | }
25 | }
26 | },
27 | layout: {
28 | title: 'Aufteilen in mehrere Charts',
29 | properties: {
30 | column: {
31 | title: 'Spalte auswählen',
32 | type: 'string',
33 | enum: optionalDataColumnEnum
34 | },
35 | columns: {
36 | title: 'Anzahl Spalten pro Zeile',
37 | type: 'number',
38 | enum: columnAmount
39 | }
40 | }
41 | }
42 | },
43 | advanced: {
44 | layout: {
45 | title: 'Layout',
46 | properties: {
47 | size: {
48 | title: 'Darstellung im Beitrag',
49 | type: 'string',
50 | enum: chartSizes
51 | }
52 | }
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/Chart/ScatterPlots.utils.js:
--------------------------------------------------------------------------------
1 | import { extent } from 'd3-array'
2 | import { scaleLinear, scaleLog } from 'd3-scale'
3 |
4 | export const scales = {
5 | linear: scaleLinear,
6 | log: scaleLog
7 | }
8 |
9 | export const tickAccessor = d => d.tick
10 |
11 | export const aggregateValues = (data, accessor, xTicks = [], xLines = []) =>
12 | data
13 | .map(accessor)
14 | .concat(xTicks)
15 | .concat(xLines.map(tickAccessor))
16 |
17 | const getNice = (nice, plotDimension) =>
18 | nice === undefined
19 | ? Math.min(Math.max(Math.round(plotDimension / 150), 3), 5)
20 | : nice
21 |
22 | export const getPlot = (scale, values, range, nice, plotDimension) => {
23 | const plotScale = scales[scale]()
24 | .domain(extent(values))
25 | .range(range)
26 | const niceValue = getNice(nice, plotDimension)
27 | if (niceValue) {
28 | plotScale.nice(niceValue)
29 | }
30 | return plotScale
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/Chart/Table.schema.js:
--------------------------------------------------------------------------------
1 | export const tableEditorSchema = ({ defaults, chartSizes }) => {
2 | return {
3 | defaultProps: defaults,
4 | properties: {
5 | basic: {},
6 | advanced: {
7 | layout: {
8 | title: 'Layout',
9 | properties: {
10 | size: {
11 | title: 'Darstellung im Beitrag',
12 | type: 'string',
13 | enum: chartSizes
14 | }
15 | }
16 | }
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/Collapsable/index.js:
--------------------------------------------------------------------------------
1 | export { default as Collapsable } from './Collapsable'
2 |
--------------------------------------------------------------------------------
/src/components/Colors/useColorContext.js:
--------------------------------------------------------------------------------
1 | export { useColorContext } from './ColorContext'
2 |
--------------------------------------------------------------------------------
/src/components/CommentBody/email/BlockCode.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { fontFamilies } from '../../../theme/fonts'
4 |
5 | export default ({ children }) => (
6 |
7 |
17 | {children}
18 |
19 |
20 | )
21 |
--------------------------------------------------------------------------------
/src/components/CommentBody/email/Blockquote.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import colors from '../../../theme/colors'
4 | import { paragraphStyle } from './Paragraph'
5 |
6 | export const BlockQuoteParagraph = ({ children }) => (
7 |
14 | {children}
15 |
16 | )
17 |
18 | export const BlockQuoteNested = ({ children }) => (
19 |
27 | {children}
28 |
29 | )
30 |
31 | export default ({ children }) => (
32 |
39 | {children}
40 |
41 | )
42 |
--------------------------------------------------------------------------------
/src/components/CommentBody/email/Container.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { serifRegular16 } from '../../Typography/styles'
4 |
5 | // em and strong css is injected into email html head in the backend template
6 | // https://github.com/orbiting/backends/commit/ff8b6b35927f6a3402baec7f293ec7cdb25a90d8
7 |
8 | export default ({ children }) => {children}
9 |
--------------------------------------------------------------------------------
/src/components/CommentBody/email/List.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { paragraphStyle } from './Paragraph'
4 |
5 | const listStyle = {
6 | marginLeft: '1em',
7 | paddingLeft: '1em'
8 | }
9 |
10 | export const ListItem = ({ children }) => (
11 | {children}
12 | )
13 |
14 | export default ({ children, data }) =>
15 | data.ordered ? (
16 |
17 | {children}
18 |
19 | ) : (
20 |
21 | )
22 |
--------------------------------------------------------------------------------
/src/components/CommentBody/email/index.js:
--------------------------------------------------------------------------------
1 | export { default as BlockCode } from './BlockCode'
2 |
3 | export {
4 | default as BlockQuote,
5 | BlockQuoteNested,
6 | BlockQuoteParagraph
7 | } from './Blockquote'
8 |
9 | export { default as Container } from './Container'
10 |
11 | export { default as List, ListItem } from './List'
12 |
13 | export {
14 | Paragraph,
15 | Code,
16 | Definition,
17 | Heading,
18 | Link,
19 | StrikeThrough
20 | } from './Paragraph'
21 |
--------------------------------------------------------------------------------
/src/components/CommentBody/web/BlockCode.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 |
4 | import { mUp } from '../../../theme/mediaQueries'
5 | import { useColorContext } from '../../Colors/useColorContext'
6 | const styles = {
7 | pre: css({
8 | margin: '20px auto',
9 | whiteSpace: 'pre-wrap'
10 | }),
11 | code: css({
12 | display: 'block',
13 | fontSize: '90%',
14 | margin: 0,
15 | padding: '0 15px 12px 15px',
16 | [mUp]: {
17 | padding: '0 25px 20px 25px',
18 | '&:first-child': {
19 | paddingTop: '20px'
20 | }
21 | },
22 | '&:first-child': {
23 | paddingTop: '12px'
24 | }
25 | })
26 | }
27 |
28 | export default ({ children }) => {
29 | const [colorScheme] = useColorContext()
30 | return (
31 |
32 |
33 | {children}
34 |
35 |
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/CommentBody/web/Container.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 |
4 | import { mUp } from '../../../theme/mediaQueries'
5 | import { serifRegular14, serifRegular16 } from '../../Typography/styles'
6 | import { Editorial } from '../../Typography'
7 | import { convertStyleToRem } from '../../Typography/utils'
8 |
9 | const styles = {
10 | container: css({
11 | wordWrap: 'break-word',
12 | ...convertStyleToRem(serifRegular14),
13 | [mUp]: {
14 | ...convertStyleToRem(serifRegular16)
15 | },
16 | '& > *:first-child': {
17 | marginTop: 0
18 | },
19 | '& > *:last-child': {
20 | marginBottom: 0
21 | }
22 | })
23 | }
24 |
25 | export default ({ children }) => (
26 |
27 | {children}
28 |
29 | )
30 |
--------------------------------------------------------------------------------
/src/components/CommentBody/web/List.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { List, ListItem as CommentListItem } from '../../List'
4 |
5 | export const ListItem = ({ children }) => (
6 |
12 | {children}
13 |
14 | )
15 |
16 | export default List
17 |
--------------------------------------------------------------------------------
/src/components/CommentBody/web/index.js:
--------------------------------------------------------------------------------
1 | export { default as CommentBodyBlockCode } from './BlockCode'
2 |
3 | export {
4 | default as CommentBodyBlockQuote,
5 | BlockQuoteNested as CommentBodyBlockQuoteNested,
6 | BlockQuoteParagraph as CommentBodyBlockQuoteParagraph
7 | } from './Blockquote'
8 |
9 | export { default as CommentBodyContainer } from './Container'
10 |
11 | export {
12 | default as CommentBodyList,
13 | ListItem as CommentBodyListItem
14 | } from './List'
15 |
16 | export {
17 | default as CommentBodyParagraph,
18 | Code as CommentBodyCode,
19 | Definition as CommentBodyDefinition,
20 | Heading as CommentBodyHeading,
21 | FeaturedText as CommentBodyFeaturedText
22 | } from './Paragraph'
23 |
--------------------------------------------------------------------------------
/src/components/CommentTeaser/docs.imports.js:
--------------------------------------------------------------------------------
1 | export { default as CommentTeaser } from './CommentTeaser'
2 |
--------------------------------------------------------------------------------
/src/components/CommentTeaser/index.js:
--------------------------------------------------------------------------------
1 | export { default as CommentTeaser } from './CommentTeaser'
2 |
--------------------------------------------------------------------------------
/src/components/Discussion/Composer/docs.md:
--------------------------------------------------------------------------------
1 | ```remove-react-source
2 | ```
3 |
4 | ## ``
5 |
6 | The `` is a stateful component which manages the input text and selected tag. The following callbacks are used to communicate with its controller:
7 |
8 | * `onClose(): void`
9 | * `onSubmit({ text: string, tags?: string[] }): Promise<{}>`
10 | * `onEditPreferences(): void`
11 |
12 | The `onSubmit()` function must return a Promise which is resolved when the backend accepts the comment, or is rejected with a string that describes the error. The error will then be shown below the form, the user can further edit the comment and try to submit again.
13 |
14 | ```react|noSource,plain
15 |
16 | ```
17 |
18 | ## ``
19 |
20 | Same height as the `` in the `` so that it can be used in its place and we can have a nice transition between the placeholder and the whole `` component.
21 |
22 | ```react|noSource,plain
23 | {}}
27 | />
28 | ```
29 |
--------------------------------------------------------------------------------
/src/components/Discussion/Composer/index.js:
--------------------------------------------------------------------------------
1 | export * from './CommentComposer'
2 | export * from './CommentComposerPlaceholder'
3 |
4 | // To allow CommentHeader preview
5 | export { CommentHeaderProfile } from '../Internal/Composer/Header'
6 |
7 | export { readDraft as readDiscussionCommentDraft } from './CommentDraftHelper'
8 |
--------------------------------------------------------------------------------
/src/components/Discussion/Internal/Comment/RelativeTime.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { useCurrentMinute } from '../../../../lib/useCurrentMinute'
4 | import { formatTimeRelative } from '../../DiscussionContext'
5 |
6 | const RelativeTime = ({ date, t, isDesktop, direction = 'past' }) => {
7 | const now = useCurrentMinute()
8 |
9 | return (
10 |
11 | {formatTimeRelative(new Date(date), {
12 | t,
13 | isDesktop,
14 | now,
15 | direction
16 | })}
17 |
18 | )
19 | }
20 |
21 | export default RelativeTime
22 |
--------------------------------------------------------------------------------
/src/components/Discussion/Internal/Comment/index.js:
--------------------------------------------------------------------------------
1 | export * from './CommentActions'
2 | export * from './Body'
3 | export * from './Context'
4 | export * from './Header'
5 | export * from './IconLink'
6 | export * from './CommentEmbed'
7 | export * from './VoteButtons'
8 |
--------------------------------------------------------------------------------
/src/components/Discussion/Internal/Comment/render.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { renderMdast } from 'mdast-react-render'
3 | import createCommentSchema from '../../../../templates/Comment'
4 | import { useColorContext } from '../../../Colors/useColorContext'
5 |
6 | const schema = createCommentSchema()
7 |
8 | const MissingNode = ({ node, children }) => {
9 | const [colorScheme] = useColorContext()
10 | return (
11 |
21 | {children || node.value || node.identifier || '[…]'}
22 |
23 | )
24 | }
25 |
26 | export const renderCommentMdast = content =>
27 | renderMdast(content, schema, { MissingNode })
28 |
--------------------------------------------------------------------------------
/src/components/Discussion/Internal/Composer/Error.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import { sansSerifRegular16 } from '../../../Typography/styles'
4 | import { convertStyleToRem } from '../../../Typography/utils'
5 | import { useColorContext } from '../../../Colors/useColorContext'
6 |
7 | const styles = {
8 | root: css({
9 | ...convertStyleToRem(sansSerifRegular16),
10 | marginTop: 12
11 | })
12 | }
13 |
14 | export const Error = ({ children }) => {
15 | const [colorScheme] = useColorContext()
16 | return (
17 |
18 | {children}
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/Discussion/Internal/Composer/Tags.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import Radio from '../../../Form/Radio'
5 | import { mUp } from '../../../../theme/mediaQueries'
6 |
7 | const styles = {
8 | root: css({
9 | padding: '12px',
10 | display: 'flex',
11 | flexDirection: 'column',
12 | flexWrap: 'wrap',
13 | [mUp]: {
14 | flexDirection: 'row'
15 | }
16 | }),
17 | tag: css({
18 | marginRight: 24,
19 | '& ~ &': {
20 | marginTop: 5
21 | },
22 | [mUp]: {
23 | '& ~ &': {
24 | marginTop: 0
25 | }
26 | }
27 | })
28 | }
29 |
30 | export const Tags = ({ tags, value, onChange }) => {
31 | if (!tags || tags.length === 0) {
32 | return null
33 | } else {
34 | return (
35 |
36 | {tags.map(tag => (
37 |
38 | onChange(event.target.value)}
42 | >
43 | {tag}
44 |
45 |
46 | ))}
47 |
48 | )
49 | }
50 | }
51 |
52 | Tags.propTypes = {
53 | tags: PropTypes.arrayOf(PropTypes.string),
54 | value: PropTypes.string,
55 | onChange: PropTypes.func.isRequired
56 | }
57 |
--------------------------------------------------------------------------------
/src/components/Discussion/Internal/Composer/index.js:
--------------------------------------------------------------------------------
1 | export * from './Actions'
2 | export * from './Error'
3 | export * from './Header'
4 | export * from './Tags'
5 |
--------------------------------------------------------------------------------
/src/components/Discussion/Internal/PropTypes.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 |
3 | export const DisplayAuthorPropType = PropTypes.shape({
4 | name: PropTypes.string.isRequired,
5 | profilePicture: PropTypes.string,
6 | credential: PropTypes.shape({
7 | description: PropTypes.string.isRequired,
8 | verified: PropTypes.bool
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/src/components/Discussion/Statements/helpers/ColorContextHelper.js:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react'
2 | import { getUniqueColorTagName } from './colorHelper'
3 | import {
4 | ColorContextLocalExtension,
5 | ColorContextProvider
6 | } from '../../../Colors/ColorContext'
7 |
8 | const ColorContextHelper = ({ children, tagMappings = [] }) => {
9 | const localColors = useMemo(() => {
10 | if (!tagMappings.length > 0) return null
11 |
12 | const colorsObject = { light: {}, dark: {} }
13 |
14 | if (!tagMappings) return colorsObject
15 |
16 | tagMappings.forEach(({ tag, color }) => {
17 | const colorName = getUniqueColorTagName(tag)
18 | colorsObject.light[colorName] = color.light
19 | colorsObject.dark[colorName] = color.dark
20 | })
21 |
22 | return colorsObject
23 | }, [tagMappings])
24 |
25 | if (!localColors) return children
26 |
27 | return (
28 |
29 |
30 | {children}
31 |
32 |
33 | )
34 | }
35 |
36 | export default ColorContextHelper
37 |
--------------------------------------------------------------------------------
/src/components/Discussion/Statements/helpers/colorHelper.js:
--------------------------------------------------------------------------------
1 | import { stripTag } from './tagHelper'
2 |
3 | export function getUniqueColorTagName(tagName) {
4 | return `tag-${stripTag(tagName)}-color`
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/Discussion/Statements/helpers/tagHelper.js:
--------------------------------------------------------------------------------
1 | export function stripTag(tag) {
2 | return tag.toLowerCase().trim()
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/Discussion/Statements/index.js:
--------------------------------------------------------------------------------
1 | import StatementNode from './StatementNode'
2 |
3 | export { StatementNode }
4 |
--------------------------------------------------------------------------------
/src/components/Discussion/Tree/BoardComment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import CommentNode, { CommentProps } from './CommentNode'
4 | import { CommentEmbed } from '../Internal/Comment'
5 | import { mUp } from '../../../theme/mediaQueries'
6 |
7 | const styles = {
8 | wrapper: css({
9 | marginTop: 10,
10 | marginBottom: 50,
11 | [mUp]: {
12 | display: 'flex',
13 | marginLeft: -10,
14 | marginRight: -10
15 | }
16 | }),
17 | item: css({
18 | [mUp]: {
19 | padding: 10,
20 | width: '50%',
21 | flex: '1 0 auto'
22 | }
23 | })
24 | }
25 |
26 |
27 | const BoardComment = (props: CommentProps) => (
28 |
29 |
30 |
31 |
32 | {props.comment?.embed && (
33 |
34 |
35 |
36 | )}
37 |
38 | )
39 |
40 | export default BoardComment
41 |
--------------------------------------------------------------------------------
/src/components/Discussion/Tree/docs.imports.js:
--------------------------------------------------------------------------------
1 | import * as allComments from '../__docs__/comments'
2 |
3 | export const comments = { ...allComments }
4 |
--------------------------------------------------------------------------------
/src/components/Discussion/Tree/index.ts:
--------------------------------------------------------------------------------
1 | export { default as CommentNode } from "./CommentNode";
2 | export type { CommentProps } from './CommentNode'
3 | export { default as BoardComment } from './BoardComment'
4 |
--------------------------------------------------------------------------------
/src/components/Discussion/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The size of each indent. Note that this is the total size including
3 | * the width of the vertical line.
4 | */
5 | export const indentSizeS = 10
6 | export const indentSizeM = 16
7 |
8 | /**
9 | * The width of the vertical line.
10 | */
11 | export const verticalLineWidth = 2
12 |
13 | /**
14 | * Limit how deep we nest comments using the standard layout/visual style.
15 | * Comments nested deeper than that are displayed differently.
16 | */
17 | export const nestLimit = 4
18 |
--------------------------------------------------------------------------------
/src/components/Discussion/docs.md:
--------------------------------------------------------------------------------
1 | We use React Context to make static properties and discussion-wide callbacks available to components. So make sure to wrap the components in `` before you render ``
2 |
3 | ```code|lang-js
4 |
5 |
6 |
7 | ```
8 |
9 | ### Configuration
10 |
11 | Some config options are stored in `src/components/Discussion/config.js`. If you need to tweak the layout, first have a look there if there is already an option for it.
12 |
13 | ### Exports
14 |
15 | The following symbols are exported from the styleguide:
16 |
17 | * `DiscussionContext`
18 | * ``
19 | * ``
20 | * ``
--------------------------------------------------------------------------------
/src/components/Dossier/Headline.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import { mUp } from '../TeaserFront/mediaQueries'
4 | import { serifTitle38, serifTitle58 } from '../Typography/styles'
5 |
6 | const styles = {
7 | base: css({
8 | margin: 0,
9 | ...serifTitle38,
10 | marginBottom: '25px',
11 | [mUp]: {
12 | ...serifTitle58,
13 | marginBottom: '35px'
14 | }
15 | })
16 | }
17 |
18 | const Headline = ({ children, poster, large, medium }) => {
19 | return (
20 |
21 | {children}
22 |
23 | )
24 | }
25 |
26 | export default Headline
27 |
--------------------------------------------------------------------------------
/src/components/Dossier/Lead.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import { mUp } from '../TeaserFront/mediaQueries'
5 | import { serifRegular17, serifRegular23 } from '../Typography/styles'
6 |
7 | const styles = {
8 | lead: css({
9 | ...serifRegular17,
10 | margin: '0 0 10px 0',
11 | [mUp]: {
12 | ...serifRegular23,
13 | margin: '0 0 20px 0'
14 | }
15 | })
16 | }
17 |
18 | const Lead = ({ children }) => {
19 | return {children}
20 | }
21 |
22 | Lead.propTypes = {
23 | children: PropTypes.node
24 | }
25 |
26 | export default Lead
27 |
--------------------------------------------------------------------------------
/src/components/Dossier/More.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import colors from '../../theme/colors'
4 | import { mUp } from '../TeaserFront/mediaQueries'
5 | import { sansSerifRegular15, sansSerifRegular21 } from '../Typography/styles'
6 |
7 | const styles = {
8 | more: css({
9 | ...sansSerifRegular15,
10 | margin: 0,
11 | minHeight: '15px',
12 | textAlign: 'center',
13 | [mUp]: {
14 | ...sansSerifRegular21
15 | },
16 | '& > a': {
17 | color: colors.text
18 | },
19 | '@media (hover)': {
20 | '& > a:hover': {
21 | color: colors.lightText
22 | }
23 | }
24 | })
25 | }
26 |
27 | const More = ({ children, attributes }) => {
28 | return (
29 |
30 | {children}
31 |
32 | )
33 | }
34 |
35 | export default More
36 |
--------------------------------------------------------------------------------
/src/components/Dossier/Subheader.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import { mUp } from '../TeaserFront/mediaQueries'
4 | import { sansSerifMedium16, sansSerifMedium20 } from '../Typography/styles'
5 | import { convertStyleToRem } from '../Typography/utils'
6 | import { useColorContext } from '../Colors/useColorContext'
7 |
8 | const styles = {
9 | subheader: css({
10 | ...convertStyleToRem(sansSerifMedium16),
11 | [mUp]: {
12 | ...convertStyleToRem(sansSerifMedium20)
13 | }
14 | }),
15 | spaced: css({
16 | width: '100%',
17 | margin: '70px 0 30px 0',
18 | textAlign: 'center',
19 | [mUp]: {
20 | margin: '100px 0 70px 0'
21 | }
22 | })
23 | }
24 |
25 | const Subheader = ({ children, singleColumn }) => {
26 | const [colorScheme] = useColorContext()
27 |
28 | return (
29 |
34 | {children}
35 |
36 | )
37 | }
38 |
39 | export default Subheader
40 |
--------------------------------------------------------------------------------
/src/components/Dossier/Tag.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import { mUp } from '../TeaserFront/mediaQueries'
4 | import { sansSerifMedium14, sansSerifMedium20 } from '../Typography/styles'
5 | import { FolderIcon } from '../Icons'
6 |
7 | const styles = {
8 | tag: css({
9 | display: 'inline-block',
10 | ...sansSerifMedium14,
11 | margin: '0 0 18px 0',
12 | [mUp]: {
13 | ...sansSerifMedium20,
14 | margin: '0 0 28px 0'
15 | }
16 | }),
17 | icon: css({
18 | marginRight: '8px'
19 | })
20 | }
21 |
22 | const Tag = ({ children, attributes }) => {
23 | return (
24 |
25 |
26 | {children}
27 |
28 | )
29 | }
30 |
31 | export default Tag
32 |
--------------------------------------------------------------------------------
/src/components/Dossier/Teaser.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import { mUp } from '../TeaserFront/mediaQueries'
5 |
6 | const styles = {
7 | container: css({
8 | backgroundColor: '#f5f5f5',
9 | position: 'relative',
10 | lineHeight: 0,
11 | margin: 0,
12 | padding: '30px 15px',
13 | [mUp]: {
14 | padding: '60px 0'
15 | }
16 | })
17 | }
18 |
19 | const Teaser = ({ children, attributes, onClick }) => {
20 | return (
21 |
29 | {children}
30 |
31 | )
32 | }
33 |
34 | Teaser.propTypes = {
35 | children: PropTypes.node.isRequired,
36 | attributes: PropTypes.object,
37 | onClick: PropTypes.func
38 | }
39 |
40 | Teaser.defaultProps = {}
41 |
42 | export default Teaser
43 |
--------------------------------------------------------------------------------
/src/components/Dossier/TileHeadline.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import { tUp } from '../TeaserFront/mediaQueries'
4 | import {
5 | serifTitle26,
6 | serifTitle32,
7 | cursiveTitle26,
8 | cursiveTitle32,
9 | sansSerifMedium26,
10 | sansSerifMedium32
11 | } from '../Typography/styles'
12 | import { convertStyleToRem } from '../Typography/utils'
13 |
14 | const styles = {
15 | base: css({
16 | margin: 0,
17 | marginBottom: '16px',
18 | [tUp]: {
19 | marginBottom: '25px'
20 | }
21 | }),
22 | editorial: css({
23 | ...convertStyleToRem(serifTitle26),
24 | [tUp]: {
25 | ...convertStyleToRem(serifTitle32)
26 | }
27 | }),
28 | interaction: css({
29 | ...convertStyleToRem(sansSerifMedium26),
30 | [tUp]: {
31 | ...convertStyleToRem(sansSerifMedium32)
32 | }
33 | }),
34 | scribble: css({
35 | ...convertStyleToRem(cursiveTitle26),
36 | [tUp]: {
37 | ...convertStyleToRem(cursiveTitle32)
38 | }
39 | })
40 | }
41 |
42 | export const Editorial = ({ children }) => {
43 | return (
44 |
45 | {children}
46 |
47 | )
48 | }
49 |
50 | export const Interaction = ({ children }) => {
51 | return (
52 |
53 | {children}
54 |
55 | )
56 | }
57 |
58 | export const Scribble = ({ children }) => {
59 | return (
60 |
61 | {children}
62 |
63 | )
64 | }
65 |
--------------------------------------------------------------------------------
/src/components/Dossier/index.js:
--------------------------------------------------------------------------------
1 | import * as _DossierTileHeadline from './TileHeadline'
2 |
3 | export const DossierTileHeadline = { ..._DossierTileHeadline }
4 |
5 | export { default as TeaserFrontDossier } from './Teaser'
6 | export { default as TeaserFrontDossierIntro } from './TeaserIntro'
7 | export { default as TeaserFrontDossierHeadline } from './Headline'
8 | export { default as TeaserFrontDossierLead } from './Lead'
9 | export { default as TeaserFrontDossierMore } from './More'
10 |
11 | export { default as DossierTag } from './Tag'
12 | export { default as DossierSubheader } from './Subheader'
13 |
--------------------------------------------------------------------------------
/src/components/ErrorBoundary/index.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent, Fragment } from 'react'
2 | import { P } from '../Typography/Interaction'
3 | import colors from '../../theme/colors'
4 |
5 | class ErrorBoundary extends PureComponent {
6 | constructor(...args) {
7 | super(...args)
8 |
9 | this.state = {}
10 | }
11 | componentDidCatch(error) {
12 | this.setState({ error })
13 | }
14 | render() {
15 | const { children, failureMessage, showException } = this.props
16 | const { error } = this.state
17 | if (error) {
18 | return (
19 |
20 |
21 | {failureMessage}
22 |
23 | {showException && (
24 |
25 | {error.toString()}
26 |
27 | )}
28 |
29 | )
30 | }
31 | return children
32 | }
33 | }
34 |
35 | export default ErrorBoundary
36 |
--------------------------------------------------------------------------------
/src/components/Figure/Caption.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { sansSerifRegular12, sansSerifRegular15 } from '../Typography/styles'
4 | import { css, merge } from 'glamor'
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { PADDING } from '../Center'
7 | import { convertStyleToRem, pxToRem } from '../Typography/utils'
8 | import { useColorContext } from '../Colors/useColorContext'
9 |
10 | const styles = {
11 | caption: css({
12 | margin: '5px auto 0 auto',
13 | width: '100%',
14 | maxWidth: `calc(100vw - ${PADDING * 2}px)`,
15 | ...convertStyleToRem(sansSerifRegular12),
16 | [mUp]: {
17 | ...convertStyleToRem(sansSerifRegular15),
18 | lineHeight: pxToRem('18px')
19 | }
20 | }),
21 | groupCaption: css({
22 | marginTop: -10,
23 | marginBottom: 15
24 | })
25 | }
26 |
27 | export const Caption = ({ children, attributes, groupCaption }) => {
28 | const [colorScheme] = useColorContext()
29 |
30 | return (
31 |
36 | {children}
37 |
38 | )
39 | }
40 |
41 | Caption.propTypes = {
42 | children: PropTypes.node.isRequired,
43 | attributes: PropTypes.object,
44 | groupCaption: PropTypes.bool
45 | }
46 |
47 | export default Caption
48 |
--------------------------------------------------------------------------------
/src/components/Figure/SwitchImage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useColorContext } from '../Colors/useColorContext'
3 |
4 | const SwitchImage = ({ src, srcSet, dark, alt, ...props }) => {
5 | const [colorScheme] = useColorContext()
6 |
7 | return (
8 | <>
9 |
16 | {dark && (
17 |
24 | )}
25 | >
26 | )
27 | }
28 |
29 | export default SwitchImage
30 |
--------------------------------------------------------------------------------
/src/components/Form/Dropdown.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | import NativeDropdown from './NativeDropdown'
5 | import VirtualDropdown from './VirtualDropdown'
6 |
7 | const getUseNative = () =>
8 | typeof navigator === 'undefined' ||
9 | /iPad|iPhone|iPod|android/i.test(navigator.userAgent)
10 |
11 | let defaultUseNative = true
12 |
13 | const Dropdown = (props: DropdownProps) => {
14 | const [useNative, setUseNative] = useState(defaultUseNative)
15 | useEffect(() => {
16 | defaultUseNative = getUseNative()
17 | setUseNative(defaultUseNative)
18 | }, [])
19 | return useNative ? (
20 |
21 | ) : (
22 |
23 | )
24 | }
25 |
26 | Dropdown.Native = NativeDropdown
27 | Dropdown.Virtual = VirtualDropdown
28 |
29 | type ItemType = {
30 | value: string
31 | text: string
32 | element?: React.ReactNode
33 | }
34 |
35 | export type DropdownProps = {
36 | label?: string
37 | items: ItemType[]
38 | value?: string
39 | onChange?: (item: ItemType) => void
40 | }
41 |
42 | export default Dropdown
43 |
--------------------------------------------------------------------------------
/src/components/Form/Field.docs.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const RefComponent = ({ children, ...props }) => {
4 | const ref = React.useRef()
5 |
6 | return children(ref)
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/Form/NativeDropdown.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Label } from './DropdownLabel'
3 | import { DropdownProps } from './Dropdown'
4 |
5 | const NativeDropdown = (props: DropdownProps) => {
6 | const { label, items, value, onChange } = props
7 | const [focus, setFocus] = useState(false)
8 | const selectedItem = items.find(item => item.value === value)
9 |
10 | return (
11 |
12 | {/* ensure the height for selected multiline values ( is absolute) */}
13 |
14 | {selectedItem ? selectedItem.element || selectedItem.text : ''}
15 |
16 | onChange(items.find(item => item.value === e.target.value)))
23 | }
24 | onFocus={() => {
25 | setFocus(true)
26 | }}
27 | onBlur={() => {
28 | setFocus(false)
29 | }}
30 | >
31 | {items.map((item, index) => (
32 |
33 | {item.text}
34 |
35 | ))}
36 |
37 |
38 | )
39 | }
40 |
41 | export default React.memo(NativeDropdown)
42 |
--------------------------------------------------------------------------------
/src/components/Form/Slider.docs.md:
--------------------------------------------------------------------------------
1 | ```react|plain
2 | state: {example1: 3}
3 | ---
4 |
5 | setState({example1})} />
11 |
12 | ```
13 |
14 | ```react|plain
15 |
16 | e.preventDefault()}
22 | title='I am inactive' />
23 |
24 | ```
25 |
26 | ```react|plain
27 | state: {example3: 1}
28 | ---
29 |
30 | setState({example3})} />
37 |
38 | ```
39 |
40 |
--------------------------------------------------------------------------------
/src/components/Form/constants.ts:
--------------------------------------------------------------------------------
1 | export const X_PADDING = 0
2 | export const Y_PADDING = 9
3 | export const BORDER_WIDTH = 1
4 | export const LINE_HEIGHT = 20
5 | export const FIELD_HEIGHT = 40
6 | export const LABEL_HEIGHT = 20
7 |
--------------------------------------------------------------------------------
/src/components/Format/Tag.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 |
5 | import {
6 | sansSerifMedium14,
7 | sansSerifMedium16,
8 | sansSerifMedium18,
9 | sansSerifMedium20
10 | } from '../Typography/styles'
11 | import { mUp } from '../../theme/mediaQueries'
12 | import { useColorContext } from '../Colors/useColorContext'
13 |
14 | const styles = {
15 | container: css({
16 | ...sansSerifMedium18,
17 | display: 'inline-block',
18 | padding: 0,
19 | margin: '0 10px 5px 0',
20 | [mUp]: {
21 | ...sansSerifMedium20,
22 | margin: '0 20px 5px 0'
23 | }
24 | }),
25 | count: css({
26 | ...sansSerifMedium14,
27 | marginLeft: 5,
28 | [mUp]: {
29 | ...sansSerifMedium16
30 | }
31 | })
32 | }
33 |
34 | const FormatTag = ({ label, count, color }) => {
35 | const [colorScheme] = useColorContext()
36 | return (
37 |
38 | {label}
39 | {count !== undefined && (
40 |
41 | {count}
42 |
43 | )}
44 |
45 | )
46 | }
47 |
48 | FormatTag.propTypes = {
49 | label: PropTypes.string.isRequired,
50 | count: PropTypes.number,
51 | color: PropTypes.string
52 | }
53 |
54 | export default FormatTag
55 |
--------------------------------------------------------------------------------
/src/components/Format/docs.md:
--------------------------------------------------------------------------------
1 | Props:
2 | - `label`: string, the label of the tag.
3 | - `count`: optional number, the count.
4 | - `color`: optional string, the color of the label.
5 |
6 | ```react
7 |
12 | ```
13 |
14 | ```react
15 |
19 | ```
20 |
21 | ```react
22 |
25 | ```
26 |
27 | ```react
28 |
29 |
34 |
39 |
44 |
49 |
54 |
55 | ```
56 |
--------------------------------------------------------------------------------
/src/components/Format/index.js:
--------------------------------------------------------------------------------
1 | export { default as FormatTag } from './Tag'
2 |
--------------------------------------------------------------------------------
/src/components/Grid/docs.md:
--------------------------------------------------------------------------------
1 | Containers define the max width and ensure a horizontal padding.
2 |
3 | ```react
4 |
5 |
6 |
7 | ```
8 |
9 | ```react
10 |
11 |
12 |
13 | ```
14 |
--------------------------------------------------------------------------------
/src/components/Grid/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 |
5 | export const GUTTER = 42
6 | export const CONTENT_PADDING = 15
7 |
8 | export const NARROW_CONTENT_MAX_WIDTH = 680
9 | export const CONTENT_MAX_WIDTH = 1230
10 |
11 | const styles = {
12 | container: css({
13 | boxSizing: 'border-box',
14 | width: '100%',
15 | padding: `0 ${CONTENT_PADDING}px`,
16 | maxWidth: CONTENT_MAX_WIDTH,
17 | marginLeft: 'auto',
18 | marginRight: 'auto'
19 | }),
20 | narrowContainer: css({
21 | boxSizing: 'border-box',
22 | width: '100%',
23 | padding: `0 ${CONTENT_PADDING}px`,
24 | maxWidth: NARROW_CONTENT_MAX_WIDTH,
25 | marginLeft: 'auto',
26 | marginRight: 'auto'
27 | })
28 | }
29 |
30 | export const Container = ({ children, ...props }) => (
31 |
32 | {children}
33 |
34 | )
35 |
36 | Container.propTypes = {
37 | children: PropTypes.node,
38 | className: PropTypes.any
39 | }
40 |
41 | export const NarrowContainer = ({ children, ...props }) => (
42 |
43 | {children}
44 |
45 | )
46 |
47 | NarrowContainer.propTypes = {
48 | children: PropTypes.node
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/IconButton/docs.md:
--------------------------------------------------------------------------------
1 | ## IconButton
2 |
3 | A clickable component that accepts icons and lables and renders them. If href is provided, the component renders an `` element, else it renders a ``.
4 |
5 | - `Icon`: A React icon component
6 | - `title`: Title (shown on hover)
7 | - `label`: Default label (optional)
8 | - `labelShort`: Label that is shown on mobile devices
9 | - `fill`: Fill for icon and text, default is *color.text*
10 | - `onClick`: onClick function. If either onClick or href are provided, the IconButton applies a hover style.
11 | - `href`: if href is provided, IconButton renders as ``
12 | - `target`: target for href
13 | - `children`: renders children after label
14 | - `style`: allows to overwrite styles on the top component
15 | - `size`: overwrite default size (24px)
16 |
17 | ```react|responsive
18 |
19 | alert("click")}
23 | />
24 |
29 |
35 |
36 | ```
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/BackIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const BackIcon = ({ fill, ...props }) => (
5 |
6 |
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/CustomIconBase.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useIconContext } from '../IconContext'
3 |
4 | export default ({
5 | size = '1em',
6 | viewBox = '0 0 24 24',
7 | children,
8 | ...props
9 | }) => {
10 | const iconContext = useIconContext()
11 | return (
12 |
19 | {children}
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/DiscussionIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const DiscussionIcon = ({ fill, ...props }) => (
5 |
6 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/FontSizeIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const FontSizeIcon = ({ fill, ...props }) => (
5 |
6 |
10 |
14 |
15 | )
16 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/MarkdownIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const MarkdownIcon = ({ fill, ...props }) => (
5 |
6 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/MdCheckCircleOutlined.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const ReadIcon = ({ fill, ...props }) => (
5 |
6 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/MdCheckSmall.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const CheckSmallIcon = ({ fill, ...props }) => (
5 |
6 |
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/MdInsertChartOutlined.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const ChartIcon = ({ fill, ...props }) => (
5 |
6 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/ShareIcon.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 | import { MdShare } from 'react-icons/md'
4 | let defaultIsGoogleOS = undefined
5 |
6 | export const ShareIcon = ({ fill, ...props }) => {
7 | const [isGoogleOS, setIsGoogleOS] = useState(defaultIsGoogleOS)
8 | useEffect(() => {
9 | if (isGoogleOS !== undefined) {
10 | return // prevent unnecessary set state / re-renders
11 | }
12 | // set default value for all subsequent renders, e.g. client side navigation
13 | defaultIsGoogleOS = !!window.navigator.userAgent.match(/Android|CrOS/)
14 | // re-render this component with certain value
15 | setIsGoogleOS(defaultIsGoogleOS)
16 | }, [isGoogleOS])
17 | if (isGoogleOS === undefined) {
18 | // empty placeholder, avoid flickering between icons on Android
19 | return
20 | } else if (isGoogleOS) {
21 | return
22 | } else {
23 | return (
24 |
25 |
29 |
30 | )
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/SubscriptIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const SubscriptIcon = ({ fill, ...props }) => (
5 |
6 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/Icons/CustomIcons/SuperscriptIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomIconBase from './CustomIconBase'
3 |
4 | export const SuperscriptIcon = ({ fill, ...props }) => (
5 |
6 |
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/src/components/Icons/IconContext.js:
--------------------------------------------------------------------------------
1 | import { IconContext } from 'react-icons'
2 | import React, { useContext } from 'react'
3 |
4 | export const IconContextProvider = ({ children, value }) => {
5 | return {children}
6 | }
7 |
8 | export const useIconContext = () => {
9 | return useContext(IconContext)
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/IllustrationHtml/docs.md:
--------------------------------------------------------------------------------
1 | ```react
2 | `} />
10 | ```
11 |
--------------------------------------------------------------------------------
/src/components/InfoBox/ListItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { sansSerifRegular15, sansSerifRegular18 } from '../Typography/styles'
4 | import { css } from 'glamor'
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { textAttributes } from './InfoBox'
7 | import { convertStyleToRem } from '../Typography/utils'
8 | import { useColorContext } from '../Colors/useColorContext'
9 |
10 | const WIDTH = 22
11 |
12 | const styles = {
13 | li: css({
14 | paddingLeft: `${WIDTH}px`,
15 | position: 'relative',
16 | ...convertStyleToRem(sansSerifRegular15),
17 | [mUp]: {
18 | ...convertStyleToRem(sansSerifRegular18)
19 | },
20 | '& p:last-child': {
21 | marginBottom: 0
22 | }
23 | })
24 | }
25 |
26 | const ListItem = ({ children, attributes = {}, style = {} }) => {
27 | const [colorScheme] = useColorContext()
28 | return (
29 |
36 | {children}
37 |
38 | )
39 | }
40 |
41 | ListItem.propTypes = {
42 | children: PropTypes.node.isRequired,
43 | attributes: PropTypes.object,
44 | style: PropTypes.object
45 | }
46 |
47 | export default ListItem
48 |
--------------------------------------------------------------------------------
/src/components/InfoBox/Subhead.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { sansSerifMedium15, sansSerifMedium18 } from '../Typography/styles'
4 | import { css } from 'glamor'
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { textAttributes } from './InfoBox'
7 | import { convertStyleToRem } from '../Typography/utils'
8 | import { useColorContext } from '../Colors/useColorContext'
9 |
10 | const styles = {
11 | text: css({
12 | ...convertStyleToRem(sansSerifMedium15),
13 | marginBottom: '-12px',
14 | [mUp]: {
15 | ...convertStyleToRem(sansSerifMedium18),
16 | marginBottom: '-14px'
17 | }
18 | })
19 | }
20 |
21 | export const Subhead = ({ children, attributes }) => {
22 | const [colorScheme] = useColorContext()
23 | return (
24 |
30 | {children}
31 |
32 | )
33 | }
34 |
35 | Subhead.propTypes = {
36 | children: PropTypes.node.isRequired,
37 | attributes: PropTypes.object
38 | }
39 |
40 | export default Subhead
41 |
--------------------------------------------------------------------------------
/src/components/InfoBox/Text.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { fontRule } from '../Typography/Interaction'
4 | import { sansSerifRegular15, sansSerifRegular18 } from '../Typography/styles'
5 | import { css } from 'glamor'
6 | import { mUp } from '../../theme/mediaQueries'
7 | import { textAttributes } from './InfoBox'
8 | import { convertStyleToRem, pxToRem } from '../Typography/utils'
9 | import { useColorContext } from '../Colors/useColorContext'
10 |
11 | const styles = {
12 | text: css({
13 | ...convertStyleToRem(sansSerifRegular15),
14 | lineHeight: pxToRem('24px'),
15 | [mUp]: {
16 | ...convertStyleToRem(sansSerifRegular18)
17 | },
18 | ':nth-of-type(2)': {
19 | marginTop: 0
20 | }
21 | })
22 | }
23 |
24 | export const Text = ({ children, attributes }) => {
25 | const [colorScheme] = useColorContext()
26 | return (
27 |
34 | {children}
35 |
36 | )
37 | }
38 |
39 | Text.propTypes = {
40 | children: PropTypes.node.isRequired,
41 | attributes: PropTypes.object
42 | }
43 |
44 | export default Text
45 |
--------------------------------------------------------------------------------
/src/components/InfoBox/Title.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { sansSerifMedium16, sansSerifMedium19 } from '../Typography/styles'
4 | import { css } from 'glamor'
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { textAttributes } from './InfoBox'
7 | import { convertStyleToRem } from '../Typography/utils'
8 | import { useColorContext } from '../Colors/useColorContext'
9 |
10 | const styles = {
11 | text: css({
12 | margin: '0 0 8px 0',
13 | borderTopWidth: 1,
14 | borderTopStyle: 'solid',
15 | ...convertStyleToRem(sansSerifMedium16),
16 | [mUp]: {
17 | ...convertStyleToRem(sansSerifMedium19),
18 | margin: '0 0 12px 0'
19 | }
20 | })
21 | }
22 |
23 | export const Title = ({ children, attributes }) => {
24 | const [colorScheme] = useColorContext()
25 | return (
26 |
33 | {children}
34 |
35 | )
36 | }
37 |
38 | Title.propTypes = {
39 | children: PropTypes.node.isRequired,
40 | attributes: PropTypes.object
41 | }
42 |
43 | export default Title
44 |
--------------------------------------------------------------------------------
/src/components/InfoBox/index.js:
--------------------------------------------------------------------------------
1 | export {
2 | default as InfoBox,
3 | IMAGE_SIZES as INFOBOX_IMAGE_SIZES,
4 | DEFAULT_IMAGE_SIZE as INFOBOX_DEFAULT_IMAGE_SIZE
5 | } from './InfoBox'
6 | export { default as InfoBoxText } from './Text'
7 | export { default as InfoBoxTitle } from './Title'
8 | export { default as InfoBoxListItem } from './ListItem'
9 | export { default as InfoBoxSubhead } from './Subhead'
10 |
--------------------------------------------------------------------------------
/src/components/List/index.js:
--------------------------------------------------------------------------------
1 | export { List, UnorderedList, OrderedList, ListItem } from './List'
2 |
--------------------------------------------------------------------------------
/src/components/Logo/docs.md:
--------------------------------------------------------------------------------
1 | ```react
2 |
3 | ```
4 |
5 | The logo is responsive by default and fills the full width.
6 |
7 | ## Inverted
8 |
9 | ```react|dark
10 |
11 | ```
12 |
13 | ## Explicit Sizes
14 |
15 | ```react
16 |
17 | ```
18 |
19 | ```react
20 |
21 | ```
22 |
23 | ## Brand Mark
24 |
25 | The responsive brand mark.
26 |
27 | ```react
28 |
29 |
30 |
31 | ```
32 |
33 | ```react
34 |
35 | ```
--------------------------------------------------------------------------------
/src/components/Overlay/OverlayBody.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import { mUp } from '../../theme/mediaQueries'
4 | import { height } from './OverlayToolbar'
5 |
6 | const PADDING = 20
7 |
8 | const overlayBodyStyle = css({
9 | padding: `${height + PADDING}px ${PADDING}px`,
10 | // The iPhone X Space
11 | // - thank you Apple for overlaying websites
12 | paddingBottom: 120,
13 | [mUp]: {
14 | padding: `${height + PADDING}px ${PADDING}px`,
15 | paddingBottom: PADDING
16 | }
17 | })
18 |
19 | const OverlayBody = props =>
20 |
21 | OverlayBody.PADDING = PADDING
22 |
23 | export default OverlayBody
24 |
--------------------------------------------------------------------------------
/src/components/Overlay/docs.imports.js:
--------------------------------------------------------------------------------
1 | export { default as Button } from '../Button'
2 | export { default as Overlay, OverlayRenderer } from './Overlay'
3 | export { OverlayToolbar } from './OverlayToolbar'
4 | export { default as OverlayBody } from './OverlayBody'
5 | export { default as Field } from '../Form/Field'
6 | export { default as Checkbox } from '../Form/Checkbox'
7 | export { Interaction } from '../Typography'
8 |
--------------------------------------------------------------------------------
/src/components/Overlay/index.js:
--------------------------------------------------------------------------------
1 | export { default as Overlay } from './Overlay'
2 | export { OverlayToolbar } from './OverlayToolbar'
3 | export { default as OverlayBody } from './OverlayBody'
4 |
--------------------------------------------------------------------------------
/src/components/Progress/index.js:
--------------------------------------------------------------------------------
1 | export { default as ProgressCircle } from './Circle'
2 |
--------------------------------------------------------------------------------
/src/components/PullQuote/Source.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { sansSerifRegular14, sansSerifRegular15 } from '../Typography/styles'
4 | import { css } from 'glamor'
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { convertStyleToRem } from '../Typography/utils'
7 |
8 | const styles = {
9 | cite: css({
10 | display: 'block',
11 | ...convertStyleToRem(sansSerifRegular14),
12 | marginTop: '18px',
13 | [mUp]: {
14 | ...convertStyleToRem(sansSerifRegular15),
15 | marginTop: '21px'
16 | },
17 | fontStyle: 'normal'
18 | })
19 | }
20 |
21 | export const Source = ({ children, attributes }) => {
22 | return (
23 |
24 | {children}
25 |
26 | )
27 | }
28 |
29 | Source.propTypes = {
30 | children: PropTypes.node.isRequired,
31 | attributes: PropTypes.object
32 | }
33 |
34 | export default Source
35 |
--------------------------------------------------------------------------------
/src/components/PullQuote/Text.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { serifBold24, serifBold28, serifBold42 } from '../Typography/styles'
4 | import { css } from 'glamor'
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { convertStyleToRem } from '../Typography/utils'
7 | import { useColorContext } from '../Colors/useColorContext'
8 |
9 | const baseStyle = {
10 | ...convertStyleToRem(serifBold24)
11 | }
12 |
13 | const styles = {
14 | default: css({
15 | ...baseStyle,
16 | [mUp]: {
17 | ...convertStyleToRem(serifBold28)
18 | }
19 | }),
20 | large: css({
21 | ...baseStyle,
22 | [mUp]: {
23 | ...convertStyleToRem(serifBold42)
24 | }
25 | })
26 | }
27 |
28 | export const Text = ({ children, attributes, size }) => {
29 | const [colorScheme] = useColorContext()
30 | return (
31 |
36 | {children}
37 |
38 | )
39 | }
40 |
41 | Text.propTypes = {
42 | children: PropTypes.node.isRequired,
43 | attributes: PropTypes.object,
44 | size: PropTypes.oneOf(['default', 'large'])
45 | }
46 |
47 | Text.defaultProps = {
48 | size: 'default'
49 | }
50 |
51 | export default Text
52 |
--------------------------------------------------------------------------------
/src/components/PullQuote/index.js:
--------------------------------------------------------------------------------
1 | export {
2 | default as PullQuote,
3 | IMAGE_SIZE as PULLQUOTE_IMAGE_SIZE
4 | } from './PullQuote'
5 | export { default as PullQuoteSource } from './Source'
6 | export { default as PullQuoteText } from './Text'
7 |
--------------------------------------------------------------------------------
/src/components/RawHtml/docs.md:
--------------------------------------------------------------------------------
1 | The `RawHtml` component allows to (dangerously) render raw HTML with styleguide-compliant typography. Typical use cases are links and ` ` tags inside translation strings.
2 |
3 | By default the HTML is rendered inside a `` element. The `type` property can be either a tag name string (such as 'div' or 'h1'), or a React component type.
4 |
5 | ```react|span-6
6 | Bold und Link '
9 | }}
10 | />
11 | ```
12 |
13 | ```react|span-6
14 | Bold und Link '
18 | }}
19 | />
20 | ```
21 |
22 | ```react|span-6
23 | Bold und Link '
27 | }}
28 | />
29 | ```
30 |
31 | ```react|span-6
32 | Link '
37 | }}
38 | />
39 | ```
40 |
--------------------------------------------------------------------------------
/src/components/RawHtml/index.js:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react'
2 | import { css } from 'glamor'
3 | import PropTypes from 'prop-types'
4 | import { useColorContext } from '../Colors/useColorContext'
5 | import { underline } from '../../lib/styleMixins'
6 |
7 | const styles = {
8 | default: css({
9 | '& ul, & ol': {
10 | overflow: 'hidden'
11 | }
12 | })
13 | }
14 |
15 | const RawHtml = ({ type: Type, dangerouslySetInnerHTML, error }) => {
16 | const [colorScheme] = useColorContext()
17 | const colorRule = useMemo(
18 | () =>
19 | css({
20 | color: colorScheme.getCSSColor(error ? 'error' : 'text'),
21 | '& a': {
22 | ...underline,
23 | color: colorScheme.getCSSColor(error ? 'error' : 'text'),
24 | '@media (hover)': {
25 | ':hover': {
26 | color: colorScheme.getCSSColor(error ? 'error' : 'textSoft')
27 | }
28 | }
29 | }
30 | }),
31 | [colorScheme, error]
32 | )
33 |
34 | return (
35 |
40 | )
41 | }
42 |
43 | RawHtml.defaultProps = {
44 | type: 'span'
45 | }
46 |
47 | RawHtml.propTypes = {
48 | type: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
49 | }
50 |
51 | export default RawHtml
52 |
--------------------------------------------------------------------------------
/src/components/SeriesNav/__docs__/index.js:
--------------------------------------------------------------------------------
1 | export * from './seriesNavExample'
2 |
--------------------------------------------------------------------------------
/src/components/SeriesNav/docs.md:
--------------------------------------------------------------------------------
1 | ```react
2 | (
6 |
7 |
8 |
9 | }
11 | label="23%"
12 | labelShort="23%"
13 | />
14 |
15 |
16 | )
17 | }
18 | PayNote={TestPayNote}
19 | seriesDescription={true}
20 | t={t}
21 | />
22 | ```
23 |
24 | ## Inline
25 |
26 | ```react
27 |
34 | ```
35 |
--------------------------------------------------------------------------------
/src/components/SeriesNav/index.js:
--------------------------------------------------------------------------------
1 | export { default as SeriesNav } from './SeriesNav'
2 |
--------------------------------------------------------------------------------
/src/components/ShareImage/SharePreviewFacebook.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 |
4 | export const FACEBOOK_CARD_PREVIEW_WIDTH = 590
5 |
6 | const styles = {
7 | container: css({
8 | backgroundColor: 'rgb(240, 242, 245)',
9 | color: 'rgb(28, 30, 33)',
10 | width: FACEBOOK_CARD_PREVIEW_WIDTH,
11 | padding: '10px 12px',
12 | maxHeight: 120,
13 | overflow: 'hidden',
14 | fontFamily:
15 | 'system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif'
16 | }),
17 | title: css({
18 | fontSize: 16,
19 | fontWeight: 600,
20 | lineHeight: '1.17em',
21 | maxHeight: 110,
22 | overflow: 'hidden',
23 | marginBottom: 3,
24 | wordWrap: 'break-word',
25 | color: 'rgb(5, 5, 5)'
26 | }),
27 | description: css({
28 | fontFamily: 'sans-serif',
29 | fontSize: 14,
30 | lineHeight: '1.33em',
31 | textOverflow: 'ellipsis',
32 | overflow: 'hidden',
33 | whiteSpace: 'nowrap',
34 | color: 'rgb(101, 103, 107)'
35 | }),
36 | domain: css({
37 | fontFamily: 'sans-serif',
38 | fontSize: 12,
39 | lineHeight: '1.23em',
40 | textTransform: 'uppercase',
41 | color: 'rgb(101, 103, 107)',
42 | paddingBottom: 4
43 | })
44 | }
45 |
46 | const SharePreviewFacebook = ({ title, description }) => (
47 |
48 |
republik.ch
49 |
{title}
50 |
{description}
51 |
52 | )
53 |
54 | export default SharePreviewFacebook
55 |
--------------------------------------------------------------------------------
/src/components/Social/index.js:
--------------------------------------------------------------------------------
1 | export { default as Tweet } from './Tweet'
2 |
--------------------------------------------------------------------------------
/src/components/Spinner/docs.md:
--------------------------------------------------------------------------------
1 | ## Spinner
2 |
3 | The `Spinner` has `position:absolute` at 50% / 50%. It is therefore taken out of the page flow, so make sure to put an appropriately-sized container around it.
4 |
5 | The only props the spinner accepts is `size` – the width/height of the spinner.
6 |
7 | ```react|span-3
8 |
9 |
10 |
11 | ```
12 | ```react|span-3
13 |
14 |
15 |
16 | ```
17 |
18 | ## InlineSpinner
19 |
20 | The `InlineSpinner` wraps a `Spinner` in a correctly-sized `inline-block` element.
21 |
22 | It accepts the same props as `Spinner`.
23 |
24 | ```react|span-3
25 |
26 | ```
27 |
28 | ```react|span-3
29 |
30 | ```
31 |
--------------------------------------------------------------------------------
/src/components/Spinner/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 |
4 | const containerStyle = css({
5 | display: 'block',
6 | position: 'absolute',
7 | top: '50%',
8 | left: '50%'
9 | })
10 | const spin = css.keyframes({
11 | '0%': { opacity: 1 },
12 | '100%': { opacity: 0.15 }
13 | })
14 | const barStyle = css({
15 | display: 'block',
16 | animation: `${spin} 1.2s linear infinite`,
17 | borderRadius: 5,
18 | backgroundColor: '#999',
19 | position: 'absolute',
20 | width: '20%',
21 | height: '7.8%',
22 | top: '-3.9%',
23 | left: '-10%'
24 | })
25 |
26 | export const Spinner = ({ size }) => {
27 | let bars = []
28 | for (let i = 0; i < 12; i++) {
29 | let style = {}
30 | style.WebkitAnimationDelay = style.animationDelay = (i - 12) / 10 + 's'
31 | style.WebkitTransform = style.transform =
32 | 'rotate(' + i * 30 + 'deg) translate(146%)'
33 |
34 | bars.push( )
35 | }
36 |
37 | return (
38 |
39 | {bars}
40 |
41 | )
42 | }
43 |
44 | const inlineBlock = css({
45 | position: 'relative',
46 | display: 'inline-block'
47 | })
48 |
49 | export const InlineSpinner = ({ size }) => (
50 |
51 |
52 |
53 | )
54 |
55 | Spinner.defaultProps = InlineSpinner.defaultProps = {
56 | size: 50
57 | }
58 |
59 | export default Spinner
60 |
--------------------------------------------------------------------------------
/src/components/TeaserActiveDebates/DebateHeader.js:
--------------------------------------------------------------------------------
1 | import { css } from 'glamor'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 | import { IconLink } from '../Discussion/Internal/Comment'
5 | import { sansSerifMedium16 } from '../Typography/styles'
6 | import { useColorContext } from '../Colors/ColorContext'
7 |
8 | const styles = {
9 | header: css({
10 | display: 'flex',
11 | justifyContent: 'space-between',
12 | alignItems: 'center'
13 | }),
14 | title: css({
15 | ...sansSerifMedium16,
16 | marginRight: 10,
17 | textDecoration: 'none'
18 | })
19 | }
20 |
21 | const DebateHeader = React.forwardRef(
22 | ({ title, commentCount, href, onClick }, ref) => {
23 | const [colorScheme] = useColorContext()
24 | return (
25 |
43 | )
44 | }
45 | )
46 |
47 | export default DebateHeader
48 |
49 | DebateHeader.propTypes = {
50 | title: PropTypes.string,
51 | commentCount: PropTypes.number,
52 | href: PropTypes.string
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/TeaserActiveDebates/__docs__/index.js:
--------------------------------------------------------------------------------
1 | export * from './activeDebatesExample'
2 |
--------------------------------------------------------------------------------
/src/components/TeaserActiveDebates/index.js:
--------------------------------------------------------------------------------
1 | export { default as TeaserActiveDebates } from './ActiveDebates'
2 | export { default as ActiveDebateHeader } from './DebateHeader'
3 | export { default as ActiveDebateTeaser } from './DebateTeaser'
4 | export { default as ActiveDebateComment } from './DebateComment'
5 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/Context.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const defaultValue = {
4 | bgColor: 'default',
5 | color: 'text'
6 | }
7 |
8 | const CarouselContext = React.createContext(defaultValue)
9 |
10 | export default CarouselContext
11 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/Format.js:
--------------------------------------------------------------------------------
1 | import { css } from 'glamor'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 | import { sansSerifMedium14 } from '../Typography/styles'
5 | import { useColorContext } from '../Colors/useColorContext'
6 | import CarouselContext, { defaultValue } from './Context'
7 |
8 | const styles = css({
9 | ...sansSerifMedium14,
10 | margin: '0 0 10px 0'
11 | })
12 |
13 | const Format = ({ children, color }) => {
14 | const context = React.useContext(CarouselContext)
15 | const mapping = context.color === defaultValue.color ? 'format' : undefined
16 | const textColor = color || context.color
17 | const [colorScheme] = useColorContext()
18 | return (
19 |
20 | {children}
21 |
22 | )
23 | }
24 |
25 | export default Format
26 |
27 | Format.propTypes = {
28 | children: PropTypes.node,
29 | color: PropTypes.string
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/Grid.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 |
4 | import { TILE_GRID_PADDING } from './constants'
5 |
6 | const styles = {
7 | container: css({
8 | display: 'flex',
9 | flexWrap: 'wrap',
10 | marginLeft: -TILE_GRID_PADDING,
11 | marginRight: -TILE_GRID_PADDING,
12 | width: `calc(100% + ${TILE_GRID_PADDING * 2}px)`
13 | })
14 | }
15 |
16 | const Grid = ({ children }) => {
17 | return (
18 |
19 | {children}
20 |
21 | )
22 | }
23 |
24 | export default Grid
25 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/Lead.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | import React from 'react'
3 |
4 | const Lead = ({ children }) => {
5 | return {children}
6 | }
7 |
8 | Lead.propTypes = {
9 | children: PropTypes.node
10 | }
11 |
12 | export default Lead
13 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/Subject.js:
--------------------------------------------------------------------------------
1 | import { css } from 'glamor'
2 | import PropTypes from 'prop-types'
3 | import React from 'react'
4 | import { mUp } from '../TeaserFront/mediaQueries'
5 | import { sansSerifRegular16, sansSerifRegular18 } from '../Typography/styles'
6 | import { useColorContext } from '../Colors/useColorContext'
7 |
8 | const styles = css({
9 | ...sansSerifRegular16,
10 | lineHeight: '22px',
11 |
12 | [mUp]: {
13 | ...sansSerifRegular18,
14 | lineHeight: '24px'
15 | }
16 | })
17 |
18 | const Subject = ({ children }) => {
19 | const [colorScheme] = useColorContext()
20 | const customStyles = css(styles, {
21 | '&::after': {
22 | content: children.length ? ' ' : undefined
23 | }
24 | })
25 | return (
26 |
27 | {children}
28 |
29 | )
30 | }
31 |
32 | export default Subject
33 |
34 | Subject.propTypes = {
35 | children: PropTypes.node
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/TileContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react'
2 |
3 | import CarouselContext from './Context'
4 | import Grid from './Grid'
5 | import Row from './Row'
6 |
7 | const Container = ({ initialScrollTileIndex, children, isSeriesNav }) => {
8 | const context = useContext(CarouselContext)
9 | if (context.grid) {
10 | return {children}
11 | }
12 | return (
13 |
17 | {children}
18 |
19 | )
20 | }
21 |
22 | export default Container
23 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/constants.js:
--------------------------------------------------------------------------------
1 | export const PADDING = 15
2 | export const TILE_MAX_WIDTH = 400
3 | export const TILE_MARGIN_RIGHT = 7
4 | export const TILE_GRID_PADDING = 7
5 |
--------------------------------------------------------------------------------
/src/components/TeaserCarousel/index.js:
--------------------------------------------------------------------------------
1 | import * as _TeaserCarouselHeadline from './Headline'
2 |
3 | export const TeaserCarouselHeadline = { ..._TeaserCarouselHeadline }
4 |
5 | export { default as TeaserCarousel } from './Carousel'
6 | export { default as TeaserCarouselTile } from './Tile'
7 | export { default as TeaserCarouselTileContainer } from './TileContainer'
8 | export { default as TeaserCarouselSubject } from './Subject'
9 | export { default as TeaserCarouselLead } from './Lead'
10 | export { default as TeaserCarouselFormat } from './Format'
11 | export { default as TeaserCarouselArticleCount } from './ArticleCount'
12 |
--------------------------------------------------------------------------------
/src/components/TeaserFeed/Credit.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import { mUp } from '../../theme/mediaQueries'
5 | import { sansSerifRegular14, sansSerifRegular15 } from '../Typography/styles'
6 | import { convertStyleToRem } from '../Typography/utils'
7 | import { useColorContext } from '../Colors/useColorContext'
8 |
9 | const styles = {
10 | main: css({
11 | margin: 0,
12 | ...convertStyleToRem(sansSerifRegular14),
13 | [mUp]: {
14 | ...convertStyleToRem(sansSerifRegular15)
15 | }
16 | })
17 | }
18 |
19 | const Credit = ({ children }) => {
20 | const [colorScheme] = useColorContext()
21 | return (
22 |
23 | {children}
24 |
25 | )
26 | }
27 |
28 | Credit.propTypes = {
29 | children: PropTypes.node.isRequired
30 | }
31 |
32 | export default Credit
33 |
--------------------------------------------------------------------------------
/src/components/TeaserFeed/Format.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { sansSerifMedium14, sansSerifMedium16 } from '../Typography/styles'
4 | import { css } from 'glamor'
5 | import { mUp } from '../../theme/mediaQueries'
6 | import { convertStyleToRem } from '../Typography/utils'
7 | import { useColorContext } from '../Colors/useColorContext'
8 |
9 | const styles = {
10 | main: css({
11 | ...convertStyleToRem(sansSerifMedium14),
12 | margin: '0 0 6px 0',
13 | [mUp]: {
14 | ...convertStyleToRem(sansSerifMedium16),
15 | margin: '-5px 0 8px 0'
16 | }
17 | })
18 | }
19 |
20 | export const Format = ({ children, color }) => {
21 | const [colorScheme] = useColorContext()
22 |
23 | return (
24 |
28 | {children}
29 |
30 | )
31 | }
32 |
33 | Format.propTypes = {
34 | children: PropTypes.node.isRequired,
35 | color: PropTypes.string
36 | }
37 |
38 | export default Format
39 |
--------------------------------------------------------------------------------
/src/components/TeaserFeed/Highlight.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import { mUp } from '../../theme/mediaQueries'
5 | import { convertStyleToRem } from '../Typography/utils'
6 | import {
7 | sansSerifMedium14,
8 | sansSerifMedium16,
9 | sansSerifRegular16,
10 | sansSerifRegular18
11 | } from '../Typography/styles'
12 | import { useColorContext } from '../Colors/useColorContext'
13 |
14 | const styles = {
15 | main: css({
16 | ...convertStyleToRem(sansSerifRegular16),
17 | margin: '10px 0 5px 0',
18 | [mUp]: {
19 | ...convertStyleToRem(sansSerifRegular18)
20 | }
21 | }),
22 | label: css({
23 | ...convertStyleToRem(sansSerifMedium14),
24 | [mUp]: {
25 | ...convertStyleToRem(sansSerifMedium16)
26 | }
27 | })
28 | }
29 |
30 | const Highlight = ({ children, label }) => {
31 | const [colorScheme] = useColorContext()
32 | return (
33 |
34 | {!!label && (
35 |
36 | {label}:
37 |
38 | )}{' '}
39 | {children}
40 |
41 | )
42 | }
43 |
44 | Highlight.propTypes = {
45 | children: PropTypes.node.isRequired
46 | }
47 |
48 | export default Highlight
49 |
--------------------------------------------------------------------------------
/src/components/TeaserFeed/InternalOnlyTag.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import colors from '../../theme/colors'
4 | import { mUp } from '../../theme/mediaQueries'
5 | import { sansSerifRegular12, sansSerifRegular13 } from '../Typography/styles'
6 | import { convertStyleToRem } from '../Typography/utils'
7 |
8 | const styles = {
9 | label: css({
10 | ...convertStyleToRem(sansSerifRegular12),
11 | color: colors.disabled,
12 | position: 'absolute',
13 | top: '-20px',
14 | right: 0,
15 | [mUp]: {
16 | ...convertStyleToRem(sansSerifRegular13)
17 | }
18 | })
19 | }
20 |
21 | const InternalOnlyTag = ({ t }) => {
22 | return (
23 |
24 | {t ? t('styleguide/TeaserFeed/InternalOnlyTag') : 'Internal'}
25 |
26 | )
27 | }
28 |
29 | export default InternalOnlyTag
30 |
--------------------------------------------------------------------------------
/src/components/TeaserFeed/Lead.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import { mUp } from '../../theme/mediaQueries'
5 | import { serifRegular17, serifRegular19 } from '../Typography/styles'
6 | import { convertStyleToRem } from '../Typography/utils'
7 |
8 | const styles = {
9 | main: css({
10 | ...convertStyleToRem(serifRegular17),
11 | margin: '0 0 5px 0',
12 | [mUp]: {
13 | ...convertStyleToRem(serifRegular19)
14 | }
15 | })
16 | }
17 |
18 | const Lead = ({ children }) => {
19 | return {children}
20 | }
21 |
22 | Lead.propTypes = {
23 | children: PropTypes.node.isRequired
24 | }
25 |
26 | export default Lead
27 |
--------------------------------------------------------------------------------
/src/components/TeaserFeed/utils.js:
--------------------------------------------------------------------------------
1 | import colors from '../../theme/colors'
2 |
3 | export const getFormatLine = ({ title, format, series, repoId, path }) => {
4 | if (format?.meta) {
5 | return {
6 | title: format.meta.title,
7 | color: format.meta.color || colors[format.meta.kind],
8 | path: format.meta.path
9 | }
10 | }
11 | // if (series) {
12 | // const currentEpisode = series.episodes.find(
13 | // episode =>
14 | // (path && path === episode.document?.meta.path) ||
15 | // (repoId && repoId === episode.document?.repoId)
16 | // )
17 | // const starterEpisode = series.episodes.find(episode =>
18 | // episode.label?.match(/Auftakt/i)
19 | // )
20 |
21 | // if (currentEpisode && currentEpisode === starterEpisode) {
22 | // return {}
23 | // }
24 | // // back off if title already contain series title to avoid doubling
25 | // if (
26 | // typeof title === 'string' &&
27 | // title.toLowerCase().indexOf(series.title.toLowerCase()) !== -1
28 | // ) {
29 | // return {}
30 | // }
31 |
32 | // return {
33 | // title: currentEpisode?.label
34 | // ? `${series.title}${series.title.match(/\?$/) ? '' : ','} ${
35 | // currentEpisode.label
36 | // }`
37 | // : series.title,
38 | // path: (starterEpisode || series.episodes[0])?.document?.meta.path,
39 | // logo: series.logo,
40 | // logoDark: series.logoDark
41 | // }
42 | // }
43 | return {}
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/TeaserFront/Credit.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { Editorial } from '../Typography'
4 |
5 | const Credit = ({ children }) => {
6 | return (
7 | {children}
8 | )
9 | }
10 |
11 | Credit.propTypes = {
12 | children: PropTypes.node.isRequired
13 | }
14 |
15 | export default Credit
16 |
--------------------------------------------------------------------------------
/src/components/TeaserFront/Format.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import { lab } from 'd3-color'
5 | import { mUp, tUp } from './mediaQueries'
6 | import { sansSerifMedium16, sansSerifMedium20 } from '../Typography/styles'
7 | import { convertStyleToRem } from '../Typography/utils'
8 |
9 | const format = css({
10 | ...convertStyleToRem(sansSerifMedium16),
11 | margin: '0 0 18px 0',
12 | [mUp]: {
13 | ...convertStyleToRem(sansSerifMedium20),
14 | margin: '0 0 28px 0'
15 | }
16 | })
17 |
18 | const Format = ({ children, color, collapsedColor }) => {
19 | const labColor = lab(color)
20 | const labCollapsedColor = lab(collapsedColor || color)
21 | const mixColorStyle =
22 | collapsedColor &&
23 | css({
24 | color:
25 | labCollapsedColor.l > 50
26 | ? labCollapsedColor.darker(0.6)
27 | : labCollapsedColor.brighter(3.0),
28 | [tUp]: {
29 | color: labColor.l > 50 ? labColor.darker(2.0) : labColor.brighter(3.0)
30 | }
31 | })
32 |
33 | return (
34 |
39 | {children}
40 |
41 | )
42 | }
43 |
44 | Format.propTypes = {
45 | children: PropTypes.node.isRequired,
46 | color: PropTypes.string,
47 | collapsedColor: PropTypes.string
48 | }
49 |
50 | export default Format
51 |
--------------------------------------------------------------------------------
/src/components/TeaserFront/Lead.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import colors from '../../theme/colors'
4 | import { css } from 'glamor'
5 | import { mUp } from './mediaQueries'
6 | import {
7 | serifRegular18,
8 | serifRegular19,
9 | serifRegular23
10 | } from '../Typography/styles'
11 | import { convertStyleToRem, pxToRem } from '../Typography/utils'
12 |
13 | const leadStyle = {
14 | ...convertStyleToRem(serifRegular19),
15 | lineHeight: pxToRem('27px'),
16 | margin: '0 0 10px 0',
17 | color: colors.text
18 | }
19 |
20 | const lead = css({
21 | ...leadStyle,
22 | [mUp]: {
23 | ...convertStyleToRem(serifRegular23),
24 | margin: '0 0 20px 0'
25 | }
26 | })
27 |
28 | const leadSmall = css({
29 | ...leadStyle,
30 | [mUp]: {
31 | ...convertStyleToRem(serifRegular18),
32 | margin: '0 0 20px 0'
33 | }
34 | })
35 |
36 | const Lead = ({ children, columns, attributes }) => (
37 |
42 | {children}
43 |
44 | )
45 |
46 | Lead.propTypes = {
47 | children: PropTypes.node.isRequired,
48 | columns: PropTypes.number
49 | }
50 |
51 | export default Lead
52 |
--------------------------------------------------------------------------------
/src/components/TeaserFront/Typo.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { css } from 'glamor'
4 | import { mUp, tUp } from './mediaQueries'
5 | import Text from './Text'
6 |
7 | export const MAX_WIDTH_PERCENT = 70
8 |
9 | const styles = {
10 | root: css({
11 | margin: 0
12 | }),
13 | textContainer: css({
14 | margin: '0 auto',
15 | padding: '15px 15px 40px 15px',
16 | [mUp]: {
17 | maxWidth: `${MAX_WIDTH_PERCENT}%`,
18 | padding: '60px 0 80px 0'
19 | },
20 | [tUp]: {
21 | padding: '80px 0 100px 0'
22 | }
23 | })
24 | }
25 |
26 | const TypoBlock = ({ children, attributes, onClick, color, bgColor }) => {
27 | const background = bgColor || ''
28 | return (
29 |
38 |
39 |
40 | {children}
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | TypoBlock.propTypes = {
48 | children: PropTypes.node.isRequired,
49 | attributes: PropTypes.object,
50 | color: PropTypes.string,
51 | bgColor: PropTypes.string
52 | }
53 |
54 | export default TypoBlock
55 |
--------------------------------------------------------------------------------
/src/components/TeaserFront/index.js:
--------------------------------------------------------------------------------
1 | import * as _ImageHeadline from './ImageHeadline'
2 | import * as _SplitHeadline from './SplitHeadline'
3 | import * as _TypoHeadline from './TypoHeadline'
4 | import * as _TileHeadline from './TileHeadline'
5 |
6 | export const TeaserFrontImageHeadline = { ..._ImageHeadline }
7 | export const TeaserFrontSplitHeadline = { ..._SplitHeadline }
8 | export const TeaserFrontTypoHeadline = { ..._TypoHeadline }
9 | export const TeaserFrontTileHeadline = { ..._TileHeadline }
10 |
11 | export { default as TeaserFrontImage } from './Image'
12 | export { default as TeaserFrontTypo } from './Typo'
13 | export { default as TeaserFrontSplit } from './Split'
14 | export { default as TeaserFrontTileRow } from './TileRow'
15 | export { default as TeaserFrontTile } from './Tile'
16 |
17 | export { default as TeaserFrontFormat } from './Format'
18 | export { default as TeaserFrontLead } from './Lead'
19 | export { default as TeaserFrontSubject } from './Subject'
20 | export { default as TeaserFrontCredit } from './Credit'
21 | export { default as TeaserFrontCreditLink } from './CreditLink'
22 | export { default as TeaserFrontLogo } from './Logo'
23 |
--------------------------------------------------------------------------------
/src/components/TeaserFront/mediaQueries.js:
--------------------------------------------------------------------------------
1 | // These media queries are specific to the front teasers.
2 |
3 | export const BreakPoints = {
4 | mobile: 640,
5 | tablet: 1174,
6 | desktop: 1400
7 | }
8 |
9 | export const mUp = `@media only screen and (min-width: ${BreakPoints.mobile}px)`
10 | export const tUp = `@media only screen and (min-width: ${BreakPoints.tablet}px)`
11 | export const dUp = `@media only screen and (min-width: ${BreakPoints.desktop}px)`
12 |
--------------------------------------------------------------------------------
/src/components/TeaserMyMagazine/__docs__/index.js:
--------------------------------------------------------------------------------
1 | export * from './myMagazineExamples'
2 |
--------------------------------------------------------------------------------
/src/components/TeaserMyMagazine/docs.md:
--------------------------------------------------------------------------------
1 | Supported props:
2 |
3 | - `latestSubscribedArticles` (array), required:
4 | - `latestProgressOrBookmarkedArticles` (array), required:
5 | - `ActionBar` (Component):
6 |
7 | ```react|responsive
8 | (
17 |
18 |
19 | }
21 | label="23%"
22 | labelShort="23%"
23 | fill="black"
24 | />
25 |
26 | )
27 | }
28 | />
29 | ```
30 |
--------------------------------------------------------------------------------
/src/components/TeaserMyMagazine/index.js:
--------------------------------------------------------------------------------
1 | export { default as TeaserMyMagazine } from './TeaserMyMagazine'
2 |
--------------------------------------------------------------------------------
/src/components/TeaserShared/SectionTitle.js:
--------------------------------------------------------------------------------
1 | import { css } from 'glamor'
2 | import React from 'react'
3 | import { ChevronRightIcon } from '../Icons'
4 | import { mUp } from '../TeaserFront/mediaQueries'
5 | import {
6 | sansSerifMedium16,
7 | sansSerifMedium22,
8 | sansSerifRegular30
9 | } from '../Typography/styles'
10 |
11 | const styles = {
12 | container: css({
13 | display: 'block',
14 | marginBottom: 15,
15 | ...sansSerifMedium22,
16 | textDecoration: 'none',
17 | '& svg': {
18 | width: 22,
19 | height: 22,
20 | marginLeft: 8
21 | },
22 | [mUp]: {
23 | ...sansSerifRegular30,
24 | '& svg': {
25 | width: 30,
26 | height: 30
27 | },
28 | marginBottom: 25
29 | },
30 | color: 'inherit'
31 | }),
32 | small: css({
33 | color: 'inherit',
34 | ...sansSerifMedium16,
35 | textDecoration: 'none',
36 | '& svg': {
37 | marginTop: -1,
38 | width: 16,
39 | height: 16,
40 | marginLeft: 4
41 | }
42 | })
43 | }
44 |
45 | const SectionTitle = React.forwardRef(
46 | ({ children, small, onClick, href }, ref) => {
47 | const style = small ? styles.small : styles.container
48 | return href ? (
49 |
50 | {children}
51 | { }
52 |
53 | ) : (
54 |
55 | {children}
56 |
57 | )
58 | }
59 | )
60 |
61 | export default SectionTitle
62 |
--------------------------------------------------------------------------------
/src/components/TeaserShared/docs.md:
--------------------------------------------------------------------------------
1 | ## ` `.
2 |
3 | A section title. If `href` is defined, an icon with a chevron right will be displayed on the right of the section title.
4 |
5 | Supported props:
6 | - `onClick` (function): function triggered on click.
7 | - `href` (string): link.
8 | - `children`: children component (section title).
9 |
10 | ```react|span-3
11 | {}}
13 | >
14 | Alle Serien
15 |
16 | ```
17 |
18 | ```react|span-3
19 | {}}
22 | >
23 | Aktive Debatten
24 |
25 | ```
26 |
27 | ```react
28 | {}}
32 | >
33 | Alle Beiträge im Feed
34 |
35 | ```
--------------------------------------------------------------------------------
/src/components/TeaserShared/index.js:
--------------------------------------------------------------------------------
1 | export { default as TeaserSectionTitle } from './SectionTitle'
2 |
--------------------------------------------------------------------------------
/src/components/TitleBlock/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import {
4 | PADDED_MAX_WIDTH,
5 | PADDED_MAX_WIDTH_BREAKOUT,
6 | MAX_WIDTH,
7 | PADDING,
8 | BREAKOUT
9 | } from '../Center'
10 | import { css, merge } from 'glamor'
11 | import { mUp } from '../../theme/mediaQueries'
12 |
13 | const styles = {
14 | container: css({
15 | maxWidth: PADDED_MAX_WIDTH,
16 | margin: '0 auto',
17 | paddingTop: 30,
18 | paddingLeft: PADDING,
19 | paddingRight: PADDING,
20 | [mUp]: {
21 | paddingTop: 40,
22 | margin: '0 auto'
23 | }
24 | }),
25 | containerMargin: css({
26 | marginBottom: 40,
27 | [mUp]: {
28 | marginBottom: 70
29 | }
30 | })
31 | }
32 |
33 | const TitleBlock = ({ children, attributes, center, margin, breakout }) => {
34 | return (
35 |
50 | )
51 | }
52 |
53 | TitleBlock.propTypes = {
54 | children: PropTypes.node.isRequired,
55 | attributes: PropTypes.object,
56 | center: PropTypes.bool
57 | }
58 |
59 | export default TitleBlock
60 |
--------------------------------------------------------------------------------
/src/components/Typography/Scribble.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import * as styles from './styles'
3 | import { css } from 'glamor'
4 | import { mUp } from '../../theme/mediaQueries'
5 | import { convertStyleToRem } from './utils'
6 | import { useColorContext } from '../Colors/useColorContext'
7 |
8 | export {
9 | List,
10 | UnorderedList as UL,
11 | OrderedList as OL,
12 | ListItem as LI
13 | } from '../List'
14 |
15 | const headline = css({
16 | ...convertStyleToRem(styles.cursiveTitle30),
17 | margin: '0 0 12px 0',
18 | [mUp]: {
19 | ...convertStyleToRem(styles.cursiveTitle58),
20 | margin: '0 0 12px 0'
21 | },
22 | ':first-child': {
23 | marginTop: 0
24 | },
25 | ':last-child': {
26 | marginBottom: 0
27 | }
28 | })
29 |
30 | export const Headline = ({ children, attributes, ...props }) => {
31 | const [colorScheme] = useColorContext()
32 | return (
33 |
39 | {children}
40 |
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/Typography/fontRules.js:
--------------------------------------------------------------------------------
1 | import { css } from 'glamor'
2 | import { fontStyles } from '../../theme/fonts'
3 | import colors from '../../theme/colors'
4 |
5 | export const editorialFontRule = css({
6 | ...fontStyles.serifRegular,
7 | '& em, & i': fontStyles.serifItalic,
8 | '& strong, & b': fontStyles.serifBold,
9 | '& strong em, & em strong, & b i, & i b': fontStyles.serifBoldItalic
10 | })
11 |
12 | export const interactionFontRule = css({
13 | ...fontStyles.sansSerifRegular,
14 | '& em, & i': fontStyles.sansSerifItalic,
15 | '& strong, & b': fontStyles.sansSerifMedium,
16 | '& strong em, & em strong, & b i, & i b': {
17 | textDecoration: `underline wavy ${colors.error}`
18 | }
19 | })
20 |
--------------------------------------------------------------------------------
/src/components/Typography/utils.js:
--------------------------------------------------------------------------------
1 | export const DEFAULT_FONT_SIZE = 16
2 |
3 | export const pxToRem = pxSize => {
4 | return pxSize && `${parseInt(pxSize, 10) / DEFAULT_FONT_SIZE}rem`
5 | }
6 |
7 | export const convertStyleToRem = cssRules => {
8 | return {
9 | ...cssRules,
10 | fontSize: pxToRem(cssRules.fontSize),
11 | lineHeight: pxToRem(cssRules.lineHeight)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/Variables/index.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, Children } from 'react'
2 |
3 | export const VariableContext = React.createContext({})
4 |
5 | export const Variable = ({ variable, fallback }) => {
6 | const vars = useContext(VariableContext)
7 | if (vars._mergeTags) {
8 | return fallback
9 | ? `*|IF:${vars[variable]}|* *|${vars[variable]}|* *|ELSE:|* ${fallback} *|END:IF|*`
10 | : `*|${vars[variable]}|*`
11 | }
12 | return vars[variable] || fallback || null
13 | }
14 |
15 | export const If = ({ present, children }) => {
16 | const vars = useContext(VariableContext)
17 | if (vars._mergeTags) {
18 | return (
19 | <>
20 | {`*|IF:${vars[present] || present}|*`}
21 | {children}
22 | {'*|END:IF|*'}
23 | >
24 | )
25 | }
26 |
27 | const childs = Children.toArray(children)
28 | if (vars[present]) {
29 | return <>{childs.filter(child => child.type !== Else)}>
30 | }
31 | return <>{childs.filter(child => child.type === Else)}>
32 | }
33 |
34 | export const Else = ({ children }) => {
35 | const vars = useContext(VariableContext)
36 | return (
37 | <>
38 | {vars._mergeTags && '*|ELSE:|*'}
39 | {children}
40 | >
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/Video/index.js:
--------------------------------------------------------------------------------
1 | export { default as Video } from './Video'
2 |
--------------------------------------------------------------------------------
/src/components/VideoPlayer/Icons/Fullscreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FullscreenIcon, FullscreenExitIcon } from '../../Icons'
3 |
4 | const Icon = ({ size, fill, off }) => {
5 | if (off) {
6 | return (
7 |
13 | )
14 | } else {
15 | return (
16 |
22 | )
23 | }
24 | }
25 |
26 | Icon.defaultProps = {
27 | size: 24,
28 | fill: '#fff',
29 | off: true
30 | }
31 |
32 | export default Icon
33 |
--------------------------------------------------------------------------------
/src/components/VideoPlayer/Icons/Play.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const ratio = 1.385
4 |
5 | const Play = ({ width, fill }) => (
6 |
7 |
8 |
9 | )
10 |
11 | Play.defaultProps = {
12 | width: 26,
13 | fill: '#fff'
14 | }
15 |
16 | export default Play
17 |
--------------------------------------------------------------------------------
/src/components/VideoPlayer/Icons/Rewind.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Rewind = ({ size, fill, disabled }) => (
4 |
5 |
10 |
11 | )
12 |
13 | Rewind.defaultProps = {
14 | size: 24,
15 | fill: '#fff',
16 | disabled: true
17 | }
18 |
19 | export default Rewind
20 |
--------------------------------------------------------------------------------
/src/components/VideoPlayer/Icons/Subtitles.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Icon = ({ size, fill, off }) => (
4 |
5 | {off ? (
6 |
7 |
12 |
19 |
20 | ) : (
21 |
27 | )}
28 |
29 | )
30 |
31 | Icon.defaultProps = {
32 | size: 24,
33 | fill: '#fff',
34 | off: false
35 | }
36 |
37 | export default Icon
38 |
--------------------------------------------------------------------------------
/src/components/VideoPlayer/Icons/Volume.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Icon = ({ size, fill, off }) => (
4 |
5 |
13 |
14 | )
15 |
16 | Icon.defaultProps = {
17 | size: 24,
18 | fill: '#fff',
19 | off: false
20 | }
21 |
22 | export default Icon
23 |
--------------------------------------------------------------------------------
/src/components/VideoPlayer/index.js:
--------------------------------------------------------------------------------
1 | export { default as VideoPlayer } from './Player'
2 |
--------------------------------------------------------------------------------
/src/components/globalMediaState.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | playingRef: undefined,
3 | muted: false, // video only
4 | subtitles: false, // currently video only
5 | instances: [],
6 | setTime: time => {
7 | state.instances.forEach(setter => {
8 | setter.setTime && setter.setTime(time)
9 | })
10 | }
11 | }
12 |
13 | export const parseTimeHash = hash => {
14 | const matches = hash && hash.match(/t=(\d+)/)
15 | const time = matches && +matches[1]
16 | if (time && time > -1) {
17 | return time
18 | }
19 | return false
20 | }
21 |
22 | if (typeof window !== 'undefined') {
23 | window.addEventListener('hashchange', () => {
24 | const time = parseTimeHash(window.location.hash)
25 | if (time !== false) {
26 | state.setTime(time)
27 | }
28 | })
29 | }
30 |
31 | export default state
32 |
--------------------------------------------------------------------------------
/src/development/process.docs.md:
--------------------------------------------------------------------------------
1 | ## Goals
2 |
3 | - empower the developers to be fast
4 | - document the available components
5 | - keep styles and interaction behaviour consistent
6 | - even between different code bases
7 | - enable division of labor
8 | - isolate the implementation and documentation of components
9 | - e.g. a new teaser can be implemented without knowing all the inner workings of the CMS
10 |
11 | ## General
12 |
13 | 1. All development should happen in branches and merged via a pull request.
14 | 2. Follow the [commit message format](/#commit-message-format) for proper versioning
15 |
16 | ## Adding a New Component
17 |
18 | ### Criteria for new components
19 |
20 | - Generically useable
21 | - Has been designed
22 | - Has been used in more than one place
23 | + Same app, two places can count too
24 |
25 | ### General flow
26 |
27 | 1. Start a new branch
28 | 2. Develop the component
29 | - Document the public API with/in a catalog page
30 | - Export in `src/lib.ts`
31 | 3. Create a pull request with screenshots
32 | 4. Review by another developer
33 | 5. Merge into master
34 | - Will be auto released
35 |
--------------------------------------------------------------------------------
/src/editor.ts:
--------------------------------------------------------------------------------
1 | export {
2 | default as ChartEditor
3 | } from './components/Chart/Editor'
4 |
--------------------------------------------------------------------------------
/src/global.css:
--------------------------------------------------------------------------------
1 | *, *:before, *:after {
2 | box-sizing: inherit;
3 | }
4 | * {
5 | -webkit-tap-highlight-color: transparent;
6 | }
7 | html {
8 | box-sizing: border-box;
9 | }
--------------------------------------------------------------------------------
/src/lib/globalMediaState.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | playingRef: undefined,
3 | muted: false, // video only
4 | subtitles: false, // currently video only
5 | instances: [],
6 | setTime: time => {
7 | state.instances.forEach(setter => {
8 | setter.setTime && setter.setTime(time)
9 | })
10 | }
11 | }
12 |
13 | export const parseTimeHash = hash => {
14 | const matches = hash && hash.match(/t=(\d+)/)
15 | const time = matches && +matches[1]
16 | if (time && time > -1) {
17 | return time
18 | }
19 | return false
20 | }
21 |
22 | if (typeof window !== 'undefined') {
23 | window.addEventListener('hashchange', () => {
24 | const time = parseTimeHash(window.location.hash)
25 | if (time !== false) {
26 | state.setTime(time)
27 | }
28 | })
29 | }
30 |
31 | export default state
32 |
--------------------------------------------------------------------------------
/src/lib/helpers.js:
--------------------------------------------------------------------------------
1 | export const intersperse = (list, separator) => {
2 | if (list.length === 0) {
3 | return []
4 | }
5 |
6 | return list.slice(1).reduce(
7 | (items, item, i) => {
8 | return items.concat([separator(item, i), item])
9 | },
10 | [list[0]]
11 | )
12 | }
13 |
14 | export const rafDebounce = fn => {
15 | let next
16 |
17 | return (...args) => {
18 | if (!next) {
19 | next = window.requestAnimationFrame(() => {
20 | next = undefined
21 | fn(...args)
22 | })
23 | }
24 | return next
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/inQuotes.docs.md:
--------------------------------------------------------------------------------
1 | Utility function for wrapping a string in quotation marks and avoiding double quoting. Ignores already quoted strings of the same quotation marks pattern and replaces nested quotation marks. No support for third level nested quotation marks or transformations between different quotation mark patterns.
2 |
3 | ```code|lang-js
4 | import {inQuotes} from '@project-r/styleguide'
5 |
6 | const quotedTitle = inQuotes('My title') // '«My title»'
7 | ```
8 |
9 |
10 | ```react
11 | {inQuotes('An der Bar')}
12 | ```
13 |
14 | ```react
15 | {inQuotes('«An der Bar»')}
16 | ```
17 |
18 | ```react
19 | {inQuotes('«An der Bar» mit Carla Del Ponte')}
20 | ```
21 |
22 | ```react
23 | {inQuotes('An der «Republik-Bar» mit Carla Del Ponte')}
24 | ```
25 |
26 | ```react
27 | {inQuotes('An der «Republik-Bar» und «zu Hause» mit Carla Del Ponte')}
28 | ```
29 |
30 | ```react
31 |
32 | {inQuotes(
33 | 'An der „Republik-Bar“ mit Carla Del Ponte',
34 | {
35 | outerOpening: '„',
36 | outerClosing: '“',
37 | innerOpening: '‚',
38 | innerClosing: '‘'
39 | }
40 | )}
41 |
42 | ```
43 |
--------------------------------------------------------------------------------
/src/lib/inQuotes.js:
--------------------------------------------------------------------------------
1 | const defaultMarks = {
2 | outerOpening: '«',
3 | outerClosing: '»',
4 | innerOpening: '‹',
5 | innerClosing: '›'
6 | }
7 |
8 | export const inQuotes = (str, marks = defaultMarks) => {
9 | let quotedStr = str.trim()
10 | if (
11 | quotedStr.startsWith(marks.outerOpening) &&
12 | quotedStr.endsWith(marks.outerClosing)
13 | ) {
14 | return quotedStr
15 | }
16 | quotedStr = quotedStr
17 | .replace(new RegExp(marks.outerOpening, 'g'), marks.innerOpening)
18 | .replace(new RegExp(marks.outerClosing, 'g'), marks.innerClosing)
19 | return marks.outerOpening + quotedStr + marks.outerClosing
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/slug.docs.md:
--------------------------------------------------------------------------------
1 | Utility function for converting a string to a slug.
2 |
3 | ```code|lang-js
4 | import {slug} from '@project-r/styleguide'
5 |
6 | const nameSlug = slug('Johnny Weißmüller') // 'johnny-weissmueller'
7 | ```
8 |
--------------------------------------------------------------------------------
/src/lib/slug.js:
--------------------------------------------------------------------------------
1 | const diacritics = [
2 | { base: 'a', letters: ['â', 'à'] },
3 | { base: 'c', letters: ['ç'] },
4 | { base: 'e', letters: ['é', 'ê', 'è', 'ë'] },
5 | { base: 'i', letters: ['î', 'ï'] },
6 | { base: 'o', letters: ['ô'] },
7 | { base: 'u', letters: ['ù', 'û'] },
8 | { base: 'ss', letters: ['ß'] },
9 | { base: 'ae', letters: ['ä'] },
10 | { base: 'ue', letters: ['ü'] },
11 | { base: 'oe', letters: ['ö'] }
12 | ]
13 |
14 | const diacriticsMap = diacritics.reduce((map, diacritic) => {
15 | diacritic.letters.forEach(letter => {
16 | map[letter] = diacritic.base
17 | })
18 | return map
19 | }, {})
20 |
21 | export const slug = string =>
22 | string
23 | .toLowerCase()
24 | // eslint-disable-next-line no-control-regex
25 | .replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a)
26 | .replace(/\u00ad/g, '')
27 | .replace(/[^0-9a-z]+/g, ' ')
28 | .trim()
29 | .replace(/\s+/g, '-')
30 |
--------------------------------------------------------------------------------
/src/lib/slug.test.js:
--------------------------------------------------------------------------------
1 | import { slug } from './slug'
2 |
3 | describe('lib.utils.slug - test suite', function() {
4 | test('lower case and no spaces', function() {
5 | expect(slug('John Doe')).toEqual('john-doe')
6 | })
7 | test('trim', function() {
8 | expect(slug(' John Doe ')).toEqual('john-doe')
9 | })
10 |
11 | test('double space', function() {
12 | expect(slug('John Doe')).toEqual('john-doe')
13 | })
14 |
15 | test('invalid chars', function() {
16 | expect(slug('@~John,.?-+=|/Doe!')).toEqual('john-doe')
17 | })
18 |
19 | test('umlaut german', function() {
20 | expect(slug('äüöß')).toEqual('aeueoess')
21 | })
22 |
23 | test('umlaut french', function() {
24 | expect(slug('âàçéêèëîïôùû')).toEqual('aaceeeeiiouu')
25 | })
26 |
27 | test('soft hyphen', function() {
28 | expect(slug('um\u00adwelt\u00adschmerz')).toEqual('umweltschmerz')
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/src/lib/styleMixins.js:
--------------------------------------------------------------------------------
1 | export const ellipsize = {
2 | whiteSpace: 'nowrap',
3 | overflow: 'hidden',
4 | textOverflow: 'ellipsis'
5 | }
6 |
7 | export const underline = {
8 | textDecoration: 'underline',
9 | textDecorationSkip: 'ink'
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/textGauger.js:
--------------------------------------------------------------------------------
1 | import memoize from 'lodash/memoize'
2 |
3 | const measurementDiv = memoize(
4 | () => {
5 | const div = document.createElement('div')
6 | div.className = 'DOMMEASUREMENTOUTLET'
7 | div.style.position = 'fixed'
8 | div.style.top = '-100%'
9 | div.style.visibility = 'hidden'
10 | div.style.pointerEvents = 'none'
11 | document.body.appendChild(div)
12 | return div
13 | },
14 | () => ''
15 | )
16 |
17 | export const createTextGauger = memoize(
18 | ({ fontFamily, fontSize, lineHeight }, { dimension, html }) => {
19 | if (typeof document === 'undefined') {
20 | return text => {
21 | // SSR approximation
22 | return fontSize * 0.6 * String(text).length
23 | }
24 | }
25 | const element = document.createElement('span')
26 | element.style.fontFamily = fontFamily
27 | element.style.fontSize = `${fontSize}px`
28 | element.style.lineHeight = lineHeight
29 | measurementDiv().appendChild(element)
30 | if (html) {
31 | return memoize(text => {
32 | element.innerHTML = text
33 | return element.getBoundingClientRect()[dimension]
34 | })
35 | }
36 | return memoize(text => {
37 | element.textContent = text
38 | return element.getBoundingClientRect()[dimension]
39 | })
40 | },
41 | ({ fontFamily, fontSize, lineHeight }, { dimension, html }) =>
42 | [fontFamily, fontSize, lineHeight, dimension, html].join()
43 | )
44 |
--------------------------------------------------------------------------------
/src/lib/timeFormat.js:
--------------------------------------------------------------------------------
1 | import { timeFormatLocale } from 'd3-time-format'
2 | import timeDefinition from 'd3-time-format/locale/de-CH'
3 |
4 | const locale = timeFormatLocale(timeDefinition)
5 |
6 | export const timeFormat = locale.format
7 | export const timeParse = locale.parse
8 |
--------------------------------------------------------------------------------
/src/lib/timeago.js:
--------------------------------------------------------------------------------
1 | const specs = [
2 | { n: 60, key: 'timeago/justNow' },
3 | { n: 60, key: 'timeago/minutes' },
4 | { n: 24, key: 'timeago/hours' },
5 | { n: 7, key: 'timeago/days' },
6 | { n: 365 / 7 / 12, key: 'timeago/weeks' },
7 | { n: 12, key: 'timeago/months', fn: 'round' },
8 | { n: 1, key: 'timeago/years' }
9 | ]
10 |
11 | // diff is in seconds, positive.
12 | export default (t, diff) => {
13 | let i = 0
14 | for (; i < specs.length && diff >= specs[i].n; i++) {
15 | diff /= specs[i].n
16 | }
17 |
18 | const spec = specs[Math.min(i, specs.length - 1)]
19 | return t.pluralize(spec.key, {
20 | count: Math[spec.fn || 'floor'](diff)
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/timeahead.js:
--------------------------------------------------------------------------------
1 | const specs = [
2 | { n: 60, key: 'timeAhead/justNow' },
3 | { n: 60, key: 'timeAhead/minutes' },
4 | { n: 24, key: 'timeAhead/hours' },
5 | { n: 7, key: 'timeAhead/days' },
6 | { n: 365 / 7 / 12, key: 'timeAhead/weeks' },
7 | { n: 12, key: 'timeAhead/months', fn: 'round' },
8 | { n: 1, key: 'timeAhead/years' }
9 | ]
10 |
11 | // diff is in seconds.
12 | export default (t, diff) => {
13 | diff = Math.abs(diff)
14 | let i = 0
15 | for (; i < specs.length && diff >= specs[i].n; i++) {
16 | diff /= specs[i].n
17 | }
18 |
19 | const spec = specs[Math.min(i, specs.length - 1)]
20 | return t.pluralize(spec.key, {
21 | count: Math[spec.fn || 'floor'](diff)
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/src/lib/timeduration.js:
--------------------------------------------------------------------------------
1 | const specs = [
2 | { n: 60, key: 'timeduration/seconds' },
3 | { n: 60, key: 'timeduration/minutes' },
4 | { n: 24, key: 'timeduration/hours' },
5 | { n: 7, key: 'timeduration/days' },
6 | { n: 365 / 7, key: 'timeduration/weeks' },
7 | { n: 52, key: 'timeduration/years' }
8 | ]
9 |
10 | // diff is in seconds, positive.
11 | export default (t, diff) => {
12 | let i = 0
13 | for (; i < specs.length && diff >= specs[i].n; i++) {
14 | diff /= specs[i].n
15 | }
16 |
17 | const spec = specs[Math.min(i, specs.length - 1)]
18 | return t(spec.key, {
19 | count: Math[spec.fn || 'floor'](diff)
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/useBoundingClientRect.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | /**
4 | * const [ref, { width, height }] = useBoundingClientRect([text])
5 | * {text}
6 | *
7 | * Make sure to pass any dependencies to the hook which may change the bounding
8 | * client rect. Without the deps this hook will only measure the initial size.
9 | */
10 | export const useBoundingClientRect = (deps = []) => {
11 | const [rect, setRect] = React.useState({})
12 |
13 | return [
14 | React.useCallback(el => {
15 | if (el) {
16 | setRect(el.getBoundingClientRect())
17 | }
18 | }, deps), // eslint-disable-line react-hooks/exhaustive-deps
19 | rect
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/useCurrentMinute.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 |
3 | let setters = []
4 |
5 | let timeout = null
6 | const startTimer = () => {
7 | const currentTime = new Date()
8 | const msLeft = 1000 - currentTime.getMilliseconds()
9 | const msToNextMinute = (60 - currentTime.getSeconds()) * 1000 + msLeft
10 | // ensure timer runs in new minute and with at least 5 seconds in between runs
11 | const msToNextRun = Math.max(msToNextMinute + 500, 5 * 1000)
12 | clearTimeout(timeout)
13 | timeout = setTimeout(() => {
14 | const now = Date.now()
15 | setters.forEach(setter => setter(now))
16 | startTimer()
17 | }, msToNextRun)
18 | }
19 |
20 | const addSetter = setter => {
21 | setters.push(setter)
22 | if (timeout === null) {
23 | startTimer()
24 | }
25 | }
26 | const rmSetter = setter => {
27 | setters = setters.filter(s => s !== setter)
28 | if (!setter.length) {
29 | clearTimeout(timeout)
30 | timeout = null
31 | }
32 | }
33 |
34 | export const useCurrentMinute = () => {
35 | const [now, setNow] = useState(() => Date.now())
36 | useEffect(() => {
37 | addSetter(setNow)
38 | return () => {
39 | rmSetter(setNow)
40 | }
41 | }, [])
42 | return now
43 | }
44 |
--------------------------------------------------------------------------------
/src/lib/useDebounce.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const useDebounce = (fastValue, ms = 400) => {
4 | const [slowValue, setSlowValue] = React.useState(fastValue)
5 |
6 | React.useEffect(() => {
7 | if (slowValue === fastValue) {
8 | return
9 | }
10 | const timer = setTimeout(() => setSlowValue(fastValue), ms)
11 | return () => {
12 | clearTimeout(timer)
13 | }
14 | }, [slowValue, fastValue, ms])
15 |
16 | return [slowValue]
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/useHeaderHeight.docs.md:
--------------------------------------------------------------------------------
1 | Utility hook passing the height of the header to its children by way of a context payload. Additionally, a list of media queries is provided to generate CSS rules.
2 |
3 | The hook requires a `HeaderHeightProvider` instance configured with a list of breakpoints (`minWidth`) and and height values (`headerHeight`) .
4 |
5 | Example using the `headerHeight` value programmatically:
6 |
7 | ```react
8 | const Child = () => {
9 |
10 | const [ headerHeight ] = useHeaderHeight()
11 |
12 | return (
13 |
14 | Lorem ipsum dolor sit amet.
15 |
16 | )
17 | }
18 |
19 |
20 |
21 |
22 | ```
23 |
24 | Example using the `mediaQuery`/`value` pairs to generate CSS:
25 |
26 | ```react
27 | const Child = () => {
28 |
29 | const [ _, rules ] = useHeaderHeight()
30 |
31 | const style = css(rules.reduce((acc, { mediaQuery, headerHeight }) =>
32 | Object.assign(
33 | acc,
34 | {[mediaQuery]: {paddingTop: headerHeight}}
35 | ), {})
36 | )
37 |
38 | return (
39 |
40 | Lorem ipsum dolor sit amet.
41 |
42 | )
43 | }
44 |
45 |
46 |
47 |
48 | ```
49 |
50 |
--------------------------------------------------------------------------------
/src/lib/useMediaQuery.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | /**
4 | * const matches = useMediaQuery("(min-width: 700px)")
5 | *
6 | * @param {string} queryInput
7 | * @returns {boolean}
8 | */
9 | export const useMediaQuery = queryInput => {
10 | /**
11 | * This is purely for convenience, so we can pass strings that start
12 | * with "@media ".
13 | */
14 | const query = queryInput.replace(/^@media /, '')
15 |
16 | const [matches, setMatches] = React.useState(() => {
17 | if (typeof window !== 'undefined') {
18 | return window.matchMedia(query).matches
19 | } else {
20 | return undefined
21 | }
22 | })
23 |
24 | React.useEffect(() => {
25 | const mql = window.matchMedia(query)
26 | setMatches(mql.matches)
27 |
28 | const onChange = ({ matches }) => {
29 | setMatches(matches)
30 | }
31 | mql.addListener(onChange)
32 | return () => {
33 | mql.removeListener(onChange)
34 | }
35 | }, [query, setMatches])
36 |
37 | return matches
38 | }
39 |
--------------------------------------------------------------------------------
/src/lib/usePrevious.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | /**
4 | * Gives you access to the previous value, used during the previous rendering of
5 | * the component.
6 | *
7 | * const MyComponent = ({ value }) => {
8 | * const previousValue = usePrevious(value)
9 | * return {value} - {previousValue}
10 | * }
11 | */
12 | export const usePrevious = value => {
13 | const ref = React.useRef()
14 |
15 | React.useEffect(() => {
16 | ref.current = value
17 | }, [value])
18 |
19 | return ref.current
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/warn.js:
--------------------------------------------------------------------------------
1 | export default (...args) => {
2 | try {
3 | console.warn(...args)
4 | } catch (e) {}
5 | }
6 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/templates.ts:
--------------------------------------------------------------------------------
1 | // Export article-schema
2 | export { default as createArticleSchema } from './templates/Article'
3 | export { extractImages, matchImagesParagraph } from './templates/Article/utils'
4 |
5 | // Export comment-schema
6 | export { default as createCommentWebSchema } from './templates/Comment/web'
7 | export { default as createCommentEmailSchema } from './templates/Comment/email'
8 |
9 | // Export dossier-schema
10 | export { default as createDossierSchema } from './templates/Dossier'
11 |
12 | // Export discussion-schema
13 | export { default as createDiscussionSchema } from './templates/Discussion'
14 |
15 | // Export editorial-newsletter-schema
16 | export { default as createNewsletterWebSchema } from './templates/EditorialNewsletter/web'
17 | export { default as createNewsletterEmailSchema } from './templates/EditorialNewsletter/email'
18 |
19 | // Export format-schema
20 | export { default as createFormatSchema } from './templates/Format'
21 |
22 | // Export front-schema
23 | export { default as createFrontSchema } from './templates/Front'
24 |
25 | // Export page-schema
26 | export { default as createPageSchema } from './templates/Page'
27 |
28 | // Export section-schema
29 | export { default as createSectionSchema } from './templates/Section'
30 |
31 | // Export Teaser components
32 | export { TeaserActiveDebates } from './components/TeaserActiveDebates'
33 | export { TeaserMyMagazine } from './components/TeaserMyMagazine'
34 |
--------------------------------------------------------------------------------
/src/templates/Article/Container.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useColorContext } from '../../components/Colors/useColorContext'
3 |
4 | const ArticleContainer = ({ children }) => {
5 | const [colorScheme] = useColorContext()
6 | return (
7 | {children}
8 | )
9 | }
10 |
11 | export default ArticleContainer
12 |
--------------------------------------------------------------------------------
/src/templates/Article/email/docs.md:
--------------------------------------------------------------------------------
1 | ```react|noSource
2 |
3 |
15 | {fixtures.BaB153Stub}
16 |
17 |
18 |
19 | {fixtures.ArticleStub}
20 |
21 |
22 | ```
--------------------------------------------------------------------------------
/src/templates/Article/email/index.js:
--------------------------------------------------------------------------------
1 | import { matchType } from 'mdast-react-render/lib/utils'
2 | import Container from '../../EditorialNewsletter/email/Container'
3 | import { editorialParagraphRule } from '../../shared/email/rules/paragraphRule'
4 | import centerRule from '../../shared/email/rules/centerRule'
5 | import {
6 | coverRule,
7 | edgeToEdgeFigureRule
8 | } from '../../shared/email/rules/figureRule'
9 | import titleBlockRule from '../../shared/email/rules/titleBlockRule'
10 |
11 | const articleEmailSchema = {
12 | rules: [
13 | {
14 | matchMdast: matchType('root'),
15 | component: Container,
16 | props: node => ({
17 | meta: node.meta || {},
18 | variableContext: {
19 | firstName: 'FNAME',
20 | lastName: 'LNAME',
21 | _mergeTags: true
22 | }
23 | }),
24 | rules: [
25 | editorialParagraphRule,
26 | titleBlockRule,
27 | centerRule,
28 | coverRule,
29 | edgeToEdgeFigureRule
30 | ]
31 | }
32 | ]
33 | }
34 |
35 | export default articleEmailSchema
36 |
--------------------------------------------------------------------------------
/src/templates/Article/test/render.test.js:
--------------------------------------------------------------------------------
1 | import { BaB153Stub, ArticleStub } from './article.stub'
2 | import { renderEmail } from 'mdast-react-render/lib/email'
3 | import { renderMdast } from 'mdast-react-render'
4 | import { parse } from '@orbiting/remark-preset'
5 | import articleEmailSchema from '../email'
6 | import createSchema from '../index'
7 |
8 | const babStub = parse(BaB153Stub)
9 | const articleStub = parse(ArticleStub)
10 |
11 | describe('chart utils test-suite', () => {
12 | it('templates/article: render web', () => {
13 | expect(() => {
14 | renderMdast(babStub, createSchema(), { MissingNode: false })
15 | }).not.toThrow()
16 | })
17 |
18 | it('templates/article: render bab as email', () => {
19 | expect(() => {
20 | renderEmail(babStub, articleEmailSchema, { MissingNode: false })
21 | }).not.toThrow()
22 | })
23 |
24 | it('templates/article: render article as email', () => {
25 | expect(() => {
26 | renderEmail(articleStub, articleEmailSchema, { MissingNode: false })
27 | }).not.toThrow()
28 | })
29 | })
30 |
--------------------------------------------------------------------------------
/src/templates/Comment/email.js:
--------------------------------------------------------------------------------
1 | import createCommentSchema from './schema'
2 |
3 | import {
4 | BlockCode,
5 | BlockQuote,
6 | BlockQuoteNested,
7 | BlockQuoteParagraph,
8 | Code,
9 | Container,
10 | Definition,
11 | Heading,
12 | Link,
13 | List,
14 | ListItem,
15 | Paragraph,
16 | StrikeThrough
17 | } from '../../components/CommentBody/email'
18 |
19 | const createCommentEmailSchema = ({ ...args } = {}) => {
20 | return createCommentSchema({
21 | BlockCode,
22 | BlockQuote,
23 | BlockQuoteNested,
24 | BlockQuoteParagraph,
25 | Code,
26 | Container,
27 | Definition,
28 | Heading,
29 | Link,
30 | List,
31 | ListItem,
32 | Paragraph,
33 | StrikeThrough,
34 | ...args
35 | })
36 | }
37 |
38 | export default createCommentEmailSchema
39 |
--------------------------------------------------------------------------------
/src/templates/Comment/index.js:
--------------------------------------------------------------------------------
1 | import schema from './web'
2 |
3 | export default schema
4 |
--------------------------------------------------------------------------------
/src/templates/Comment/web.js:
--------------------------------------------------------------------------------
1 | import createCommentSchema from './schema'
2 |
3 | import {
4 | CommentBodyBlockCode,
5 | CommentBodyBlockQuote,
6 | CommentBodyBlockQuoteNested,
7 | CommentBodyBlockQuoteParagraph,
8 | CommentBodyCode,
9 | CommentBodyDefinition,
10 | CommentBodyContainer,
11 | CommentBodyHeading,
12 | CommentBodyList,
13 | CommentBodyListItem,
14 | CommentBodyParagraph
15 | } from '../../components/CommentBody/web'
16 | import { Editorial } from '../../components/Typography'
17 |
18 | const createCommentWebSchema = ({ ...args } = {}) => {
19 | return createCommentSchema({
20 | BlockCode: CommentBodyBlockCode,
21 | BlockQuote: CommentBodyBlockQuote,
22 | BlockQuoteNested: CommentBodyBlockQuoteNested,
23 | BlockQuoteParagraph: CommentBodyBlockQuoteParagraph,
24 | Code: CommentBodyCode,
25 | Container: CommentBodyContainer,
26 | Definition: CommentBodyDefinition,
27 | Heading: CommentBodyHeading,
28 | Link: Editorial.A,
29 | List: CommentBodyList,
30 | ListItem: CommentBodyListItem,
31 | Paragraph: CommentBodyParagraph,
32 | StrikeThrough: Editorial.StrikeThrough,
33 | ...args
34 | })
35 | }
36 |
37 | export default createCommentWebSchema
38 |
--------------------------------------------------------------------------------
/src/templates/Discussion/docs.md:
--------------------------------------------------------------------------------
1 | A preconfigured article template for discussion pages.
2 |
3 | ```code|lang-jsx
4 | import createDiscussionSchema from '@project-r/styleguide/lib/templates/Discussion'
5 |
6 | const schema = createDiscussionSchema()
7 | ```
8 |
9 | `createDiscussionSchema` take the same keys as the article template.
10 |
11 | Defaults:
12 | - `repoPrefix`, `discussion-`
13 | - `getPath`, `/YYYY/MM/DD/:slug/diskussion`
14 | - `customMetaFields`, repo refs for `format`, `dossier` and `discussion` settings with a `commentsMaxLength`, `commentsMinInterval` and `discussionAnonymity` field.
15 |
--------------------------------------------------------------------------------
/src/templates/Dossier/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import { DossierTag } from '../../components/Dossier'
4 |
5 | import createArticleSchema from '../Article'
6 |
7 | const DefaultLink = ({ children }) => children
8 |
9 | const createDossierSchema = ({
10 | dossierLabel = 'Dossier',
11 | dossierHref = '/dossier',
12 | customMetaFields = [],
13 | series = false,
14 | darkMode,
15 | paynotes = true,
16 | Link = DefaultLink,
17 | titleBlockPrepend = null,
18 | getPath = ({ slug }) => `/dossier/${(slug || '').split('/').pop()}`,
19 | hasEmailTemplate = false,
20 | ...args
21 | } = {}) => {
22 | return createArticleSchema({
23 | repoPrefix: 'dossier-',
24 | getPath,
25 | hasEmailTemplate,
26 | titleBlockPrepend: [
27 | titleBlockPrepend,
28 |
29 | {dossierLabel}
30 |
31 | ],
32 | customMetaFields: [
33 | {
34 | label: 'Diskussion',
35 | key: 'discussion',
36 | ref: 'repo'
37 | },
38 | ...customMetaFields
39 | ],
40 | series,
41 | darkMode,
42 | paynotes,
43 | Link,
44 | ...args
45 | })
46 | }
47 |
48 | export default createDossierSchema
49 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/Blockquote.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontFamilies } from '../../../theme/fonts'
3 |
4 | const blockquoteStyle = {
5 | marginBottom: '30px'
6 | }
7 |
8 | const textStyle = {
9 | color: '#000',
10 | fontSize: '28px',
11 | lineHeight: '33px',
12 | fontFamily: fontFamilies.serifBold
13 | }
14 |
15 | const sourceStyle = {
16 | color: '#000',
17 | fontSize: '15px',
18 | lineHeight: '158%',
19 | fontFamily: fontFamilies.sansSerifRegular,
20 | fontStyle: 'normal'
21 | }
22 |
23 | export default ({ children }) => (
24 | {children}
25 | )
26 |
27 | export const BlockquoteText = ({ children }) => (
28 | {children}
29 | )
30 |
31 | export const BlockquoteSource = ({ children }) => (
32 | {children}
33 | )
34 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/Center.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontFamilies } from '../../../theme/fonts'
3 | import { Mso } from 'mdast-react-render/lib/email'
4 |
5 | export default ({ children }) => {
6 | return (
7 |
8 |
9 |
10 | {`
11 |
12 |
13 |
14 | `}
15 |
16 |
29 |
30 |
31 |
32 | {children}
33 |
34 |
35 |
36 |
37 |
38 | {`
39 |
40 |
41 |
42 | `}
43 |
44 |
45 |
46 | )
47 | }
48 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/Cover.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const CoverImage = ({ src, alt }) => {
4 | // skip rendering empty cover images
5 | // - some email clients show a prominent error when rendering an img tag without a src
6 | // - this happens for covers all the time because they currently can't be removed in publikator-frontend
7 | if (!src && !alt) {
8 | return null
9 | }
10 |
11 | return (
12 |
24 | )
25 | }
26 |
27 | export default ({ children }) => (
28 |
29 |
30 | {children}
31 |
32 |
33 | )
34 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/Figure.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontFamilies } from '../../../theme/fonts'
3 | import { imageResizeUrl } from 'mdast-react-render/lib/utils'
4 |
5 | export const Image = ({ src, alt, plain }) => (
6 |
21 | )
22 |
23 | export const Caption = ({ children, data }) => (
24 |
34 | {children}
35 |
36 | )
37 |
38 | export const Byline = ({ children, data }) => (
39 |
46 | {children}
47 |
48 | )
49 |
50 | export default ({ children }) => {children}
51 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/HR.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import colors from '../../../theme/colors'
3 |
4 | const hrStyle = {
5 | border: 0,
6 | height: 1,
7 | color: colors.divider,
8 | backgroundColor: colors.divider,
9 | marginTop: 30,
10 | marginBottom: 30
11 | }
12 |
13 | export default () =>
14 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/Headlines.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontFamilies } from '../../../theme/fonts'
3 |
4 | const h2Style = {
5 | fontFamily: fontFamilies.serifBold,
6 | fontSize: '23px',
7 | lineHeight: '130%',
8 | marginTop: '60px'
9 | }
10 |
11 | export const H2 = ({ children }) => {children}
12 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/List.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const ListItem = ({ children }) => {children}
4 |
5 | export default ({ children, data }) =>
6 | data.ordered ? {children} :
7 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/Paragraph.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontFamilies } from '../../../theme/fonts'
3 | import { Editorial } from '../../../components/Typography'
4 | import colors from '../../../theme/colors'
5 |
6 | export const paragraphStyle = {
7 | color: colors.text,
8 | fontSize: '19px',
9 | lineHeight: '158%',
10 | fontFamily: fontFamilies.serifRegular
11 | }
12 |
13 | export const linkStyle = {
14 | color: colors.text,
15 | textDecoration: 'underline',
16 | textDecorationSkip: 'ink'
17 | }
18 |
19 | export const Br = () =>
20 | export const A = ({ children, href, title }) => (
21 |
22 | {children}
23 |
24 | )
25 |
26 | // emails normally don't do glamor but
27 | // Editorial.fontRule is manually injected in ./Container
28 | export default ({ children }) => (
29 |
30 | {children}
31 |
32 | )
33 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/SubSup.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const Sub = ({ children }) => (
4 | {children}
5 | )
6 | export const Sup = ({ children }) => (
7 | {children}
8 | )
9 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/email/index.js:
--------------------------------------------------------------------------------
1 | import createNewsletterSchema from '../schema'
2 |
3 | import { H2 } from './Headlines'
4 | import Paragraph, { A } from './Paragraph'
5 | import Container from './Container'
6 | import Cover, { CoverImage } from './Cover'
7 | import Center from './Center'
8 | import Figure, { Image, Caption, Byline } from './Figure'
9 | import { Sub, Sup } from './SubSup'
10 | import { Button } from './Button'
11 | import List, { ListItem } from './List'
12 |
13 | const createNewsletterEmailSchema = ({ ...args } = {}) => {
14 | return createNewsletterSchema({
15 | H2,
16 | Paragraph,
17 | Container,
18 | Cover,
19 | CoverImage,
20 | Center,
21 | Figure,
22 | Image,
23 | Caption,
24 | Byline,
25 | Sub,
26 | Sup,
27 | Button,
28 | List,
29 | ListItem,
30 | A,
31 | ...args,
32 | variableContext: args.variableContext || {
33 | firstName: 'FNAME',
34 | lastName: 'LNAME',
35 | _mergeTags: true
36 | }
37 | })
38 | }
39 |
40 | export default createNewsletterEmailSchema
41 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/index.js:
--------------------------------------------------------------------------------
1 | import schema from './web'
2 |
3 | export default schema
4 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/web/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Button from '../../../components/Button'
3 |
4 | export default ({
5 | children,
6 | href,
7 | title,
8 | target,
9 | primary,
10 | block,
11 | attributes
12 | }) => (
13 | <>
14 |
23 | {children}
24 |
25 | {!block && }
26 | >
27 | )
28 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/web/Container.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { css } from 'glamor'
3 | import { fontStyles } from '../../../theme/fonts'
4 | import { useColorContext } from '../../../components/Colors/useColorContext'
5 |
6 | const styles = {
7 | container: {
8 | ...fontStyles.serifRegular,
9 | fontSize: 18,
10 | WebkitFontSmoothing: 'antialiased',
11 | width: '100%',
12 | margin: 0,
13 | padding: 0
14 | }
15 | }
16 |
17 | export default ({ children, attributes = {} }) => {
18 | const [colorScheme] = useColorContext()
19 | return (
20 |
26 | {children}
27 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/web/Figure.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Figure } from '../../../components/Figure'
3 |
4 | const StyledFigure = ({ children, plain }) => (
5 |
14 | {children}
15 |
16 | )
17 |
18 | export default StyledFigure
19 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/web/ListP.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export default ({ children, attributes = {} }) => (
4 | {children}
5 | )
6 |
--------------------------------------------------------------------------------
/src/templates/EditorialNewsletter/web/index.js:
--------------------------------------------------------------------------------
1 | import createNewsletterSchema from '../schema'
2 |
3 | import Container from './Container'
4 | import StyledFigure from './Figure'
5 | import Button from './Button'
6 | import ListP from './ListP'
7 |
8 | import Center from '../../../components/Center'
9 | import {
10 | FigureCover,
11 | FigureImage,
12 | FigureCaption,
13 | FigureByline
14 | } from '../../../components/Figure'
15 | import { Sub, Sup } from '../../../components/Typography'
16 | import { P, Subhead, A } from '../../../components/Typography/Editorial'
17 | import { List, ListItem } from '../../../components/List'
18 |
19 | const createNewsletterWebSchema = ({ ...args } = {}) => {
20 | return createNewsletterSchema({
21 | H2: Subhead,
22 | Paragraph: P,
23 | Container,
24 | Cover: FigureCover,
25 | CoverImage: FigureImage,
26 | Center,
27 | Figure: StyledFigure,
28 | Image: FigureImage,
29 | Caption: FigureCaption,
30 | Byline: FigureByline,
31 | Sub,
32 | Sup,
33 | Button: Button,
34 | List,
35 | ListItem,
36 | ListP,
37 | A,
38 | ...args
39 | })
40 | }
41 |
42 | export default createNewsletterWebSchema
43 |
--------------------------------------------------------------------------------
/src/templates/Format/docs.md:
--------------------------------------------------------------------------------
1 | A preconfigured article template for format pages.
2 |
3 | ```code|lang-jsx
4 | import createFormatSchema from '@project-r/styleguide/lib/templates/Format'
5 |
6 | const schema = createFormatSchema()
7 | ```
8 |
9 | `createFormatSchema` take the same keys as the article template.
10 |
11 | Defaults:
12 | - `repoPrefix`, `format-`
13 | - `getPath`, `/format/:slug`
14 | - `customMetaFields`, always adds repo refs for `discussion`, `dossier` and `format` settings with a `kind` (font) and `color` field.
15 | - `series`, false
16 | - `darkMode`, false
17 | - `metaBody`, true
18 |
19 | # Example
20 |
21 | ```react|noSource
22 | {`
23 |
24 | FIGURE
25 |
26 | \`\`\`
27 | {
28 | "size": "tiny"
29 | }
30 | \`\`\`
31 |
32 |  
33 |
34 |
35 |
36 | TITLE
37 |
38 | # Dada
39 |
40 |
41 |
42 | CENTER
43 |
44 | Er hörte leise Schritte hinter sich. Das bedeutete nichts Gutes. Wer würde ihm schon folgen, spät in der Nacht und dazu noch in dieser engen Gasse mitten im übel beleumundeten Hafenviertel?
45 |
46 | Gerade jetzt, wo er das Ding seines Lebens gedreht hatte und mit der Beute verschwinden wollte! Hatte einer seiner zahllosen Kollegen dieselbe Idee gehabt, ihn beobachtet und abgewartet, um ihn nun um die Früchte seiner Arbeit zu erleichtern?
47 |
48 |
49 |
50 | `}
51 | ```
52 |
--------------------------------------------------------------------------------
/src/templates/Page/index.js:
--------------------------------------------------------------------------------
1 | import createArticleSchema from '../Article'
2 |
3 | const DefaultLink = ({ children }) => children
4 |
5 | const createPageSchema = ({
6 | documentEditorOptions,
7 | customMetaFields = [],
8 | series = false,
9 | darkMode,
10 | paynotes = true,
11 | Link = DefaultLink,
12 | titleBlockPrepend = null,
13 | getPath = ({ slug }) => `/${(slug || '').split('/').pop()}`,
14 | metaHeadlines = true,
15 | skipContainer = false,
16 | skipCenter = false,
17 | hasEmailTemplate = false,
18 | ...args
19 | } = {}) => {
20 | return createArticleSchema({
21 | documentEditorOptions: {
22 | skipCredits: true,
23 | titleCenter: true
24 | },
25 | repoPrefix: 'page-',
26 | getPath,
27 | hasEmailTemplate,
28 | customMetaFields: [
29 | {
30 | label: 'Diskussion',
31 | key: 'discussion',
32 | ref: 'repo'
33 | },
34 | {
35 | label: 'Action Bar ausblenden',
36 | key: 'disableActionBar',
37 | ref: 'bool'
38 | },
39 | ...customMetaFields
40 | ],
41 | series,
42 | darkMode,
43 | paynotes,
44 | Link,
45 | metaHeadlines,
46 | skipContainer,
47 | skipCenter,
48 | ...args
49 | })
50 | }
51 |
52 | export default createPageSchema
53 |
--------------------------------------------------------------------------------
/src/templates/Section/docs.md:
--------------------------------------------------------------------------------
1 | A preconfigured article template for section pages.
2 |
3 | ```code|lang-jsx
4 | import createSectionSchema from '@project-r/styleguide/lib/templates/Section'
5 |
6 | const schema = createSectionSchema()
7 | ```
8 |
9 | `createSectionSchema` take the same keys as the article template.
10 |
11 | Defaults:
12 | - `repoPrefix`, `section-`
13 | - `getPath`, `/:slug`
14 | - `customMetaFields`, always adds repo refs for `discussion`, `dossier` and `format` settings with a `kind` (font) and `color` field.
15 | - `series`, false
16 | - `darkMode`, false
17 | - `metaBody`, true
18 |
19 | # Example
20 |
21 | ```react|noSource
22 | {`
23 |
24 | TITLE
25 |
26 | # Dada
27 |
28 |
29 |
30 | CENTER
31 |
32 | Er hörte leise Schritte hinter sich. Das bedeutete nichts Gutes. Wer würde ihm schon folgen, spät in der Nacht und dazu noch in dieser engen Gasse mitten im übel beleumundeten Hafenviertel?
33 |
34 | Gerade jetzt, wo er das Ding seines Lebens gedreht hatte und mit der Beute verschwinden wollte! Hatte einer seiner zahllosen Kollegen dieselbe Idee gehabt, ihn beobachtet und abgewartet, um ihn nun um die Früchte seiner Arbeit zu erleichtern?
35 |
36 |
37 |
38 | `}
39 | ```
40 |
--------------------------------------------------------------------------------
/src/templates/docs.js:
--------------------------------------------------------------------------------
1 | import { renderMdast } from 'mdast-react-render'
2 | import { parse } from '@orbiting/remark-preset'
3 |
4 | export const Markdown = ({ children, schema, rootData }) => {
5 | return renderMdast(
6 | {
7 | ...parse(children),
8 | ...rootData
9 | },
10 | schema
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/BlockQuote.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontStyles } from '../../../../theme/fonts'
3 |
4 | const BlockQuote = ({ children }) => {children}
5 |
6 | export default BlockQuote
7 |
8 | export const ParagraphWrapper = ({ children }) => (
9 |
14 | {children}
15 |
16 | )
17 |
18 | export const Paragraph = ({ children }) => (
19 |
30 | {children}
31 |
32 | )
33 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Caption.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontFamilies } from '../../../../theme/fonts'
3 |
4 | export const Caption = ({ children }) => (
5 |
15 | {children}
16 |
17 | )
18 |
19 | export const Byline = ({ children }) => (
20 |
28 | {children}
29 |
30 | )
31 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Center.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Mso } from 'mdast-react-render/lib/email'
3 | import { fontFamilies } from '../../../../theme/fonts'
4 |
5 | const Center = ({ children }) => {
6 | return (
7 |
8 |
9 |
10 | {`
11 |
12 |
13 |
14 | `}
15 |
16 |
29 |
30 |
31 |
32 | {children}
33 |
34 |
35 |
36 |
37 |
38 | {`
39 |
40 |
41 |
42 | `}
43 |
44 |
45 |
46 | )
47 | }
48 |
49 | export default Center
50 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Figure.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { imageResizeUrl } from 'mdast-react-render/lib/utils'
3 |
4 | export const Figure = ({ children }) => (
5 | {children}
6 | )
7 |
8 | export const Image = ({ src, alt, width, resize }) => (
9 |
26 | )
27 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Heading.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontStyles } from '../../../../theme/fonts'
3 |
4 | export const Heading2 = ({ children }) => (
5 |
13 | {children}
14 |
15 | )
16 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/HorizontalRule.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const HorizontalRule = () => (
4 |
13 | )
14 |
15 | export default HorizontalRule
16 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Link.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import colors from '../../../../theme/colors'
3 |
4 | export const Link = ({ children, href, title }) => (
5 |
14 | {children}
15 |
16 | )
17 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/List.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { fontStyles } from '../../../../theme/fonts'
3 |
4 | const List = ({ children, ordered, start }) => {
5 | if (ordered) return {children}
6 | return
7 | }
8 |
9 | export default List
10 |
11 | export const ListItem = ({ children }) => {children}
12 |
13 | export const ListParagraph = ({ children }) => (
14 |
22 | {children}
23 |
24 | )
25 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Note.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Interaction } from '../../../../components/Typography'
3 | import colors from '../../../../theme/colors'
4 | import { fontStyles } from '../../../../theme/fonts'
5 |
6 | export const Note = ({ children }) => <>{children}>
7 |
8 | export const NoteParagraph = ({ children, attributes, ...props }) => (
9 |
21 | {children}
22 |
23 | )
24 |
25 | export default NoteParagraph
26 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Paragraph.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import colors from '../../../../theme/colors'
3 | import { fontStyles } from '../../../../theme/fonts'
4 | import { Editorial, Interaction } from '../../../../components/Typography'
5 |
6 | const baseParagraphStyle = {
7 | color: colors.text,
8 | fontSize: '19px',
9 | lineHeight: '30px',
10 | margin: '30px 0'
11 | }
12 |
13 | export const EditorialParagraph = ({ children }) => (
14 |
18 | {children}
19 |
20 | )
21 |
22 | export const InteractionParagraph = ({ children }) => (
23 |
27 | {children}
28 |
29 | )
30 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Sub.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Sub = ({ children }) => (
4 | {children}
5 | )
6 |
7 | export default Sub
8 |
--------------------------------------------------------------------------------
/src/templates/shared/email/components/Sup.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Sup = ({ children }) => (
4 | {children}
5 | )
6 |
7 | export default Sup
8 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/articleCollectionRule.js:
--------------------------------------------------------------------------------
1 | import { matchZone } from 'mdast-react-render/lib/utils'
2 |
3 | const articleCollectionRule = {
4 | matchMdast: matchZone('ARTICLECOLLECTION'),
5 | component: () => null,
6 | isVoid: true
7 | }
8 |
9 | export default articleCollectionRule
10 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/blockQuoteRule.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import BlockQuote, {
3 | Paragraph,
4 | ParagraphWrapper
5 | } from '../components/BlockQuote'
6 | import {
7 | matchParagraph,
8 | matchType,
9 | matchZone
10 | } from 'mdast-react-render/lib/utils'
11 | import legendRule from './legendRules'
12 | import { inlineInteractionParagraphRules } from './paragraphRule'
13 |
14 | const blockQuoteRule = {
15 | matchMdast: matchZone('BLOCKQUOTE'),
16 | props: node => {
17 | return {
18 | isEmpty:
19 | node.children &&
20 | node.children.length === 1 &&
21 | !node.children[0].children
22 | }
23 | },
24 | component: ({ children, isEmpty }) => {
25 | if (isEmpty) return null
26 | return {children}
27 | },
28 | rules: [
29 | {
30 | matchMdast: matchType('blockquote'),
31 | component: ParagraphWrapper,
32 | rules: [
33 | {
34 | matchMdast: matchParagraph,
35 | component: Paragraph,
36 | rules: inlineInteractionParagraphRules
37 | }
38 | ]
39 | },
40 | legendRule
41 | ]
42 | }
43 |
44 | export default blockQuoteRule
45 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/centerRule.js:
--------------------------------------------------------------------------------
1 | import { matchZone } from 'mdast-react-render/lib/utils'
2 | import { editorialParagraphRule } from './paragraphRule'
3 | import inlineHeadingsRules from './inlineHeadingsRule'
4 | import blockQuoteRule from './blockQuoteRule'
5 | import hrRule from './hrRule'
6 | import Center from '../components/Center'
7 | import { figureRule } from './figureRule'
8 | import figureGroupRule from './figureGroupRule'
9 | import noteRule from './noteRule'
10 | import articleCollectionRule from './articleCollectionRule'
11 | import listRule from './listRule'
12 | import pullQuoteRule from './pullQuoteRule'
13 | import infoBoxRule from './infoBoxRule'
14 |
15 | const centerRule = {
16 | matchMdast: matchZone('CENTER'),
17 | component: Center,
18 | rules: [
19 | editorialParagraphRule,
20 | ...inlineHeadingsRules,
21 | hrRule,
22 | figureRule,
23 | figureGroupRule,
24 | listRule,
25 | blockQuoteRule,
26 | pullQuoteRule,
27 | noteRule,
28 | infoBoxRule,
29 | articleCollectionRule
30 | ]
31 | }
32 |
33 | export default centerRule
34 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/figureGroupRule.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { matchZone } from 'mdast-react-render/lib/utils'
3 | import { figureRule } from './figureRule'
4 | import legendRule from './legendRules'
5 |
6 | const figureGroupRule = {
7 | matchMdast: matchZone('FIGUREGROUP'),
8 | component: ({ children }) => {children}
,
9 | rules: [figureRule, legendRule]
10 | }
11 |
12 | export default figureGroupRule
13 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/hrRule.js:
--------------------------------------------------------------------------------
1 | import { matchType } from 'mdast-react-render/lib/utils'
2 | import HorizontalRule from '../components/HorizontalRule'
3 |
4 | const hrRule = {
5 | matchMdast: matchType('thematicBreak'),
6 | component: HorizontalRule
7 | }
8 |
9 | export default hrRule
10 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/inlineHeadingsRule.js:
--------------------------------------------------------------------------------
1 | import { matchHeading } from 'mdast-react-render/lib/utils'
2 | import { Heading2 } from '../components/Heading'
3 | import inlineRules from './inlineRules'
4 |
5 | const inlineHeadingsRules = [
6 | {
7 | matchMdast: matchHeading(2),
8 | component: Heading2,
9 | rules: inlineRules
10 | }
11 | ]
12 |
13 | export default inlineHeadingsRules
14 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/inlineRules.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { matchType } from 'mdast-react-render/lib/utils'
3 | import Sup from '../components/Sup'
4 | import Sub from '../components/Sub'
5 |
6 | const inlineRules = [
7 | {
8 | matchMdast: matchType('sup'),
9 | component: Sup
10 | },
11 | {
12 | matchMdast: matchType('sub'),
13 | component: Sub
14 | },
15 | {
16 | matchMdast: matchType('break'),
17 | component: () => ,
18 | isVoid: true
19 | }
20 | ]
21 |
22 | export default inlineRules
23 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/legendRules.js:
--------------------------------------------------------------------------------
1 | import { matchParagraph, matchType } from 'mdast-react-render/lib/utils'
2 | import { Byline, Caption } from '../components/Caption'
3 | import { linkRule } from './linkRule'
4 | import inlineRules from './inlineRules'
5 |
6 | const legendRule = {
7 | matchMdast: matchParagraph,
8 | component: Caption,
9 | rules: [
10 | {
11 | matchMdast: matchType('emphasis'),
12 | component: Byline
13 | },
14 | linkRule,
15 | inlineRules
16 | ]
17 | }
18 |
19 | export default legendRule
20 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/linkRule.js:
--------------------------------------------------------------------------------
1 | import { matchType } from 'mdast-react-render/lib/utils'
2 | import { Link } from '../components/Link'
3 |
4 | export const linkRule = {
5 | matchMdast: matchType('link'),
6 | component: Link,
7 | props: node => ({
8 | title: node.title,
9 | href: node.url
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/listRule.js:
--------------------------------------------------------------------------------
1 | import { matchParagraph, matchType } from 'mdast-react-render/lib/utils'
2 | import List, { ListItem, ListParagraph } from '../components/List'
3 | import { inlineEditorialParagraphRules } from './paragraphRule'
4 |
5 | const listRule = {
6 | matchMdast: matchType('list'),
7 | component: List,
8 | props: node => {
9 | return {
10 | ordered: node.ordered,
11 | start: node.start
12 | }
13 | },
14 | rules: [
15 | {
16 | matchMdast: matchType('listItem'),
17 | component: ListItem,
18 | rules: [
19 | {
20 | matchMdast: matchParagraph,
21 | // Custom paragraph required as the margin defers from the default variant
22 | component: ListParagraph,
23 | rules: inlineEditorialParagraphRules
24 | }
25 | ]
26 | }
27 | ]
28 | }
29 |
30 | export default listRule
31 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/noteRule.js:
--------------------------------------------------------------------------------
1 | import { matchParagraph, matchZone } from 'mdast-react-render/lib/utils'
2 | import { Note, NoteParagraph } from '../components/Note'
3 | import inlineRules from './inlineRules'
4 | import { linkRule } from './linkRule'
5 |
6 | const noteRule = {
7 | matchMdast: matchZone('NOTE'),
8 | component: Note,
9 | rules: [
10 | {
11 | matchMdast: matchParagraph,
12 | component: NoteParagraph,
13 | rules: [inlineRules, linkRule]
14 | }
15 | ]
16 | }
17 |
18 | export default noteRule
19 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/pullQuoteRule.js:
--------------------------------------------------------------------------------
1 | import { matchParagraph, matchZone } from 'mdast-react-render/lib/utils'
2 | import { matchFigure, matchLast } from '../../../Article/utils'
3 | import inlineRules from './inlineRules'
4 | import { linkRule } from './linkRule'
5 | import { getImageRules } from './figureRule'
6 | import {
7 | PullQuote,
8 | PullQuoteSource,
9 | PullQuoteText
10 | } from '../components/PullQuote'
11 | import { Figure } from '../components/Figure'
12 |
13 | const pullQuoteRule = {
14 | matchMdast: matchZone('QUOTE'),
15 | component: PullQuote,
16 | props: node => ({
17 | hasFigure: !!node.children.find(matchZone('FIGURE'))
18 | }),
19 | rules: [
20 | {
21 | matchMdast: matchZone('FIGURE'),
22 | component: Figure,
23 | rules: getImageRules({ forceWidth: '155px' })
24 | },
25 | {
26 | // PullQuote text
27 | matchMdast: (node, index, parent) =>
28 | matchParagraph(node) &&
29 | (index === 0 ||
30 | (index === 1 && matchFigure(parent.children[0])) ||
31 | !matchLast(node, index, parent)),
32 | component: PullQuoteText,
33 | rules: [...inlineRules, linkRule]
34 | },
35 | {
36 | // PullQuote Source
37 | matchMdast: (node, index, parent) =>
38 | matchParagraph(node) && matchLast(node, index, parent),
39 | component: PullQuoteSource,
40 | rules: [...inlineRules, linkRule]
41 | }
42 | ]
43 | }
44 |
45 | export default pullQuoteRule
46 |
--------------------------------------------------------------------------------
/src/templates/shared/email/rules/teaserGroupRule.js:
--------------------------------------------------------------------------------
1 | import { matchZone } from 'mdast-react-render/lib/utils'
2 |
3 | const teaserGroupRule = {
4 | matchMdast: matchZone('TEASERGROUP'),
5 | component: () => null,
6 | isVoid: true
7 | }
8 |
9 | export default teaserGroupRule
10 |
--------------------------------------------------------------------------------
/src/templates/shared/email/util/ImageSizingUtil.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Get the width of an image based on it's size and the displayWidth
3 | * @param size
4 | * @param displayWidth
5 | * @param fill
6 | * @returns {string}
7 | */
8 | export function getImageSize({ size = '', displayWidth, fill }) {
9 | switch (size) {
10 | case 'tiny':
11 | return '325px'
12 | default:
13 | if (fill) return '100%'
14 | return displayWidth
15 | }
16 | }
17 |
18 | export function isPixelSize(value) {
19 | return /^([0-9]+)px$/.test(value)
20 | }
21 |
22 | export function isRelativeSize(value) {
23 | return /^([0-9]+)%$/.test(value)
24 | }
25 |
--------------------------------------------------------------------------------
/src/templates/shared/email/util/NodeDepthUtil.js:
--------------------------------------------------------------------------------
1 | import { matchType } from 'mdast-react-render/lib/utils'
2 |
3 | /**
4 | * Get the depth relative to closest ancestor that matches the given matcher
5 | *
6 | * If node is a direct child -> 0
7 | * Node is a nested child -> >= 1
8 | * If no parent matches -> -1
9 | *
10 | * @param ancestors
11 | * @param matcher
12 | * @returns {number}
13 | */
14 | export function getNodeDepth(ancestors, matcher = matchType('root')) {
15 | let depth = 0
16 | for (let i = 0; i < ancestors.length; i++) {
17 | const node = ancestors[i]
18 | if (matcher(node)) return depth
19 | depth += 1
20 | }
21 | return -1
22 | }
23 |
--------------------------------------------------------------------------------
/src/theme/env.js:
--------------------------------------------------------------------------------
1 | const ENV =
2 | (typeof window !== 'undefined' &&
3 | (window.ENV || (window.__NEXT_DATA__ && window.__NEXT_DATA__.env))) ||
4 | process.env ||
5 | {}
6 |
7 | const SG_ENV = {}
8 |
9 | const SG_PREFIX = /^(REACT_APP_)?SG_(.+)$/
10 |
11 | Object.keys(ENV).forEach(key => {
12 | const matches = key.match(SG_PREFIX)
13 | if (matches) {
14 | SG_ENV[matches[2]] = ENV[key]
15 | }
16 | })
17 |
18 | export default SG_ENV
19 |
20 | export const getJson = key => (SG_ENV[key] && JSON.parse(SG_ENV[key])) || {}
21 |
--------------------------------------------------------------------------------
/src/theme/mediaQueries.js:
--------------------------------------------------------------------------------
1 | export const mBreakPoint = 768
2 | export const lBreakPoint = 1025
3 |
4 | export const onlyS = `@media only screen and (max-width: ${mBreakPoint - 1}px)`
5 | export const mUp = `@media only screen and (min-width: ${mBreakPoint}px)`
6 | export const lUp = `@media only screen and (min-width: ${lBreakPoint}px)`
7 |
--------------------------------------------------------------------------------
/src/theme/zIndex.docs.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | ```code|lang-js
4 | import {zIndex} from '@project-r/styleguide'
5 |
6 | const style = css({
7 | zIndex: zIndex.overlay
8 | })
9 | ```
10 |
11 | ## Values
12 |
13 | ```table
14 | rows:
15 | - Name: dropdown
16 | Value: 5
17 | - Name: overlay
18 | Value: 50
19 | ```
20 |
--------------------------------------------------------------------------------
/src/theme/zIndex.js:
--------------------------------------------------------------------------------
1 | export default {
2 | dropdown: 5,
3 | frontImage: 1,
4 | callout: 20,
5 | overlay: 50,
6 | foreground: 100
7 | }
8 |
--------------------------------------------------------------------------------
/static.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": "build/",
3 | "https_only": true,
4 | "routes": {
5 | "/**": "index.html"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tsconfig",
3 | "compilerOptions": {
4 | "target": "es5",
5 | "lib": [
6 | "dom",
7 | "dom.iterable",
8 | "esnext"
9 | ],
10 | "allowJs": true,
11 | "skipLibCheck": true,
12 | "strict": false,
13 | "forceConsistentCasingInFileNames": true,
14 | "noEmit": true,
15 | "esModuleInterop": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "jsx": "preserve",
21 | "allowSyntheticDefaultImports": true,
22 | "declaration": true,
23 | "declarationDir": "dist/types"
24 | },
25 | "include": [
26 | "src"
27 | ],
28 | "exclude": [
29 | "node_modules",
30 | "dist"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------