mirror of
https://github.com/noodlapp/noodl-docs.git
synced 2026-03-07 17:43:27 +01:00
Initial commit
Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: Michael Cartner <32543275+michaelcartner@users.noreply.github.com>
This commit is contained in:
BIN
src/assets/fonts/PolySans-Bulky.woff
Normal file
BIN
src/assets/fonts/PolySans-Bulky.woff
Normal file
Binary file not shown.
BIN
src/assets/fonts/PolySans-BulkyItalic.woff
Normal file
BIN
src/assets/fonts/PolySans-BulkyItalic.woff
Normal file
Binary file not shown.
BIN
src/assets/fonts/PolySans-Median.woff
Normal file
BIN
src/assets/fonts/PolySans-Median.woff
Normal file
Binary file not shown.
BIN
src/assets/fonts/PolySans-MedianItalic.woff
Normal file
BIN
src/assets/fonts/PolySans-MedianItalic.woff
Normal file
Binary file not shown.
BIN
src/assets/fonts/PolySans-Neutral.woff
Normal file
BIN
src/assets/fonts/PolySans-Neutral.woff
Normal file
Binary file not shown.
BIN
src/assets/fonts/PolySans-NeutralItalic.woff
Normal file
BIN
src/assets/fonts/PolySans-NeutralItalic.woff
Normal file
Binary file not shown.
BIN
src/assets/fonts/PolySans-Slim.woff
Normal file
BIN
src/assets/fonts/PolySans-Slim.woff
Normal file
Binary file not shown.
BIN
src/assets/fonts/PolySans-SlimItalic.woff
Normal file
BIN
src/assets/fonts/PolySans-SlimItalic.woff
Normal file
Binary file not shown.
65
src/blocks/GuideListing.tsx
Normal file
65
src/blocks/GuideListing.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React from 'react'
|
||||
import { getGuideListing } from '../../static/data/guides.js'
|
||||
import featuredGuides from '../../static/data/featuredGuides.json'
|
||||
import { Grid, GridLayout } from '../components/layout/Grid/Grid'
|
||||
import { Section } from '../components/layout/Section/Section'
|
||||
import { GuideCard } from '../components/cards/GuideCard/GuideCard'
|
||||
|
||||
interface GuideListingProps {
|
||||
title: string
|
||||
hasNoLink: boolean
|
||||
isFeaturedOnly: boolean
|
||||
}
|
||||
|
||||
export function GuideListing({
|
||||
title,
|
||||
hasNoLink,
|
||||
isFeaturedOnly,
|
||||
}: GuideListingProps) {
|
||||
if (isFeaturedOnly) {
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
linkHref={!hasNoLink ? 'docs/learn' : null}
|
||||
linkLabel={!hasNoLink ? 'View all' : null}
|
||||
>
|
||||
<Grid layout={GridLayout.Half} hasEqualHeightItems>
|
||||
{featuredGuides.map((guide) => {
|
||||
return (
|
||||
<GuideCard
|
||||
key={guide.title}
|
||||
imageUrl={guide.imageUrl}
|
||||
title={guide.title}
|
||||
description={guide.description}
|
||||
href={guide.href}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Grid>
|
||||
</Section>
|
||||
)
|
||||
} else {
|
||||
return getGuideListing().map((category) => (
|
||||
<Section
|
||||
key={category.key}
|
||||
title={category.title}
|
||||
linkHref={null}
|
||||
linkLabel={null}
|
||||
>
|
||||
<Grid layout={GridLayout.Half} hasEqualHeightItems>
|
||||
{category.items.map((guide) => {
|
||||
return (
|
||||
<GuideCard
|
||||
key={guide.key}
|
||||
imageUrl={guide.imageUrl}
|
||||
title={guide.title}
|
||||
description={guide.description}
|
||||
href={guide.href}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Grid>
|
||||
</Section>
|
||||
))
|
||||
}
|
||||
}
|
||||
68
src/blocks/HeroBlock.tsx
Normal file
68
src/blocks/HeroBlock.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import React from 'react'
|
||||
import { Section } from '../components/layout/Section/Section'
|
||||
import { Title, TitleSize } from '../components/typography/Title/Title'
|
||||
import { Text } from '../components/typography/Text/Text'
|
||||
import { Grid, GridLayout } from '../components/layout/Grid/Grid'
|
||||
import {
|
||||
YouTubeEmbed,
|
||||
YouTubeEmbedProps,
|
||||
} from '../components/common/YouTubeEmbed/YouTubeEmbed'
|
||||
import { LinkCard, LinkCardProps } from '../components/cards/LinkCard/LinkCard'
|
||||
|
||||
interface IHeroBlockYoutube extends YouTubeEmbedProps {
|
||||
type: 'youtube'
|
||||
}
|
||||
|
||||
interface IHeroBlockLink extends LinkCardProps {
|
||||
type: 'link'
|
||||
}
|
||||
|
||||
interface HeroBlockProps {
|
||||
title: string
|
||||
text: string
|
||||
gridItems: (IHeroBlockLink | IHeroBlockYoutube)[]
|
||||
}
|
||||
|
||||
export function HeroBlock({ title, text, gridItems }: HeroBlockProps) {
|
||||
return (
|
||||
<Section hasNoHeader>
|
||||
<Title size={TitleSize.Large} headingLevel={1}>
|
||||
{title}
|
||||
</Title>
|
||||
|
||||
<Text>{text}</Text>
|
||||
|
||||
<Grid layout={GridLayout.Grid_2_1_1} hasEqualHeightItems>
|
||||
{gridItems.map((item, i) => {
|
||||
switch (item.type) {
|
||||
case 'youtube':
|
||||
return (
|
||||
<YouTubeEmbed
|
||||
key={i + item.videoId}
|
||||
videoId={item.videoId}
|
||||
/>
|
||||
)
|
||||
|
||||
case 'link':
|
||||
return (
|
||||
<LinkCard
|
||||
key={i + item.label}
|
||||
colorVariable={item.colorVariable}
|
||||
label={item.label}
|
||||
href={item.href}
|
||||
backgroundImage={item.backgroundImage}
|
||||
playIcon={item.playIcon}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return (
|
||||
<Text key={i}>
|
||||
Error: Wrong item type provided.
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</Grid>
|
||||
</Section>
|
||||
)
|
||||
}
|
||||
29
src/blocks/LinkButtonGrid.tsx
Normal file
29
src/blocks/LinkButtonGrid.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
ButtonCard,
|
||||
ButtonCardProps,
|
||||
} from '../components/cards/ButtonCard/ButtonCard'
|
||||
import { Grid, GridLayout } from '../components/layout/Grid/Grid'
|
||||
import { Section } from '../components/layout/Section/Section'
|
||||
|
||||
interface LinkButtonGridProps {
|
||||
title?: string
|
||||
links: ButtonCardProps[]
|
||||
}
|
||||
|
||||
export function LinkButtonGrid({ title, links }: LinkButtonGridProps) {
|
||||
return (
|
||||
<Section title={title} linkLabel={null}>
|
||||
<Grid layout={GridLayout.Thirds} hasEqualHeightItems>
|
||||
{links.map((link) => (
|
||||
<ButtonCard
|
||||
key={link.href}
|
||||
title={link.title}
|
||||
href={link.href}
|
||||
onClick={link.onClick}
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
</Section>
|
||||
)
|
||||
}
|
||||
55
src/blocks/ModuleListing.tsx
Normal file
55
src/blocks/ModuleListing.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import { Section } from '../components/layout/Section/Section';
|
||||
import { Grid, GridLayout } from '../components/layout/Grid/Grid';
|
||||
import modules from '../../static/library/modules/index.json';
|
||||
import featuredModuleIds from '../../static/data/featuredModules.json';
|
||||
import { ModuleCard } from '../components/cards/ModuleCard/ModuleCard';
|
||||
|
||||
const featuredModules = featuredModuleIds.map((moduleId) =>
|
||||
modules.find((module) => module.label === moduleId)
|
||||
);
|
||||
|
||||
interface ModuleListingProps {
|
||||
title: string;
|
||||
hasNoLink?: boolean;
|
||||
isFeaturedOnly: boolean;
|
||||
}
|
||||
|
||||
export function ModuleListing({
|
||||
title,
|
||||
hasNoLink,
|
||||
isFeaturedOnly,
|
||||
}: ModuleListingProps) {
|
||||
const renderedModules = isFeaturedOnly ? featuredModules : modules;
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
linkHref={hasNoLink ? undefined : '/library/modules/overview'}
|
||||
linkLabel={hasNoLink ? false : 'View all'}
|
||||
>
|
||||
<Grid layout={GridLayout.Thirds} hasEqualHeightItems>
|
||||
{renderedModules.map((module) => {
|
||||
if (!module) return null;
|
||||
|
||||
return (
|
||||
<ModuleCard
|
||||
key={module.label}
|
||||
title={module.label}
|
||||
description={module.desc}
|
||||
readMoreUrl={module.docs}
|
||||
thumbUrl={module.icon}
|
||||
importArgs={{
|
||||
path: module.project,
|
||||
options: {
|
||||
thumb: module.icon,
|
||||
name: module.label,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
55
src/blocks/PrefabListing.tsx
Normal file
55
src/blocks/PrefabListing.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import { Section } from '../components/layout/Section/Section';
|
||||
import { Grid, GridLayout } from '../components/layout/Grid/Grid';
|
||||
import modules from '../../static/library/prefabs/index.json';
|
||||
import featuredModuleIds from '../../static/data/featuredPrefabs.json';
|
||||
import { ModuleCard } from '../components/cards/ModuleCard/ModuleCard';
|
||||
|
||||
const featuredModules = featuredModuleIds.map((moduleId) =>
|
||||
modules.find((module) => module.label === moduleId)
|
||||
);
|
||||
|
||||
interface ModuleListingProps {
|
||||
title: string;
|
||||
hasNoLink?: boolean;
|
||||
isFeaturedOnly: boolean;
|
||||
}
|
||||
|
||||
export function PrefabListing({
|
||||
title,
|
||||
hasNoLink,
|
||||
isFeaturedOnly,
|
||||
}: ModuleListingProps) {
|
||||
const renderedModules = isFeaturedOnly ? featuredModules : modules;
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
linkHref={hasNoLink ? undefined : '/library/prefabs/overview'}
|
||||
linkLabel={hasNoLink ? false : 'View all'}
|
||||
>
|
||||
<Grid layout={GridLayout.Thirds} hasEqualHeightItems>
|
||||
{renderedModules.map((module) => {
|
||||
if (!module) return null;
|
||||
|
||||
return (
|
||||
<ModuleCard
|
||||
key={module.label}
|
||||
title={module.label}
|
||||
description={module.desc}
|
||||
readMoreUrl={module.docs}
|
||||
thumbUrl={module.icon}
|
||||
importArgs={{
|
||||
path: module.project,
|
||||
options: {
|
||||
thumb: module.icon,
|
||||
name: module.label,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
37
src/blocks/ProjectListing.tsx
Normal file
37
src/blocks/ProjectListing.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { Grid, GridLayout } from '../components/layout/Grid/Grid'
|
||||
import { Section } from '../components/layout/Section/Section'
|
||||
import featuredProjects from '../../static/data/featuredProjects.json'
|
||||
import projects from '../../static/data/projects.json'
|
||||
import { ProjectCard } from '../components/cards/ProjectCard/ProjectCard'
|
||||
|
||||
export function ProjectListing({ title, hasNoLink, isFeaturedOnly }) {
|
||||
const renderedProjects = useMemo(
|
||||
() => (isFeaturedOnly ? featuredProjects : projects),
|
||||
[isFeaturedOnly]
|
||||
)
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
linkHref={hasNoLink ? null : 'library/examples/overview'}
|
||||
linkLabel={hasNoLink ? null : 'View all'}
|
||||
>
|
||||
<Grid layout={GridLayout.Thirds} hasEqualHeightItems>
|
||||
{renderedProjects.map((project) => {
|
||||
return (
|
||||
<ProjectCard
|
||||
key={project.title}
|
||||
title={project.title}
|
||||
description={project.description}
|
||||
backend={project.backend}
|
||||
href={project.href}
|
||||
imageUrl={project.imageUrl}
|
||||
project={project.project}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Grid>
|
||||
</Section>
|
||||
)
|
||||
}
|
||||
49
src/blocks/VideoListing.tsx
Normal file
49
src/blocks/VideoListing.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
import { VideoLinkCard } from '../components/cards/VideoLinkCard/VideoLinkCard'
|
||||
import { Grid, GridLayout } from '../components/layout/Grid/Grid'
|
||||
import { Section } from '../components/layout/Section/Section'
|
||||
import videos from '../../static/data/youtubeVideos.json'
|
||||
import featuredVideoIds from '../../static/data/featuredVideos.json'
|
||||
|
||||
const featuredVideos = featuredVideoIds.map((id) =>
|
||||
videos.find((video) => video.videoId === id)
|
||||
)
|
||||
|
||||
interface VideoListingProps {
|
||||
title: string
|
||||
hasNoLink?: boolean
|
||||
isFeaturedOnly: boolean
|
||||
}
|
||||
|
||||
export function VideoListing({
|
||||
title,
|
||||
hasNoLink,
|
||||
isFeaturedOnly,
|
||||
}: VideoListingProps) {
|
||||
const renderedVideos = isFeaturedOnly ? featuredVideos : videos
|
||||
return (
|
||||
<Section
|
||||
title={title}
|
||||
linkHref={
|
||||
hasNoLink
|
||||
? null
|
||||
: 'https://www.youtube.com/channel/UCLkJ8XYV1J1RqrZKY-o1YWg'
|
||||
}
|
||||
linkLabel={hasNoLink ? false : 'View all'}
|
||||
>
|
||||
<Grid layout={GridLayout.Half} hasEqualHeightItems>
|
||||
{renderedVideos.map((video) => {
|
||||
return (
|
||||
<VideoLinkCard
|
||||
key={video.videoId}
|
||||
title={video.title}
|
||||
description={video.description}
|
||||
videoLength={video.videoLength}
|
||||
videoId={video.videoId}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Grid>
|
||||
</Section>
|
||||
)
|
||||
}
|
||||
105
src/components/cards/ArticleCard/ArticleCard.module.scss
Normal file
105
src/components/cards/ArticleCard/ArticleCard.module.scss
Normal file
@@ -0,0 +1,105 @@
|
||||
@use '../../../css/utils/mixins.scss';
|
||||
|
||||
.Root {
|
||||
display: flex;
|
||||
|
||||
&.is-horisontal {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&.is-vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.ImageContainer {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
background-color: #ffffff;
|
||||
|
||||
.Root.is-horisontal & {
|
||||
@include mixins.aspect-ratio(1, 1);
|
||||
width: 156px;
|
||||
}
|
||||
|
||||
.Root.is-vertical & {
|
||||
@include mixins.aspect-ratio(354, 200);
|
||||
}
|
||||
}
|
||||
|
||||
.Image {
|
||||
background-position: center;
|
||||
position: absolute;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
.Root.is-vertical &:not(.has-no-padding) {
|
||||
background-size: contain;
|
||||
top: 12px;
|
||||
bottom: 12px;
|
||||
left: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.Root.is-horisontal & {
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.Content {
|
||||
background-color: var(--doc-color-noodl-black-light);
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.Root.is-horisontal & {
|
||||
padding: 25px 32px;
|
||||
}
|
||||
|
||||
.Root.is-vertical & {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.PrimaryAction {
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin-right: 24px;
|
||||
border-bottom: none !important;
|
||||
font-family: var(--doc-font-title);
|
||||
|
||||
span {
|
||||
color: var(--doc-color-noodl-orange);
|
||||
transition: color var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default);
|
||||
|
||||
&:hover {
|
||||
color: var(--doc-color-noodl-orange-140);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.SecondaryAction {
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
border-bottom: none !important;
|
||||
font-family: var(--doc-font-title);
|
||||
|
||||
span {
|
||||
color: var(--doc-color-text);
|
||||
transition: color var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default);
|
||||
|
||||
&:hover {
|
||||
color: var(--doc-color-noodl-orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/components/cards/ArticleCard/ArticleCard.tsx
Normal file
105
src/components/cards/ArticleCard/ArticleCard.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser'
|
||||
import clsx from 'clsx'
|
||||
import React, { useMemo } from 'react'
|
||||
import { TextSize, Text } from '../../typography/Text/Text'
|
||||
import { Title, TitleSize } from '../../typography/Title/Title'
|
||||
import css from './ArticleCard.module.scss'
|
||||
|
||||
export enum ArticleCardLayout {
|
||||
Horisontal = 'is-horisontal',
|
||||
Vertical = 'is-vertical',
|
||||
}
|
||||
|
||||
interface IActionSlot {
|
||||
label: string
|
||||
onClick?: () => void
|
||||
href?: string
|
||||
}
|
||||
|
||||
export interface ArticleCardProps {
|
||||
layout?: ArticleCardLayout
|
||||
title: string
|
||||
description: string
|
||||
hasNoPaddingInThumb?: boolean
|
||||
primaryAction: IActionSlot
|
||||
secondaryAction?: IActionSlot
|
||||
imageUrl?: string
|
||||
}
|
||||
|
||||
export function ArticleCard({
|
||||
layout = ArticleCardLayout.Vertical,
|
||||
title,
|
||||
description,
|
||||
hasNoPaddingInThumb,
|
||||
primaryAction,
|
||||
secondaryAction,
|
||||
imageUrl,
|
||||
}: ArticleCardProps) {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
|
||||
const isBrowser = useIsBrowser()
|
||||
|
||||
const thumbUrl = useMemo(() => {
|
||||
return !isBrowser
|
||||
? null
|
||||
: location.protocol +
|
||||
'//' +
|
||||
location.host +
|
||||
siteConfig.baseUrl.slice(0, -1) +
|
||||
(imageUrl[0]==='/'?imageUrl:('/'+imageUrl))
|
||||
}, [isBrowser])
|
||||
|
||||
return (
|
||||
<article className={clsx(css['Root'], css[layout])}>
|
||||
<div className={css['ImageContainer']}>
|
||||
{thumbUrl && (
|
||||
<div
|
||||
className={clsx(
|
||||
css['Image'],
|
||||
hasNoPaddingInThumb && css['has-no-padding']
|
||||
)}
|
||||
style={{ backgroundImage: `url(${thumbUrl})` }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={css['Content']}>
|
||||
<div>
|
||||
<header>
|
||||
<Title size={TitleSize.Smaller} headingLevel={1}>
|
||||
{title}
|
||||
</Title>
|
||||
</header>
|
||||
<Text size={TextSize.Small}>{description}</Text>
|
||||
</div>
|
||||
|
||||
<footer className={css['Footer']}>
|
||||
{Boolean(primaryAction) && (
|
||||
<a
|
||||
className={css['PrimaryAction']}
|
||||
href={primaryAction.href}
|
||||
onClick={primaryAction.onClick}
|
||||
>
|
||||
<Text size={TextSize.Small} isSpan>
|
||||
{primaryAction.label}
|
||||
</Text>
|
||||
</a>
|
||||
)}
|
||||
|
||||
{Boolean(secondaryAction) && (
|
||||
<a
|
||||
className={css['SecondaryAction']}
|
||||
href={secondaryAction.href}
|
||||
onClick={secondaryAction.onClick}
|
||||
>
|
||||
<Text size={TextSize.Small} isSpan>
|
||||
{secondaryAction.label}
|
||||
</Text>
|
||||
</a>
|
||||
)}
|
||||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
20
src/components/cards/ButtonCard/ButtonCard.module.scss
Normal file
20
src/components/cards/ButtonCard/ButtonCard.module.scss
Normal file
@@ -0,0 +1,20 @@
|
||||
@use '../../../css/utils/typography.scss';
|
||||
|
||||
.Root {
|
||||
@include typography.h2;
|
||||
font-size: 26px;
|
||||
line-height: 1.1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 32px 24px 24px;
|
||||
height: 100%;
|
||||
min-height: 180px;
|
||||
border-bottom: none !important;
|
||||
background-color: var(--doc-color-noodl-green);
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--doc-color-noodl-green-180);
|
||||
}
|
||||
}
|
||||
19
src/components/cards/ButtonCard/ButtonCard.tsx
Normal file
19
src/components/cards/ButtonCard/ButtonCard.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import Link from '@docusaurus/Link'
|
||||
import React from 'react'
|
||||
import css from './ButtonCard.module.scss'
|
||||
|
||||
export interface ButtonCardProps {
|
||||
title: string
|
||||
href?: string
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
export function ButtonCard({ title, href, onClick }: ButtonCardProps) {
|
||||
const Tag = href ? Link : 'button'
|
||||
|
||||
return (
|
||||
<Tag className={css['Root']} to={href} onClick={onClick}>
|
||||
{title}
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
1
src/components/cards/ButtonCard/index.ts
Normal file
1
src/components/cards/ButtonCard/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './ButtonCard'
|
||||
32
src/components/cards/GuideCard/GuideCard.tsx
Normal file
32
src/components/cards/GuideCard/GuideCard.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import React from 'react'
|
||||
import { ArticleCard, ArticleCardLayout } from '../ArticleCard/ArticleCard'
|
||||
|
||||
interface GuideCardProps {
|
||||
title: string
|
||||
description: string
|
||||
href: string
|
||||
imageUrl?: string
|
||||
}
|
||||
|
||||
export function GuideCard({
|
||||
title,
|
||||
description,
|
||||
href,
|
||||
imageUrl,
|
||||
}: GuideCardProps) {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
|
||||
return (
|
||||
<ArticleCard
|
||||
layout={ArticleCardLayout.Horisontal}
|
||||
primaryAction={{
|
||||
label: 'Read guide',
|
||||
href: siteConfig.baseUrl.slice(0, -1) + href,
|
||||
}}
|
||||
title={title}
|
||||
description={description}
|
||||
imageUrl={imageUrl}
|
||||
/>
|
||||
)
|
||||
}
|
||||
42
src/components/cards/LinkCard/LinkCard.module.scss
Normal file
42
src/components/cards/LinkCard/LinkCard.module.scss
Normal file
@@ -0,0 +1,42 @@
|
||||
@use '../../../css/utils/typography.scss';
|
||||
|
||||
.Root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default);
|
||||
background-color: var(--doc-color-noodl-white);
|
||||
}
|
||||
|
||||
&:hover:before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.IconContainer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.Label {
|
||||
@include typography.h3;
|
||||
color: var(--doc-color-noodl-black) !important;
|
||||
max-width: 131px;
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
52
src/components/cards/LinkCard/LinkCard.tsx
Normal file
52
src/components/cards/LinkCard/LinkCard.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import Link from '@docusaurus/Link'
|
||||
import React, { useMemo } from 'react'
|
||||
import css from './LinkCard.module.scss'
|
||||
import PlayIcon from '../../../../static/img/icons/play-black.svg'
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser'
|
||||
|
||||
export interface LinkCardProps {
|
||||
href: string
|
||||
colorVariable: string
|
||||
backgroundImage: string
|
||||
label: string
|
||||
playIcon?: boolean
|
||||
}
|
||||
|
||||
export function LinkCard({
|
||||
href,
|
||||
colorVariable,
|
||||
backgroundImage,
|
||||
label,
|
||||
playIcon
|
||||
}: LinkCardProps) {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
const isBrowser = useIsBrowser()
|
||||
|
||||
const bgUrl = useMemo(() => {
|
||||
return isBrowser && backgroundImage
|
||||
? location.protocol +
|
||||
'//' +
|
||||
location.host +
|
||||
siteConfig.baseUrl.slice(0, -1) +
|
||||
backgroundImage
|
||||
: null
|
||||
}, [isBrowser])
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={css['Root']}
|
||||
style={{
|
||||
backgroundColor: `var(${colorVariable})`,
|
||||
backgroundImage: bgUrl ? `url(${bgUrl})` : null,
|
||||
}}
|
||||
to={href}
|
||||
>
|
||||
<span className={css['Label']}>{label}</span>
|
||||
|
||||
{(playIcon===undefined || playIcon === true) && (<div className={css['IconContainer']}>
|
||||
<PlayIcon />
|
||||
</div>)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
1
src/components/cards/LinkCard/index.ts
Normal file
1
src/components/cards/LinkCard/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './LinkCard'
|
||||
41
src/components/cards/ModuleCard/ModuleCard.tsx
Normal file
41
src/components/cards/ModuleCard/ModuleCard.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser'
|
||||
import React from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import {
|
||||
importIntoNoodl,
|
||||
ImportIntoNoodlArgs,
|
||||
} from '../../../utils/importIntoNoodl'
|
||||
import { ArticleCard, ArticleCardLayout } from '../ArticleCard/ArticleCard'
|
||||
|
||||
interface ModuleCardProps {
|
||||
thumbUrl: string
|
||||
title: string
|
||||
description: string
|
||||
readMoreUrl: string
|
||||
importArgs: ImportIntoNoodlArgs
|
||||
}
|
||||
|
||||
export function ModuleCard({
|
||||
thumbUrl,
|
||||
title,
|
||||
description,
|
||||
readMoreUrl,
|
||||
importArgs,
|
||||
}: ModuleCardProps) {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
|
||||
return (
|
||||
<ArticleCard
|
||||
title={title}
|
||||
description={description}
|
||||
hasNoPaddingInThumb
|
||||
imageUrl={thumbUrl}
|
||||
layout={ArticleCardLayout.Vertical}
|
||||
primaryAction={{
|
||||
label: 'Read more',
|
||||
href: siteConfig.baseUrl.slice(0, -1) + readMoreUrl,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
51
src/components/cards/NodeCard/NodeCard.module.scss
Normal file
51
src/components/cards/NodeCard/NodeCard.module.scss
Normal file
@@ -0,0 +1,51 @@
|
||||
.Root {
|
||||
display: block;
|
||||
padding: 13px 18px;
|
||||
font-weight: 600;
|
||||
color: var(--doc-color-noodl-white) !important;
|
||||
border: 2px solid transparent !important;
|
||||
position: relative;
|
||||
line-height: 1;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--doc-color-noodl-white);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&.has-hoverstate:hover {
|
||||
border: 2px solid var(--doc-color-noodl-white) !important;
|
||||
|
||||
&:after {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-visual {
|
||||
background-color: var(--doc-color-visual-node);
|
||||
}
|
||||
|
||||
&.is-data {
|
||||
background-color: var(--doc-color-data-node);
|
||||
}
|
||||
|
||||
&.is-custom {
|
||||
background-color: var(--doc-color-custom-node);
|
||||
}
|
||||
|
||||
&.is-logic {
|
||||
background-color: var(--doc-color-logic-node);
|
||||
}
|
||||
|
||||
&.is-connection {
|
||||
background-color: var(--doc-color-connection-node);
|
||||
}
|
||||
}
|
||||
35
src/components/cards/NodeCard/NodeCard.tsx
Normal file
35
src/components/cards/NodeCard/NodeCard.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import Link from '@docusaurus/Link'
|
||||
import clsx from 'clsx'
|
||||
import React from 'react'
|
||||
import css from './NodeCard.module.scss'
|
||||
|
||||
export enum NodeType {
|
||||
Visual = 'is-visual',
|
||||
Data = 'is-data',
|
||||
Custom = 'is-custom',
|
||||
Logic = 'is-logic',
|
||||
Connection = 'is-connection',
|
||||
}
|
||||
|
||||
export interface NodeCardProps {
|
||||
nodeType: NodeType
|
||||
label: string
|
||||
docUrl?: string
|
||||
}
|
||||
|
||||
export function NodeCard({ nodeType, label, docUrl }: NodeCardProps) {
|
||||
const Tag = docUrl ? Link : 'div'
|
||||
|
||||
return (
|
||||
<Tag
|
||||
className={clsx(
|
||||
css['Root'],
|
||||
css[nodeType],
|
||||
Boolean(docUrl) && css['has-hoverstate']
|
||||
)}
|
||||
to={docUrl}
|
||||
>
|
||||
{label}
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
1
src/components/cards/NodeCard/index.ts
Normal file
1
src/components/cards/NodeCard/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './NodeCard'
|
||||
46
src/components/cards/ProjectCard/ProjectCard.tsx
Normal file
46
src/components/cards/ProjectCard/ProjectCard.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import React from 'react'
|
||||
import { importIntoNoodl } from '../../../utils/importIntoNoodl'
|
||||
import { ArticleCard, ArticleCardLayout } from '../ArticleCard/ArticleCard'
|
||||
|
||||
interface ProjectCardProps {
|
||||
title: string
|
||||
description: string
|
||||
href: string
|
||||
imageUrl: string
|
||||
project: string
|
||||
backend: string
|
||||
}
|
||||
|
||||
export function ProjectCard({
|
||||
title,
|
||||
description,
|
||||
href,
|
||||
imageUrl,
|
||||
project,
|
||||
backend,
|
||||
}: ProjectCardProps) {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
|
||||
return (
|
||||
<ArticleCard
|
||||
layout={ArticleCardLayout.Vertical}
|
||||
title={title}
|
||||
description={description}
|
||||
imageUrl={imageUrl}
|
||||
primaryAction={{
|
||||
label: 'Download project',
|
||||
onClick: () =>
|
||||
importIntoNoodl(project, {
|
||||
name: title,
|
||||
cf: backend,
|
||||
thumb: imageUrl,
|
||||
}),
|
||||
}}
|
||||
secondaryAction={{
|
||||
label: 'Read more',
|
||||
href: siteConfig.baseUrl.slice(0, -1) + href,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
75
src/components/cards/VideoLinkCard/VideoLinkCard.module.scss
Normal file
75
src/components/cards/VideoLinkCard/VideoLinkCard.module.scss
Normal file
@@ -0,0 +1,75 @@
|
||||
@use '../../../css/utils/mixins.scss';
|
||||
@use '../../../css/utils/typography.scss';
|
||||
|
||||
$_hover-background: var(--doc-color-noodl-black-light);
|
||||
|
||||
.Root {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
position: relative;
|
||||
outline: 10px solid transparent;
|
||||
transition: outline var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default);
|
||||
|
||||
&:hover {
|
||||
outline: 10px solid $_hover-background;
|
||||
}
|
||||
}
|
||||
|
||||
.Thumb {
|
||||
@include mixins.aspect-ratio(560, 315);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: calc(50% - 24px);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.Details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: calc(50% + 24px);
|
||||
padding-left: 24px;
|
||||
transition: background-color var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default);
|
||||
|
||||
.Root:hover & {
|
||||
background-color: $_hover-background;
|
||||
}
|
||||
}
|
||||
|
||||
.Title {
|
||||
@include typography.h4;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.Description {
|
||||
@include typography.body-small;
|
||||
}
|
||||
|
||||
.VideoLength {
|
||||
font-size: 12px;
|
||||
padding-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left: 5px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.Link {
|
||||
font-size: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
47
src/components/cards/VideoLinkCard/VideoLinkCard.tsx
Normal file
47
src/components/cards/VideoLinkCard/VideoLinkCard.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import React from 'react'
|
||||
import css from './VideoLinkCard.module.scss'
|
||||
import PlayIcon from '../../../../static/img/icons/play-white.svg'
|
||||
|
||||
export interface VideoLinkCardProps {
|
||||
videoId: string
|
||||
title: string
|
||||
description: string
|
||||
videoLength: string
|
||||
}
|
||||
|
||||
export function VideoLinkCard({
|
||||
videoId,
|
||||
title,
|
||||
description,
|
||||
videoLength,
|
||||
}: VideoLinkCardProps) {
|
||||
return (
|
||||
<article className={css['Root']}>
|
||||
<div
|
||||
className={css['Thumb']}
|
||||
style={{
|
||||
backgroundImage: `url(http://img.youtube.com/vi/${videoId}/0.jpg)`,
|
||||
}}
|
||||
/>
|
||||
<div className={css['Details']}>
|
||||
<div>
|
||||
<h1 className={css['Title']}>{title}</h1>
|
||||
<p className={css['Description']}>{description}</p>
|
||||
</div>
|
||||
<p className={css['VideoLength']}>
|
||||
<PlayIcon />
|
||||
<span>{videoLength}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<a
|
||||
className={css['Link']}
|
||||
href={`https://www.youtube.com/watch?v=${videoId}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Watch video
|
||||
</a>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
1
src/components/cards/VideoLinkCard/index.ts
Normal file
1
src/components/cards/VideoLinkCard/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './VideoLinkCard'
|
||||
15
src/components/common/YouTubeEmbed/YouTubeEmbed.module.scss
Normal file
15
src/components/common/YouTubeEmbed/YouTubeEmbed.module.scss
Normal file
@@ -0,0 +1,15 @@
|
||||
@use '../../../css/utils/mixins.scss';
|
||||
|
||||
.Root {
|
||||
@include mixins.aspect-ratio(560, 315);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
iframe {
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
22
src/components/common/YouTubeEmbed/YouTubeEmbed.tsx
Normal file
22
src/components/common/YouTubeEmbed/YouTubeEmbed.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from 'react'
|
||||
import css from './YouTubeEmbed.module.scss'
|
||||
|
||||
export interface YouTubeEmbedProps {
|
||||
videoId: string
|
||||
}
|
||||
|
||||
export function YouTubeEmbed({ videoId }: YouTubeEmbedProps) {
|
||||
return (
|
||||
<div className={css['Root']}>
|
||||
<iframe
|
||||
width="840"
|
||||
height="472"
|
||||
src={`https://www.youtube.com/embed/${videoId}`}
|
||||
title="YouTube video player"
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
49
src/components/copytoclipboardbutton.js
Normal file
49
src/components/copytoclipboardbutton.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
|
||||
function fallbackCopyTextToClipboard(text) {
|
||||
var textArea = document.createElement('textarea');
|
||||
textArea.value = text;
|
||||
|
||||
// Avoid scrolling to bottom
|
||||
textArea.style.top = '0';
|
||||
textArea.style.left = '0';
|
||||
textArea.style.position = 'fixed';
|
||||
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
var successful = document.execCommand('copy');
|
||||
var msg = successful ? 'successful' : 'unsuccessful';
|
||||
console.log('Fallback: Copying text command was ' + msg);
|
||||
} catch (err) {
|
||||
console.error('Fallback: Oops, unable to copy', err);
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
}
|
||||
function copyTextToClipboard(text) {
|
||||
if (!navigator.clipboard) {
|
||||
fallbackCopyTextToClipboard(text);
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(text).then(
|
||||
function () {
|
||||
console.log('Async: Copying to clipboard was successful!');
|
||||
},
|
||||
function (err) {
|
||||
console.error('Async: Could not copy text: ', err);
|
||||
}
|
||||
);
|
||||
}
|
||||
function copyJsonToClipboard(json) {
|
||||
copyTextToClipboard(JSON.stringify(json));
|
||||
}
|
||||
|
||||
export default function CopyToClipboardButton(props) {
|
||||
return (
|
||||
<button className="ndl-copy-nodes-button" onClick={() => copyJsonToClipboard(props.json)}></button>
|
||||
)
|
||||
}
|
||||
|
||||
29
src/components/importbutton.tsx
Normal file
29
src/components/importbutton.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import { importIntoNoodl } from '../utils/importIntoNoodl'
|
||||
|
||||
interface ImportButtonProps {
|
||||
zip: string
|
||||
name: string
|
||||
thumb: string
|
||||
cf: string
|
||||
}
|
||||
|
||||
export default function ImportButton({
|
||||
zip,
|
||||
name,
|
||||
thumb,
|
||||
cf,
|
||||
}: ImportButtonProps) {
|
||||
return (
|
||||
<button
|
||||
className="ndl-import-button"
|
||||
onClick={() =>
|
||||
importIntoNoodl(zip, {
|
||||
name,
|
||||
thumb,
|
||||
cf,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
6
src/components/layout/Container/Container.module.scss
Normal file
6
src/components/layout/Container/Container.module.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
.Root {
|
||||
max-width: var(--ifm-container-width-xl);
|
||||
padding: var(--doc-size-page-top-spacing-l)
|
||||
var(--ifm-navbar-padding-horizontal);
|
||||
margin: 0 auto;
|
||||
}
|
||||
10
src/components/layout/Container/Container.tsx
Normal file
10
src/components/layout/Container/Container.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import React, { ReactNode } from 'react'
|
||||
import css from './Container.module.scss'
|
||||
|
||||
export interface ContainerProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export function Container({ children }: ContainerProps) {
|
||||
return <div className={css['Root']}>{children}</div>
|
||||
}
|
||||
103
src/components/layout/Grid/Grid.module.scss
Normal file
103
src/components/layout/Grid/Grid.module.scss
Normal file
@@ -0,0 +1,103 @@
|
||||
$_gutter: 24px;
|
||||
|
||||
.Root {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
flex-wrap: wrap;
|
||||
margin-top: $_gutter * -1;
|
||||
margin-left: $_gutter * -1;
|
||||
|
||||
&.has-equal-height-items {
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.GridItem {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
padding-top: $_gutter;
|
||||
padding-left: $_gutter;
|
||||
pointer-events: none;
|
||||
|
||||
> * {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.Root.has-equal-height-items & > * {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Root.is-grid-half > & {
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: 850px) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.Root.is-grid-thirds > & {
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
@media (min-width: 900px) {
|
||||
width: 33.333%;
|
||||
}
|
||||
}
|
||||
|
||||
.Root.is-grid-fifths > & {
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: 350px) {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
@media (min-width: 520px) {
|
||||
width: 33.333%;
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
@media (min-width: 1250px) {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.Root.is-grid-2-1-1 > & {
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: 400px) {
|
||||
&:nth-child(3n-2) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:not(:nth-child(3n-2)) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
&:nth-child(3n-2) {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
&:not(:nth-child(3n-2)) {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Root.is-grid-2-3 > & {
|
||||
&:nth-child(odd) {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/components/layout/Grid/Grid.tsx
Normal file
46
src/components/layout/Grid/Grid.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import clsx from 'clsx'
|
||||
import React, { ReactNode, useMemo } from 'react'
|
||||
import css from './Grid.module.scss'
|
||||
|
||||
export enum GridLayout {
|
||||
Half = 'is-grid-half',
|
||||
Thirds = 'is-grid-thirds',
|
||||
Fifths = 'is-grid-fifths',
|
||||
Grid_2_1_1 = 'is-grid-2-1-1',
|
||||
Grid_2_3 = 'is-grid-2-3',
|
||||
}
|
||||
|
||||
export interface GridProps {
|
||||
layout: GridLayout
|
||||
children: ReactNode
|
||||
hasEqualHeightItems?: boolean
|
||||
}
|
||||
|
||||
export function Grid({ layout, children, hasEqualHeightItems }: GridProps) {
|
||||
const childArray = useMemo(
|
||||
() => (Array.isArray(children) ? children : [children]),
|
||||
[children]
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
css['Root'],
|
||||
css[layout],
|
||||
hasEqualHeightItems && css['has-equal-height-items']
|
||||
)}
|
||||
>
|
||||
{/* using i is not the best, but not all items will have ids.
|
||||
if items orders or rendering get all weird or buggy this is the cause */}
|
||||
{childArray.map((child, i) => {
|
||||
if (child === null) return null
|
||||
|
||||
return (
|
||||
<div key={i} className={css['GridItem']}>
|
||||
{child}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
22
src/components/layout/Section/Section.module.scss
Normal file
22
src/components/layout/Section/Section.module.scss
Normal file
@@ -0,0 +1,22 @@
|
||||
@use '../../../css/utils/typography.scss';
|
||||
|
||||
.Root {
|
||||
padding-bottom: 120px;
|
||||
}
|
||||
|
||||
.Header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.Link {
|
||||
@include typography.h3;
|
||||
|
||||
color: var(--doc-color-noodl-white-65) !important; // ajajaj
|
||||
|
||||
&:hover {
|
||||
color: var(--doc-color-noodl-white) !important;
|
||||
border-bottom-color: transparent !important;
|
||||
}
|
||||
}
|
||||
42
src/components/layout/Section/Section.tsx
Normal file
42
src/components/layout/Section/Section.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import Link from '@docusaurus/Link'
|
||||
import React, { ReactNode } from 'react'
|
||||
import { Title, TitleProps, TitleSize } from '../../typography/Title/Title'
|
||||
import css from './Section.module.scss'
|
||||
|
||||
export interface SectionProps {
|
||||
title?: TitleProps['children']
|
||||
titleSize?: TitleProps['size']
|
||||
linkLabel?: string | false
|
||||
linkHref?: string
|
||||
children: ReactNode
|
||||
|
||||
hasNoHeader?: boolean
|
||||
}
|
||||
|
||||
export function Section({
|
||||
title,
|
||||
titleSize,
|
||||
linkLabel = 'View all',
|
||||
linkHref,
|
||||
children,
|
||||
|
||||
hasNoHeader,
|
||||
}: SectionProps) {
|
||||
return (
|
||||
<section className={css['Root']}>
|
||||
{!hasNoHeader && (
|
||||
<div className={css['Header']}>
|
||||
<Title size={titleSize}>{title}</Title>
|
||||
|
||||
{Boolean(linkLabel) && (
|
||||
<Link className={css['Link']} href={linkHref}>
|
||||
{linkLabel}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={css['Content']}>{children}</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
1
src/components/layout/Section/index.ts
Normal file
1
src/components/layout/Section/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Section'
|
||||
36
src/components/typography/Text/Text.module.scss
Normal file
36
src/components/typography/Text/Text.module.scss
Normal file
@@ -0,0 +1,36 @@
|
||||
@use '../../../css/utils/typography.scss';
|
||||
|
||||
.Root {
|
||||
font-family: var(--doc-font-text);
|
||||
margin-block-start: 0;
|
||||
margin-block-end: 0;
|
||||
max-width: 860px;
|
||||
|
||||
[data-theme='dark'] & {
|
||||
@extend %font-smoothing;
|
||||
}
|
||||
|
||||
&.is-size-default {
|
||||
@include typography.body;
|
||||
|
||||
&.has-bottom-spacing {
|
||||
@include typography.body-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-size-small {
|
||||
@include typography.body-small;
|
||||
|
||||
&.has-bottom-spacing {
|
||||
@include typography.body-small-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
&.is-centered {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
47
src/components/typography/Text/Text.tsx
Normal file
47
src/components/typography/Text/Text.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import clsx from 'clsx'
|
||||
import React, { CSSProperties, ReactNode } from 'react'
|
||||
import css from './Text.module.scss'
|
||||
|
||||
export enum TextSize {
|
||||
Default = 'default',
|
||||
Small = 'small',
|
||||
}
|
||||
|
||||
export interface TextProps {
|
||||
children?: ReactNode
|
||||
className?: string
|
||||
size?: TextSize
|
||||
style?: CSSProperties
|
||||
|
||||
hasBottomSpacing?: boolean
|
||||
isSpan?: boolean
|
||||
isCentered?: boolean
|
||||
}
|
||||
|
||||
export function Text({
|
||||
children,
|
||||
size = TextSize.Default,
|
||||
style,
|
||||
className,
|
||||
hasBottomSpacing = true,
|
||||
isSpan,
|
||||
isCentered,
|
||||
}: TextProps) {
|
||||
const Tag = isSpan ? 'span' : 'p'
|
||||
|
||||
return (
|
||||
<Tag
|
||||
className={clsx(
|
||||
css['Root'],
|
||||
css[`is-size-${size}`],
|
||||
isSpan && css['is-inline'],
|
||||
isCentered && css['is-centered'],
|
||||
hasBottomSpacing && css['has-bottom-spacing'],
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
1
src/components/typography/Text/index.ts
Normal file
1
src/components/typography/Text/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Text'
|
||||
42
src/components/typography/Title/Title.module.scss
Normal file
42
src/components/typography/Title/Title.module.scss
Normal file
@@ -0,0 +1,42 @@
|
||||
@use '../../../css/utils/typography.scss';
|
||||
|
||||
.Root {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
|
||||
&.is-size-default {
|
||||
@include typography.h2;
|
||||
|
||||
&.has-bottom-spacing {
|
||||
@include typography.h2-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-size-large {
|
||||
@include typography.h1;
|
||||
|
||||
&.has-bottom-spacing {
|
||||
@include typography.h1-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-size-small {
|
||||
@include typography.h3;
|
||||
|
||||
&.has-bottom-spacing {
|
||||
@include typography.h3-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-size-smaller {
|
||||
@include typography.h4;
|
||||
|
||||
&.has-bottom-spacing {
|
||||
@include typography.h4-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-centered {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
43
src/components/typography/Title/Title.tsx
Normal file
43
src/components/typography/Title/Title.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import clsx from 'clsx'
|
||||
import React, { ReactNode } from 'react'
|
||||
import css from './Title.module.scss'
|
||||
|
||||
export enum TitleSize {
|
||||
Default = 'default',
|
||||
Large = 'large',
|
||||
Small = 'small',
|
||||
Smaller = 'smaller',
|
||||
}
|
||||
|
||||
export interface TitleProps {
|
||||
children?: ReactNode
|
||||
size?: TitleSize
|
||||
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6
|
||||
|
||||
hasBottomSpacing?: boolean
|
||||
isCentered?: boolean
|
||||
}
|
||||
|
||||
export function Title({
|
||||
children,
|
||||
size = TitleSize.Default,
|
||||
headingLevel = 2,
|
||||
hasBottomSpacing = true,
|
||||
isCentered,
|
||||
}: TitleProps) {
|
||||
// hahahaha wtf
|
||||
const Tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' = `h${headingLevel}`
|
||||
|
||||
return (
|
||||
<Tag
|
||||
className={clsx(
|
||||
css['Root'],
|
||||
css[`is-size-${size}`],
|
||||
isCentered && css['is-centered'],
|
||||
hasBottomSpacing && css['has-bottom-spacing']
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
1
src/components/typography/Title/index.ts
Normal file
1
src/components/typography/Title/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './Title'
|
||||
74
src/css/custom.css
Normal file
74
src/css/custom.css
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Any CSS included here will be global. The classic template
|
||||
* bundles Infima by default. Infima is a CSS framework designed to
|
||||
* work well for content-centric websites.
|
||||
*/
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap');
|
||||
|
||||
@font-face {
|
||||
font-family: 'PolySans';
|
||||
src: url('../assets/fonts/PolySans-Bulky.woff');
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
}
|
||||
|
||||
/* You can override the default Infima variables here. */
|
||||
:root {
|
||||
--ifm-color-primary: var(--doc-color-noodl-orange);
|
||||
--ifm-color-primary-dark: var(--doc-color-noodl-orange-180);
|
||||
--ifm-color-primary-darker: var(--doc-color-noodl-orange-160);
|
||||
--ifm-color-primary-darkest: var(--doc-color-noodl-orange-140);
|
||||
--ifm-color-primary-light: var(--doc-color-noodl-orange-80);
|
||||
--ifm-color-primary-lighter: var(--doc-color-noodl-orange-60);
|
||||
--ifm-color-primary-lightest: var(--doc-color-noodl-orange-40);
|
||||
|
||||
--ifm-link-color: var(--doc-color-noodl-blue-40);
|
||||
--ifm-link-hover-color: var(--doc-color-noodl-blue-60);
|
||||
|
||||
--ifm-leading: 0;
|
||||
|
||||
--ifm-code-font-size: 95%;
|
||||
--ifm-container-width-xl: 1100px;
|
||||
--ifm-container-width: 670px;
|
||||
}
|
||||
|
||||
.docusaurus-highlight-code-line {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
display: block;
|
||||
margin: 0 calc(-1 * var(--ifm-pre-padding));
|
||||
padding: 0 var(--ifm-pre-padding);
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 100%;
|
||||
line-height: 1.5;
|
||||
color: var(--doc-color-text);
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
background-color: var(--doc-color-noodl-black-dark);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
}
|
||||
|
||||
* {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
a {
|
||||
transition: all 0.1s linear;
|
||||
}
|
||||
|
||||
.github-corner {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
326
src/css/markdown.scss
Normal file
326
src/css/markdown.scss
Normal file
@@ -0,0 +1,326 @@
|
||||
@use '../css/utils/typography.scss';
|
||||
|
||||
.markdown h1:first-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.theme-doc-markdown,
|
||||
.markdown,
|
||||
.markdown section {
|
||||
margin: 0 auto;
|
||||
|
||||
> h1 {
|
||||
@include typography.h1;
|
||||
|
||||
&:not(:last-child) {
|
||||
@include typography.h1-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
> h2 {
|
||||
@include typography.h2;
|
||||
|
||||
&:not(:last-child) {
|
||||
@include typography.h2-bottom-spacing;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
@include typography.h2-top-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
> h3 {
|
||||
@include typography.h3;
|
||||
|
||||
&:not(:last-child) {
|
||||
@include typography.h3-bottom-spacing;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
@include typography.h3-top-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
> h4 {
|
||||
@include typography.h4;
|
||||
|
||||
&:not(:last-child) {
|
||||
@include typography.h4-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
> p,
|
||||
> ol,
|
||||
> ul {
|
||||
@include typography.body;
|
||||
|
||||
&:not(:last-child) {
|
||||
@include typography.body-bottom-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
> p,
|
||||
> ol,
|
||||
> ul {
|
||||
max-width: 830px;
|
||||
}
|
||||
|
||||
> a {
|
||||
border-bottom: 1px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 1px solid var(--ifm-link-hover-color);
|
||||
}
|
||||
}
|
||||
|
||||
.prism-code {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
p code {
|
||||
border-radius: 5px;
|
||||
padding-left: 4px;
|
||||
padding-right: 2px;
|
||||
background-color: rgb(52, 56, 72);
|
||||
letter-spacing: 0.03em;
|
||||
font-weight: normal;
|
||||
|
||||
@extend %font-smoothing;
|
||||
}
|
||||
|
||||
> table {
|
||||
margin-bottom: 40px;
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****** COPY TO CLIPBOARD ******/
|
||||
.docsify-copy-code-button {
|
||||
font-size: 0.7em !important;
|
||||
}
|
||||
|
||||
/****** IMAGES ******/
|
||||
.ndl-images {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ndl-image {
|
||||
height: auto;
|
||||
margin: 5px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.ndl-image.small {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.ndl-image.med {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.ndl-image.large {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ndl-image-with-background,
|
||||
.ndl-video {
|
||||
background: linear-gradient(
|
||||
45deg,
|
||||
var(--doc-color-noodl-orange),
|
||||
var(--doc-color-noodl-blue)
|
||||
);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
margin-bottom: 40px;
|
||||
|
||||
p {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
img,
|
||||
video {
|
||||
height: auto;
|
||||
|
||||
border-radius: 4px;
|
||||
box-shadow: -5px 5px 30px -5px #38341caa, 5px -5px 30px -5px #203c2caa;
|
||||
}
|
||||
}
|
||||
|
||||
.ndl-video {
|
||||
video {
|
||||
margin: 2.5%;
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
.ndl-image-with-background {
|
||||
video,
|
||||
img {
|
||||
width: 50%;
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
&.xl {
|
||||
img,
|
||||
video {
|
||||
width: 95%;
|
||||
margin: 2.5%;
|
||||
}
|
||||
}
|
||||
&.l {
|
||||
video,
|
||||
img {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
&.s {
|
||||
video,
|
||||
img {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ndl-image-with-background .ndl-copy-nodes-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: black;
|
||||
box-shadow: 0px 0px 10px 0px #38341ceaa;
|
||||
}
|
||||
|
||||
.tutorial-img-link:hover {
|
||||
opacity: 75%;
|
||||
}
|
||||
|
||||
/****** COPY NODES BUTTON ******/
|
||||
.ndl-copy-nodes-button {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
right: 0;
|
||||
overflow: visible;
|
||||
padding: 0.65em 0.8em;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
outline: 0;
|
||||
font-size: 10px;
|
||||
background: #808080;
|
||||
background: var(--doc-color-noodl-orange);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
transition: transform 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.ndl-copy-nodes-button:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.ndl-copy-nodes-button::after {
|
||||
content: 'COPY NODES';
|
||||
}
|
||||
|
||||
.ndl-copy-nodes-button:active {
|
||||
background: var(--doc-color-noodl-orange-140);
|
||||
}
|
||||
|
||||
.ndl-import-button {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
right: 0;
|
||||
overflow: visible;
|
||||
padding: 0.65em 0.8em;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
outline: 0;
|
||||
font-size: 14px;
|
||||
background: var(--doc-color-noodl-orange);
|
||||
color: var(--doc-color-noodl-black-darkest);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ndl-import-button::after {
|
||||
content: 'IMPORT';
|
||||
}
|
||||
|
||||
.ndl-import-button.no-content::after {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.ndl-import-button:active {
|
||||
background: var(--doc-color-noodl-orange-140);
|
||||
}
|
||||
|
||||
.img-size-xs {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.img-size-s {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.img-size-m {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.img-size-l {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.johan-test {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Modules table */
|
||||
.modules-table img {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.ndl-data {
|
||||
font-weight: bold;
|
||||
color: var(--doc-color-noodl-orange-80);
|
||||
}
|
||||
|
||||
.ndl-signal {
|
||||
font-weight: bold;
|
||||
color: var(--doc-color-noodl-green-80);
|
||||
}
|
||||
|
||||
.ndl-deprecated {
|
||||
font-weight: bold;
|
||||
color: rgb(228, 57, 57);
|
||||
}
|
||||
|
||||
.hidden-props-for-editor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ndl-table-35-65 table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
.ndl-table-35-65 table td:nth-child(1) {
|
||||
width: 35%;
|
||||
}
|
||||
.ndl-table-35-65 table td:nth-child(2) {
|
||||
width: 65%;
|
||||
}
|
||||
105
src/css/navbar.scss
Normal file
105
src/css/navbar.scss
Normal file
@@ -0,0 +1,105 @@
|
||||
@use './utils/mixins.scss';
|
||||
|
||||
:root {
|
||||
--ifm-navbar-background-color: var(--doc-color-noodl-black-darker);
|
||||
--ifm-navbar-link-color: var(--doc-color-noodl-white-65);
|
||||
--ifm-navbar-padding-horizontal: 28px;
|
||||
--ifm-navbar-height: 64px;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
border-bottom: 1px solid var(--doc-color-noodl-black-light);
|
||||
padding: 0;
|
||||
|
||||
&__toggle {
|
||||
@media (max-width: 996px) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
&__inner {
|
||||
padding: 0 var(--ifm-navbar-padding-horizontal);
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: var(--doc-color-noodl-white);
|
||||
}
|
||||
|
||||
&__items {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
&__item {
|
||||
padding: calc(var(--ifm-navbar-padding-vertical) + 10px) 20px
|
||||
calc(var(--ifm-navbar-padding-vertical) + 5px);
|
||||
font-size: 16px;
|
||||
font-weight: var(--doc-font-semibold);
|
||||
|
||||
&:not(.is-download-button) {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
&.has-divider {
|
||||
padding-right: 50px;
|
||||
margin-right: 30px;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
bottom: 12px;
|
||||
right: 0;
|
||||
width: 1px;
|
||||
background-color: var(--doc-color-noodl-white-65);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-download-button {
|
||||
background-color: var(--doc-color-noodl-orange);
|
||||
color: var(--doc-color-noodl-black);
|
||||
padding: 0 40px;
|
||||
margin-left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: calc(var(--ifm-navbar-padding-horizontal) * -1);
|
||||
transition-duration: 100ms;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--doc-color-noodl-orange-140);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-discord {
|
||||
display: block;
|
||||
font-size: 0;
|
||||
width: 36px;
|
||||
box-sizing: content-box;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.65;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
background-image: url('../../static/img/discord.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/css/pagination.scss
Normal file
42
src/css/pagination.scss
Normal file
@@ -0,0 +1,42 @@
|
||||
@use '../css/utils/typography.scss';
|
||||
|
||||
.pagination-nav {
|
||||
border-top: 1px solid var(--doc-color-noodl-white-65);
|
||||
padding-bottom: 180px;
|
||||
|
||||
&__link {
|
||||
border: none;
|
||||
}
|
||||
|
||||
&__sublabel,
|
||||
&__label {
|
||||
@include typography.h3;
|
||||
}
|
||||
|
||||
&__label {
|
||||
&:after,
|
||||
&:before {
|
||||
content: '' !important;
|
||||
}
|
||||
}
|
||||
|
||||
&__sublabel {
|
||||
color: var(--doc-color-noodl-white-65) !important;
|
||||
padding-top: 32px;
|
||||
opacity: 0.5;
|
||||
transition: opacity var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default);
|
||||
|
||||
.pagination-nav__link:hover & {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.pagination-nav__item--next &:after {
|
||||
content: ' →';
|
||||
}
|
||||
|
||||
.pagination-nav__item:not(.pagination-nav__item--next) &:before {
|
||||
content: '← ';
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/css/searchbar.scss
Normal file
53
src/css/searchbar.scss
Normal file
@@ -0,0 +1,53 @@
|
||||
[data-theme='dark'] .DocSearch {
|
||||
--docsearch-text-color: var(--ifm-font-color-base);
|
||||
--docsearch-muted-color: var(--ifm-color-secondary-darkest);
|
||||
--docsearch-container-background: rgba(0, 0, 0, 0.8);
|
||||
/* Modal */
|
||||
--docsearch-modal-background: var(--doc-color-noodl-black-light);
|
||||
/* Search box */
|
||||
--docsearch-searchbox-background: var(--doc-color-noodl-black-darker);
|
||||
--docsearch-searchbox-focus-background: var(--ifm-color-black);
|
||||
/* Hit */
|
||||
--docsearch-hit-color: var(--ifm-font-color-base);
|
||||
--docsearch-hit-active-color: var(--ifm-color-white);
|
||||
--docsearch-hit-background: var(--ifm-color-emphasis-100);
|
||||
/* Footer */
|
||||
--docsearch-footer-background: var(--ifm-background-surface-color);
|
||||
--docsearch-key-gradient: linear-gradient(
|
||||
-26.5deg,
|
||||
var(--ifm-color-emphasis-200) 0%,
|
||||
var(--ifm-color-emphasis-100) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.DocSearch {
|
||||
padding: 0 !important;
|
||||
|
||||
main & {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
|
||||
.navbar & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar__items--right :last-child {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.DocSearch-Button {
|
||||
height: auto !important;
|
||||
border-radius: 2px !important;
|
||||
border: 1px solid var(--doc-color-noodl-black-light) !important;
|
||||
width: 100% !important;
|
||||
padding: 20px 24px !important;
|
||||
}
|
||||
|
||||
.search-bar-outer > :first-child {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.DocSearch-Hit[aria-selected='true'] a {
|
||||
background-color: var(--doc-color-noodl-blue-80) !important;
|
||||
}
|
||||
115
src/css/sidebar.scss
Normal file
115
src/css/sidebar.scss
Normal file
@@ -0,0 +1,115 @@
|
||||
// This file has a lot of messy overwrites as
|
||||
// we dont really want change the markup of the sidebar
|
||||
// component if we would have to update docusaurus in the
|
||||
// future. Future me: I hope that is a good desicion.
|
||||
|
||||
:root {
|
||||
--ifm-menu-color-background-hover: none;
|
||||
--ifm-menu-color-background-active: ;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background-color: var(--doc-color-noodl-black-darker);
|
||||
padding: 0 0 30px !important;
|
||||
height: 100vh;
|
||||
|
||||
.theme-doc-sidebar-menu {
|
||||
padding: 0;
|
||||
|
||||
> li {
|
||||
border-bottom: 1px solid var(--doc-color-noodl-black-light);
|
||||
|
||||
> div > .menu__link {
|
||||
padding: 13px var(--ifm-menu-link-padding-horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
> .theme-doc-sidebar-item-link > .menu__link {
|
||||
padding: 13px var(--ifm-menu-link-padding-horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
.theme-doc-sidebar-item-link-level-3 {
|
||||
border-left: 1px solid var(--doc-color-noodl-white-65);
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
&__list {
|
||||
margin: 0 !important;
|
||||
|
||||
& & {
|
||||
background-color: var(--doc-color-noodl-black-darkest);
|
||||
|
||||
a:not(.menu__link--active) {
|
||||
color: var(--doc-color-noodl-white-65) !important;
|
||||
|
||||
&:hover {
|
||||
color: var(--doc-color-noodl-white) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__list-item {
|
||||
margin: 0 !important;
|
||||
|
||||
&:not(.theme-doc-sidebar-item-link-level-3):not(.theme-doc-sidebar-item-category-level-1) {
|
||||
&:last-child {
|
||||
padding-bottom: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
&.theme-doc-sidebar-item-link-level-3 {
|
||||
&:first-child {
|
||||
margin-top: 13px !important;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 13px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__list-item-collapsible {
|
||||
&--active {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&__link {
|
||||
transition: color var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default),
|
||||
background-color var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default) !important;
|
||||
|
||||
&[aria-expanded='true'] {
|
||||
&,
|
||||
&:hover {
|
||||
background-color: var(
|
||||
--doc-color-noodl-black-darkest
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: var(--doc-color-noodl-orange) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&__caret {
|
||||
margin-left: 0;
|
||||
transition: background-color var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default) !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.menu__list-item:not(.menu__list-item--collapsed) & {
|
||||
background-color: var(--doc-color-noodl-black-darkest);
|
||||
}
|
||||
}
|
||||
|
||||
&__link--sublist-caret:after,
|
||||
&__caret:before {
|
||||
background: var(--ifm-menu-link-sublist-icon) 50% / 1.5rem 1.5rem;
|
||||
}
|
||||
}
|
||||
57
src/css/utils/mixins.scss
Normal file
57
src/css/utils/mixins.scss
Normal file
@@ -0,0 +1,57 @@
|
||||
@function _get-pseudo($pseudo) {
|
||||
@if ($pseudo == false) {
|
||||
$pseudo: '&::after';
|
||||
} @else if
|
||||
(
|
||||
_contains(
|
||||
('after', ':after', '::after', '&:after', '&::after'),
|
||||
$pseudo
|
||||
)
|
||||
)
|
||||
{
|
||||
$pseudo: '&::after';
|
||||
} @else if
|
||||
(
|
||||
_contains(
|
||||
('before', ':before', '::before', '&:before', '&::before'),
|
||||
$pseudo
|
||||
)
|
||||
)
|
||||
{
|
||||
$pseudo: '&::before';
|
||||
}
|
||||
|
||||
@return $pseudo;
|
||||
}
|
||||
|
||||
@function _is-pseudo($pseudo) {
|
||||
@return ($pseudo == '&::after' or $pseudo == '&::before');
|
||||
}
|
||||
|
||||
@function _contains($list, $item) {
|
||||
@return index($list, $item) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* aspect-ratio()
|
||||
*
|
||||
* Give a heightless element a height based on its width.
|
||||
* Always follows the set width:height ratio.
|
||||
*
|
||||
* @param {number} $width - Without CSS unit
|
||||
* @param {number} $height - Without CSS unit
|
||||
* @param {string} $pseudo - Optional selector to use insted of default pseudo-element
|
||||
*/
|
||||
|
||||
@mixin aspect-ratio($width, $height, $pseudo: false) {
|
||||
$pseudo: _get-pseudo($pseudo);
|
||||
|
||||
#{$pseudo} {
|
||||
@if (_is-pseudo($pseudo)) {
|
||||
content: '';
|
||||
}
|
||||
display: block;
|
||||
height: 0;
|
||||
padding-bottom: calc((100% / $width) * $height);
|
||||
}
|
||||
}
|
||||
98
src/css/utils/typography.scss
Normal file
98
src/css/utils/typography.scss
Normal file
@@ -0,0 +1,98 @@
|
||||
%font-smoothing {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
%title-base {
|
||||
font-family: var(--doc-font-title);
|
||||
font-weight: 600;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
|
||||
[data-theme='dark'] & {
|
||||
@extend %font-smoothing;
|
||||
color: var(--doc-color-title);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin h1 {
|
||||
@extend %title-base;
|
||||
font-family: var(--doc-font-supertitle);
|
||||
font-size: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
@mixin h1-bottom-spacing {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
@mixin h2 {
|
||||
@extend %title-base;
|
||||
font-family: var(--doc-font-supertitle);
|
||||
font-size: 32px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
@mixin h2-bottom-spacing {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
@mixin h2-top-spacing {
|
||||
margin-top: 120px;
|
||||
}
|
||||
|
||||
@mixin h3 {
|
||||
@extend %title-base;
|
||||
font-size: 24px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
@mixin h3-top-spacing {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
@mixin h3-bottom-spacing {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
@mixin h4 {
|
||||
@extend %title-base;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
@mixin h4-bottom-spacing {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
%body-base {
|
||||
font-family: var(--doc-font-text);
|
||||
|
||||
[data-theme='dark'] & {
|
||||
@extend %font-smoothing;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin body {
|
||||
@extend %body-base;
|
||||
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
@mixin body-bottom-spacing {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
@mixin body-small {
|
||||
@extend %body-base;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
@mixin body-small-bottom-spacing {
|
||||
padding-bottom: 14px;
|
||||
}
|
||||
57
src/css/variables.css
Normal file
57
src/css/variables.css
Normal file
@@ -0,0 +1,57 @@
|
||||
:root {
|
||||
/* Colors */
|
||||
--doc-color-noodl-black: #1f1f1f;
|
||||
--doc-color-noodl-black-dark: #141416;
|
||||
--doc-color-noodl-black-darker: #0e0e0e;
|
||||
--doc-color-noodl-black-darkest: #000000;
|
||||
--doc-color-noodl-black-light: #232326;
|
||||
|
||||
--doc-color-noodl-white: #f6f6f6;
|
||||
--doc-color-noodl-white-85: #dcdcdc;
|
||||
--doc-color-noodl-white-65: #a5a5a5;
|
||||
|
||||
--doc-color-noodl-orange: #f5bc41;
|
||||
--doc-color-noodl-orange-80: #f7c967;
|
||||
--doc-color-noodl-orange-60: #f9d78d;
|
||||
--doc-color-noodl-orange-40: #fbe4b3;
|
||||
--doc-color-noodl-orange-20: #fce9c2;
|
||||
--doc-color-noodl-orange-180: #f3b224;
|
||||
--doc-color-noodl-orange-160: #f3ac15;
|
||||
--doc-color-noodl-orange-140: #ce900b;
|
||||
|
||||
--doc-color-noodl-green: #1ca5b8;
|
||||
--doc-color-noodl-green-80: #49b7c6;
|
||||
--doc-color-noodl-green-60: #77c9d4;
|
||||
--doc-color-noodl-green-40: #92d4dd;
|
||||
--doc-color-noodl-green-20: #a8dde4;
|
||||
--doc-color-noodl-green-180: #1994a6;
|
||||
--doc-color-noodl-green-160: #188c9c;
|
||||
--doc-color-noodl-green-140: #147381;
|
||||
|
||||
--doc-color-noodl-blue: #5836f5;
|
||||
--doc-color-noodl-blue-80: #795ef7;
|
||||
--doc-color-noodl-blue-60: #9b86f9;
|
||||
--doc-color-noodl-blue-40: #bcaffb;
|
||||
--doc-color-noodl-blue-20: #c9bffc;
|
||||
--doc-color-noodl-blue-180: #401af4;
|
||||
--doc-color-noodl-blue-160: #350cf2;
|
||||
--doc-color-noodl-blue-140: #2c0ac7;
|
||||
|
||||
--doc-color-visual-node: #324e6b;
|
||||
--doc-color-data-node: #697844;
|
||||
--doc-color-custom-node: #8c436c;
|
||||
--doc-color-logic-node: #3b3e48;
|
||||
--doc-color-connection-node: #5f3789;
|
||||
|
||||
--doc-color-title: var(--doc-color-noodl-white);
|
||||
--doc-color-text: var(--doc-color-noodl-white-85);
|
||||
|
||||
/* Typography */
|
||||
--doc-font-title: 'Poppins', sans-serif;
|
||||
--doc-font-supertitle: 'PolySans', sans-serif;
|
||||
--doc-font-text: 'Inter', sans-serif;
|
||||
--doc-font-semibold: 600;
|
||||
|
||||
/* Sizes */
|
||||
--doc-size-page-top-spacing-l: 120px;
|
||||
}
|
||||
112
src/pages/index.js
Normal file
112
src/pages/index.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import React from 'react'
|
||||
import Layout from '@theme/Layout'
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import { Container } from '../components/layout/Container/Container'
|
||||
import { ModuleListing } from '../blocks/ModuleListing'
|
||||
import { frontpageData, FrontpageBlocks } from '../../static/data/frontpage'
|
||||
import { Text } from '../components/typography/Text/Text'
|
||||
import { HeroBlock } from '../blocks/HeroBlock'
|
||||
import { GuideListing } from '../blocks/GuideListing'
|
||||
import { VideoListing } from '../blocks/VideoListing'
|
||||
import { ProjectListing } from '../blocks/ProjectListing'
|
||||
import { PrefabListing } from '../blocks/PrefabListing'
|
||||
import SearchBar from '@theme-original/SearchBar'
|
||||
import Head from '@docusaurus/Head'
|
||||
|
||||
export default function Home() {
|
||||
const { siteConfig } = useDocusaurusContext()
|
||||
|
||||
return (
|
||||
<Layout title={`${siteConfig.title}`}>
|
||||
<Head>
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://docs.noodl.net/noodl-docs.png"
|
||||
/>
|
||||
<meta property="og:title" content="Noodl Documentation" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Explore Noodl guides, tutorials, videos, modules, and reference documentation here. Noodl is the low-code platform for designers + developers to build custom web apps and experiences."
|
||||
/>
|
||||
</Head>
|
||||
|
||||
<Container>
|
||||
<main>
|
||||
{frontpageData.map((item, i) => {
|
||||
switch (item.type) {
|
||||
case FrontpageBlocks.SearchBar:
|
||||
return (
|
||||
<div className="search-bar-outer" key={i}>
|
||||
<SearchBar />
|
||||
</div>
|
||||
)
|
||||
|
||||
case FrontpageBlocks.Hero:
|
||||
return (
|
||||
<HeroBlock
|
||||
key={i}
|
||||
title={item.title}
|
||||
text={item.text}
|
||||
gridItems={item.gridItems}
|
||||
playIcon={item.playIcon}
|
||||
/>
|
||||
)
|
||||
|
||||
case FrontpageBlocks.FeaturedModules:
|
||||
return (
|
||||
<ModuleListing
|
||||
key={i}
|
||||
title="Featured modules"
|
||||
isFeaturedOnly
|
||||
/>
|
||||
)
|
||||
|
||||
case FrontpageBlocks.FeaturedGuides:
|
||||
return (
|
||||
<GuideListing
|
||||
key={i}
|
||||
title="Featured guides"
|
||||
isFeaturedOnly
|
||||
/>
|
||||
)
|
||||
|
||||
case FrontpageBlocks.FeaturedProjects:
|
||||
return (
|
||||
<ProjectListing
|
||||
key={i}
|
||||
title="Featured example projects"
|
||||
/>
|
||||
)
|
||||
|
||||
case FrontpageBlocks.FeaturedVideos:
|
||||
return (
|
||||
<VideoListing
|
||||
key={i}
|
||||
title="Featured videos"
|
||||
isFeaturedOnly
|
||||
/>
|
||||
)
|
||||
|
||||
case FrontpageBlocks.FeaturedPrefabs:
|
||||
return (
|
||||
<PrefabListing
|
||||
key={i}
|
||||
title="Featured prefabs"
|
||||
isFeaturedOnly
|
||||
/>
|
||||
)
|
||||
|
||||
default:
|
||||
return (
|
||||
<Text key={i}>
|
||||
Error: Wrong type provided in frontpage
|
||||
data
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</main>
|
||||
</Container>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
1
src/pages/index.module.css
Normal file
1
src/pages/index.module.css
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
7
src/pages/markdown-page.md
Normal file
7
src/pages/markdown-page.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Markdown page example
|
||||
---
|
||||
|
||||
# Markdown page example
|
||||
|
||||
You don't need React to write simple standalone pages.
|
||||
79
src/theme/DocItem/DocItemWrapper.module.scss
Normal file
79
src/theme/DocItem/DocItemWrapper.module.scss
Normal file
@@ -0,0 +1,79 @@
|
||||
.Root {
|
||||
> div {
|
||||
justify-content: center;
|
||||
padding-top: var(--doc-size-page-top-spacing-l);
|
||||
|
||||
> div:first-child {
|
||||
:global(html:not(.docs-doc-id-overview):not(.docs-doc-id-modules\/overview):not(.docs-doc-id-prefabs\/overview):not(.docs-doc-id-getting-started\/overview):not(.docs-doc-id-learn):not(.docs-doc-id-examples\/overview))
|
||||
& {
|
||||
max-width: var(--ifm-container-width) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> div > div {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.Lightbox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(30,30,30, 0.7);
|
||||
z-index: 666;
|
||||
animation: show 200ms ease-out both;
|
||||
}
|
||||
|
||||
.Lightbox,
|
||||
.LightboxImageContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@keyframes show {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.LightboxImageContainer {
|
||||
position: relative;
|
||||
width: 85%;
|
||||
height: 85%;
|
||||
background: linear-gradient(45deg, var(--doc-color-noodl-orange), var(--doc-color-noodl-blue));
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 30px 5px rgba(0,0,0,0.3), 0 0 20px 5px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.LightboxClose {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: var(--doc-color-noodl-black-light);
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
border: 0;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
transition: color var(--speed-turbo) var(--easing-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--doc-color-noodl-black-darkest);
|
||||
}
|
||||
}
|
||||
|
||||
.LightboxAsset {
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
object-fit: contain;
|
||||
border-radius: 5px;
|
||||
box-shadow: -5px 5px 30px -5px rgba(56, 52, 28, 0.6666666667), 5px -5px 30px -5px rgba(32, 60, 44, 0.6666666667);
|
||||
}
|
||||
60
src/theme/DocItem/index.js
Normal file
60
src/theme/DocItem/index.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import DocItem from '@theme-original/DocItem';
|
||||
import css from './DocItemWrapper.module.scss';
|
||||
|
||||
export default function DocItemWrapper(props) {
|
||||
const docItemRootRef = React.useRef();
|
||||
const [lightboxAsset, setLightboxAsset] = React.useState(null);
|
||||
|
||||
function handleImageClick(e) {
|
||||
setLightboxAsset({
|
||||
src: e.target.src,
|
||||
type: e.target.tagName,
|
||||
});
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!docItemRootRef.current) return;
|
||||
|
||||
const images = Array.from(docItemRootRef.current.querySelectorAll('img'));
|
||||
const videos = Array.from(docItemRootRef.current.querySelectorAll('video'));
|
||||
|
||||
[...images, ...videos].forEach((asset) => {
|
||||
asset.style.cursor = 'pointer';
|
||||
asset.addEventListener('click', handleImageClick);
|
||||
});
|
||||
|
||||
return () => {
|
||||
[...images, ...videos].forEach((asset) => {
|
||||
asset.removeEventListener('click', handleImageClick);
|
||||
});
|
||||
};
|
||||
}, [docItemRootRef.current]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{lightboxAsset && (
|
||||
<div className={css['Lightbox']} onClick={() => setLightboxAsset(null)}>
|
||||
<div className={css['LightboxImageContainer']}>
|
||||
<button className={css['LightboxClose']}>✕</button>
|
||||
{lightboxAsset.type === 'IMG' && (
|
||||
<img className={css['LightboxAsset']} src={lightboxAsset.src} />
|
||||
)}
|
||||
|
||||
{lightboxAsset.type === 'VIDEO' && (
|
||||
<video
|
||||
className={css['LightboxAsset']}
|
||||
src={lightboxAsset.src}
|
||||
autoPlay
|
||||
loop
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div ref={docItemRootRef} className={css['Root']}>
|
||||
<DocItem {...props} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
15
src/theme/DocSidebar/Desktop/Content/index.js
Normal file
15
src/theme/DocSidebar/Desktop/Content/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
import Content from '@theme-original/DocSidebar/Desktop/Content'
|
||||
import SearchBar from '@theme-original/SearchBar'
|
||||
|
||||
export default function ContentWrapper(props) {
|
||||
return (
|
||||
<>
|
||||
<div className="search-bar-outer">
|
||||
<SearchBar />
|
||||
</div>
|
||||
|
||||
<Content {...props} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
58
src/utils/importIntoNoodl.ts
Normal file
58
src/utils/importIntoNoodl.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import config from '@generated/docusaurus.config'
|
||||
|
||||
interface IImportOptions {
|
||||
/** Name of import */
|
||||
name: string
|
||||
/** Image shown in project import */
|
||||
thumb: string
|
||||
/** Cloudformation, JSON that creates a backend */
|
||||
cf?: string
|
||||
}
|
||||
|
||||
export interface ImportIntoNoodlArgs {
|
||||
path: string
|
||||
options: IImportOptions
|
||||
}
|
||||
|
||||
export function importIntoNoodl(path: string, options: IImportOptions) {
|
||||
let query = []
|
||||
if (options && options.name !== undefined)
|
||||
query.push('name=' + encodeURIComponent(options.name))
|
||||
if (options && options.thumb !== undefined)
|
||||
query.push(
|
||||
'thumb=' +
|
||||
encodeURIComponent(
|
||||
location.protocol +
|
||||
'//' +
|
||||
location.host +
|
||||
config.baseUrl +
|
||||
options.thumb
|
||||
)
|
||||
)
|
||||
if (options && options.cf !== undefined)
|
||||
query.push(
|
||||
'cf=' +
|
||||
encodeURIComponent(
|
||||
location.protocol +
|
||||
'//' +
|
||||
location.host +
|
||||
config.baseUrl +
|
||||
'/' +
|
||||
options.cf
|
||||
)
|
||||
)
|
||||
|
||||
var uri =
|
||||
'noodl:import/' +
|
||||
location.protocol +
|
||||
'//' +
|
||||
location.host +
|
||||
config.baseUrl +
|
||||
path +
|
||||
(query.length > 0 ? '?' + query.join('&') : '')
|
||||
|
||||
console.log('Importing into Noodl:', uri)
|
||||
console.log(path)
|
||||
|
||||
window.location.href = uri
|
||||
}
|
||||
Reference in New Issue
Block a user