*/
10 | className?: string
11 |
12 | children?: React.ReactNode
13 | }
14 |
15 | /**
16 | * Post content with transform magic.
17 | * @param {any} props.htmlAst The markdown AST to render.
18 | * @param {any} props.children Stuff to render. If given, htmlAst is ignored.
19 | * @param {any} props.className The classname of the parent div.
20 | */
21 |
22 | const PostContent = memo((props: Props) => {
23 | const { htmlAst, className, children } = props
24 | const root = useRef
(null)
25 |
26 | // Render HTML AST as React nodes
27 | const content = useMemo(() => {
28 | if (children) {
29 | return children
30 | } else if (htmlAst) {
31 | return transform(htmlAst)
32 | }
33 | }, [htmlAst, children])
34 |
35 | // Perform syntax highlighting and Isotope'ing
36 | useEffect(() => {
37 | if (root.current) doPostTransform(root.current)
38 | }, [])
39 |
40 | return (
41 |
42 | {content}
43 |
44 | )
45 | })
46 |
47 | export default PostContent
48 |
--------------------------------------------------------------------------------
/src/css-legacy-components/css/related-posts-section.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Section
3 | * has callout and group
4 | */
5 |
6 | .related-posts-section {
7 | & {
8 | display: flex;
9 | }
10 | & {
11 | @extend %section-gutter-margin-left--1;
12 | }
13 | & {
14 | @extend %section-gutter-margin-right--1;
15 | }
16 |
17 | & > .callout,
18 | & > .group {
19 | margin: 0;
20 | & {
21 | @extend %section-gutter-margin-left;
22 | }
23 | & {
24 | @extend %section-gutter-margin-right;
25 | }
26 | }
27 |
28 | & > .callout {
29 | flex: 1 1 33%;
30 | }
31 |
32 | & > .group {
33 | flex: 1 1 50%;
34 | }
35 |
36 | & > .callout {
37 | display: flex;
38 |
39 | & > * {
40 | flex: 1 0 100%;
41 | }
42 | }
43 |
44 | /* Mobile */
45 | @media (max-width: 480px) {
46 | & {
47 | flex-wrap: wrap;
48 | }
49 |
50 | & > .callout,
51 | & > .group {
52 | margin-top: 16px;
53 | margin-bottom: 16px;
54 | flex: 1 1 100%;
55 | }
56 | }
57 |
58 | /* Tablet */
59 | @media (min-width: 481px) and (max-width: 768px) {
60 | & {
61 | flex-wrap: wrap;
62 | }
63 |
64 | & > .callout,
65 | & > .group {
66 | margin-top: 16px;
67 | margin-bottom: 16px;
68 | flex: 1 1 100%;
69 | }
70 |
71 | & > .group {
72 | flex: 1 1 40%;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/css-legacy-components/css/future/announcements-item.css:
--------------------------------------------------------------------------------
1 | .announcements-item {
2 | & {
3 | position: relative;
4 | padding: 16px;
5 | box-shadow: var(--shadow6);
6 | border-radius: 1px;
7 | background: white;
8 | padding-right: 48px;
9 | animation: announcements-item-flyin 500ms ease-out;
10 | transition: opacity 500ms linear, transform 500ms ease-out;
11 | }
12 |
13 | &.-hide {
14 | display: none;
15 | }
16 |
17 | & > .title {
18 | @extend %ms-font-size-1;
19 | font-weight: normal;
20 | color: var(--brand-a);
21 | margin: 0;
22 | padding: 0;
23 | }
24 |
25 | & > .body > p {
26 | margin: 0;
27 | padding: 0;
28 |
29 | & + p {
30 | margin-top: 1em;
31 | }
32 | }
33 |
34 | & > .close {
35 | position: absolute;
36 | right: 0;
37 | top: 0;
38 | width: 40px;
39 | height: 40px;
40 | line-height: 40px;
41 | text-align: center;
42 | border: 0;
43 | margin: 0;
44 | padding: 0;
45 | cursor: pointer;
46 |
47 | &:hover,
48 | &:focus {
49 | color: var(--brand-a);
50 | }
51 | }
52 |
53 | & > .close::before {
54 | content: '\00D7';
55 | font-size: 14px;
56 | }
57 | }
58 |
59 | @keyframes announcements-item-flyin {
60 | 0% {
61 | transform: translate3d(0, 32px, 0);
62 | opacity: 0;
63 | }
64 |
65 | 100% {
66 | transform: translate3d(0, 0, 0);
67 | opacity: 1;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/web/components/PageActions.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { github as githubIcon } from '../../web-icons'
3 |
4 | import cn from 'classnames'
5 | import useSiteContent from '../../gatsby-hooks/useSiteContent'
6 | import CSS from './PageActions.module.css'
7 |
8 | /*
9 | * Types
10 | */
11 |
12 | export interface Props {
13 | // eg, '/vim'
14 | path?: string
15 | }
16 |
17 | export interface ViewProps extends Props {
18 | labels: {
19 | edit: string // => 'Edit'
20 | editOnGithub: string // => 'Edit on GitHub'
21 | }
22 | editURL: string
23 | }
24 |
25 | /**
26 | * Connector
27 | */
28 |
29 | export const PageActions = (props: Props) => {
30 | const repo = 'https://github.com/rstacruz/cheatsheets'
31 | const branch = 'master'
32 | const editURL = `${repo}/blob/${branch}${props.path || ''}.md`
33 | const content = useSiteContent()
34 | const { editOnGithub, edit } = content.topNav
35 | const { path } = props
36 |
37 | if (!path) return null
38 |
39 | return (
40 |
51 | )
52 | }
53 |
54 | export default PageActions
55 |
--------------------------------------------------------------------------------
/src/web/components/PagesList.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | & {
3 | display: flex;
4 | flex-wrap: wrap;
5 | }
6 |
7 | & > .item {
8 | flex: 0 0 100%;
9 | }
10 |
11 | & > .item.article {
12 | flex: 0 0 50%;
13 | }
14 |
15 | @media (min-width: 581px) {
16 | & > .item.isTopSheet {
17 | flex: 0 0 25%;
18 | }
19 | }
20 | }
21 |
22 | /* Article */
23 |
24 | .root > .article {
25 | text-decoration: none;
26 | display: block;
27 | white-space: nowrap;
28 | padding: 4px 0;
29 |
30 | &,
31 | &:visited {
32 | color: var(--text-mute3);
33 | }
34 |
35 | & > .info > .slug {
36 | color: var(--text-bold);
37 | }
38 |
39 | &:visited > .info > .slug {
40 | color: var(--text-body);
41 | }
42 |
43 | & > .info > .title::before {
44 | content: '';
45 | margin: 0 4px;
46 | }
47 |
48 | & > .info > .title {
49 | opacity: 0;
50 | }
51 |
52 | @media (max-width: 768px) {
53 | & > .info > .title {
54 | display: none;
55 | }
56 | }
57 |
58 | &:hover,
59 | &:focus {
60 | & {
61 | color: var(--text-mute);
62 | }
63 |
64 | & > .info > .title {
65 | opacity: 1;
66 | color: var(--brand-a);
67 | }
68 | }
69 | }
70 |
71 | .root > .category {
72 | @extend %ms-font-size-1;
73 | border-bottom: solid 1px var(--dark-line-color);
74 | margin: 16px 0;
75 | padding: 0 0 16px 0;
76 | font-weight: normal;
77 | color: var(--brand-a);
78 | }
79 |
--------------------------------------------------------------------------------
/src/web-post-content/lib/isotopify.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Lays out each h3-section using Isotope.
3 | */
4 |
5 | export default function isotopify(el: HTMLElement | null | void) {
6 | if (!el || !el.children) return
7 |
8 | // If we're running on the server, don't bother with this
9 | if (typeof window === 'undefined') return
10 |
11 | // There's a wrapping from renderAst, meh
12 | const div = el.children[0]
13 | if (!div) return
14 |
15 | // isotope()'ify all lists
16 | const lists = div.querySelectorAll
('.h3-section-list')
17 | Array.from(lists).forEach(isotopifyItem)
18 | }
19 |
20 | /**
21 | * Applies an Isotope layout to the given HTML element `el`'s H3 sections.
22 | */
23 |
24 | function isotopifyItem(el: HTMLElement) {
25 | // Load this lazily, so that it doesn't happen on the server
26 | const Isotope = require('isotope-layout/dist/isotope.pkgd.js')
27 |
28 | const iso = new Isotope(el, {
29 | itemSelector: '.h3-section',
30 | transitionDuration: 0
31 | })
32 |
33 | const images = el.querySelectorAll('img')
34 |
35 | Array.from(images).forEach(image => {
36 | image.addEventListener('load', () => {
37 | iso.layout()
38 | })
39 | })
40 |
41 | // Insurance against weirdness on pages like devhints.io/vim, where the
42 | // critical path CSS may look different from the final CSS (because of the
43 | // tables).
44 | window.addEventListener('load', () => {
45 | iso.layout()
46 | })
47 | }
48 |
--------------------------------------------------------------------------------
/src/web-comments/CommentsArea.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { DisqusData } from '../types/types'
3 | import CSS from './CommentsArea.module.css'
4 | import CommentsAreaSummary from './comps/CommentsAreaSummary'
5 | import CommentsSection from './comps/CommentsSection'
6 | import DisqusScript, { RenderProps } from './comps/DisqusScript'
7 |
8 | interface ViewProps {
9 | thread: React.ReactNode
10 | count: React.ReactNode
11 | }
12 |
13 | /**
14 | * Comments area
15 | */
16 |
17 | const CommentsAreaView = (props: ViewProps) => {
18 | const { count } = props
19 |
20 | return (
21 |
29 | )
30 | }
31 |
32 | /*
33 | * Connector
34 | */
35 |
36 | const CommentsArea = () => {
37 | // Disqus configuration
38 | const disqus: DisqusData = {
39 | host: 'devhints.disqus.com',
40 | url: 'https://devhints.io/react',
41 | identifier: 'react'
42 | }
43 |
44 | return (
45 |
46 | {({ thread, count }: RenderProps) => {
47 | return
48 | }}
49 |
50 | )
51 | }
52 |
53 | /*
54 | * Export
55 | */
56 |
57 | export default CommentsArea
58 |
--------------------------------------------------------------------------------
/src/web/components/RelatedPostItem.module.css:
--------------------------------------------------------------------------------
1 | .root {
2 | display: flex;
3 | text-align: left;
4 | line-height: 1.4;
5 | }
6 |
7 | /* Layout */
8 | .link {
9 | flex: 1 1 100%;
10 | display: block;
11 | border-radius: 2px;
12 | box-shadow: var(--shadow2);
13 | padding: 16px;
14 | text-decoration: none;
15 | }
16 |
17 | /* Color */
18 | .link,
19 | .link:visited {
20 | background: white;
21 | color: var(--text-mute);
22 |
23 | & > .title {
24 | color: var(--brand-a);
25 | }
26 |
27 | &:hover,
28 | &:focus {
29 | color: var(--brand-a);
30 | }
31 |
32 | &:hover > .title,
33 | &:focus > .title {
34 | /* TODO color: darken(var(--brand-a), 16%); */
35 | }
36 | }
37 |
38 | .root.isPrimary > .link,
39 | .root.isPrimary > .link:visited {
40 | background: var(--brand-a);
41 | color: color-mod(white alpha(50%));
42 |
43 | & > .title {
44 | color: white;
45 | }
46 |
47 | &:hover,
48 | &:focus {
49 | color: white;
50 | }
51 |
52 | &:hover > .title,
53 | &:focus > .title {
54 | color: white;
55 | }
56 |
57 | &:hover,
58 | &:focus {
59 | background: color-mod(var(--brand-a) lightness(-9%));
60 | }
61 | }
62 |
63 | /* Two lines when bigger */
64 | @media (min-width: 481px) {
65 | .link > .title,
66 | .link > .suffix {
67 | display: block;
68 | }
69 |
70 | .link > .title {
71 | font-size: calc(var(--ms-base-md) * var(--ms-ratio-md));
72 | font-weight: normal;
73 | }
74 |
75 | .link > .suffix {
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/web/components/RootPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import useSiteContent from '../../gatsby-hooks/useSiteContent'
4 | import CommonHead from '../../gatsby-shell/comps/CommonHead'
5 | import { HomeMeta } from '../../gatsby-shell/Meta'
6 | import { GroupedSiteLinks, SiteLink } from '../../types/types'
7 | import { LiveSearchInput } from '../../web-search'
8 | import PagesList from './PagesList'
9 | import SiteHeader from './SiteHeader'
10 | import TopNav from './TopNav'
11 |
12 | export interface Props {
13 | recentlyUpdated: SiteLink[]
14 | groups: GroupedSiteLinks
15 | }
16 |
17 | /**
18 | * The home page.
19 | *
20 | * @example
21 | *
25 | */
26 |
27 | export const RootPage = (props: Props) => {
28 | const content = useSiteContent()
29 | const recentlyUpdatedLabel = content.home.recentlyUpdated
30 | const { groups, recentlyUpdated } = props
31 |
32 | return (
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | {Object.keys(groups).map((group: string) => (
45 |
46 | ))}
47 |
48 |
49 | )
50 | }
51 |
52 | export default RootPage
53 |
--------------------------------------------------------------------------------
/src/uipad/lib/useIFrameSize.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export interface IFrame {
4 | node: HTMLIFrameElement
5 | }
6 |
7 | /**
8 | * React hook to dynamically adjust iframe size.
9 | * Returns the following things:
10 | *
11 | * - `ref` - set this ref to the `