|
| 1 | +import React from 'react' |
| 2 | +import styled, { keyframes } from 'styled-components' |
| 3 | +import { colors, theme } from 'theme' |
| 4 | +import { rgba } from 'polished' |
| 5 | + |
| 6 | +import Box from 'components/elements/Box' |
| 7 | +import Flex from 'components/elements/Flex' |
| 8 | +import Text from 'components/elements/Text' |
| 9 | +import { FileType } from 'components/icons/FileType' |
| 10 | +import { Microlink } from 'components/logos' |
| 11 | +import { PRODUCTS } from 'components/pages/home/catalog' |
| 12 | +import { DemoCard } from 'components/patterns/ProductStory/demo-card' |
| 13 | + |
| 14 | +const INPUTS = [ |
| 15 | + { name: 'document.pdf', type: 'pdf' }, |
| 16 | + { name: 'guide.docx', type: 'docx' }, |
| 17 | + { name: 'report.xlsx', type: 'xlsx' }, |
| 18 | + { name: 'slides.pptx', type: 'pptx' } |
| 19 | +] |
| 20 | + |
| 21 | +const OUTPUTS = [ |
| 22 | + { |
| 23 | + label: 'HTML', |
| 24 | + icon: PRODUCTS.html.icon, |
| 25 | + bg: colors.violet0, |
| 26 | + color: colors.violet7 |
| 27 | + }, |
| 28 | + { |
| 29 | + label: 'MARKDOWN', |
| 30 | + icon: PRODUCTS.markdown.icon, |
| 31 | + bg: colors.indigo0, |
| 32 | + color: colors.indigo7 |
| 33 | + }, |
| 34 | + { |
| 35 | + label: 'TEXT', |
| 36 | + icon: PRODUCTS.text.icon, |
| 37 | + bg: colors.orange0, |
| 38 | + color: colors.orange8 |
| 39 | + }, |
| 40 | + { label: 'PDF', icon: PRODUCTS.pdf.icon, bg: colors.red0, color: colors.red6 } |
| 41 | +] |
| 42 | + |
| 43 | +const CURVE_X = [55, 165, 275, 385] |
| 44 | + |
| 45 | +const dashFlow = keyframes` |
| 46 | + to { stroke-dashoffset: -26; } |
| 47 | +` |
| 48 | + |
| 49 | +const Body = styled(Box)(theme({ px: 4, py: 5, bg: 'white' })) |
| 50 | + |
| 51 | +const TileGrid = styled(Box)( |
| 52 | + theme({ |
| 53 | + display: 'grid', |
| 54 | + gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', |
| 55 | + gap: 2 |
| 56 | + }) |
| 57 | +) |
| 58 | + |
| 59 | +const FileTile = styled(Flex)( |
| 60 | + theme({ |
| 61 | + flexDirection: 'column', |
| 62 | + alignItems: 'center', |
| 63 | + gap: 2, |
| 64 | + py: 3, |
| 65 | + px: 1, |
| 66 | + bg: 'white', |
| 67 | + border: 1, |
| 68 | + borderColor: 'gray2', |
| 69 | + borderRadius: 3 |
| 70 | + }) |
| 71 | +) |
| 72 | + |
| 73 | +const FileName = styled(Text)( |
| 74 | + theme({ |
| 75 | + fontFamily: 'mono', |
| 76 | + fontSize: '10px', |
| 77 | + color: 'black60', |
| 78 | + maxWidth: '100%' |
| 79 | + }), |
| 80 | + 'overflow: hidden; text-overflow: ellipsis; white-space: nowrap;' |
| 81 | +) |
| 82 | + |
| 83 | +const Bus = styled('svg')` |
| 84 | + display: block; |
| 85 | + width: 100%; |
| 86 | + height: 60px; |
| 87 | +
|
| 88 | + path { |
| 89 | + fill: none; |
| 90 | + stroke: ${colors.gray4}; |
| 91 | + stroke-width: 2; |
| 92 | + stroke-dasharray: 6 7; |
| 93 | + stroke-linecap: round; |
| 94 | + animation: ${dashFlow} 1.6s linear infinite; |
| 95 | + } |
| 96 | +
|
| 97 | + @media (prefers-reduced-motion: reduce) { |
| 98 | + path { |
| 99 | + animation: none; |
| 100 | + } |
| 101 | + } |
| 102 | +` |
| 103 | + |
| 104 | +const NodeWrap = styled(Flex)` |
| 105 | + position: relative; |
| 106 | + align-items: center; |
| 107 | + justify-content: center; |
| 108 | +` |
| 109 | + |
| 110 | +const NodeGlow = styled(Box)` |
| 111 | + position: absolute; |
| 112 | + width: 170px; |
| 113 | + height: 170px; |
| 114 | + border-radius: 50%; |
| 115 | + background: radial-gradient( |
| 116 | + circle, |
| 117 | + ${rgba(colors.pink6, 0.18)}, |
| 118 | + ${rgba(colors.violet6, 0.14)} 42%, |
| 119 | + ${rgba(colors.white, 0)} 72% |
| 120 | + ); |
| 121 | + filter: blur(8px); |
| 122 | +` |
| 123 | + |
| 124 | +const NodeCircle = styled(Flex)( |
| 125 | + theme({ |
| 126 | + position: 'relative', |
| 127 | + width: '96px', |
| 128 | + height: '96px', |
| 129 | + borderRadius: '50%', |
| 130 | + bg: 'white', |
| 131 | + boxShadow: 0, |
| 132 | + alignItems: 'center', |
| 133 | + justifyContent: 'center' |
| 134 | + }) |
| 135 | +) |
| 136 | + |
| 137 | +const OutTile = styled(Flex)( |
| 138 | + theme({ |
| 139 | + flexDirection: 'column', |
| 140 | + alignItems: 'center', |
| 141 | + justifyContent: 'center', |
| 142 | + gap: 2, |
| 143 | + py: 3, |
| 144 | + borderRadius: 2, |
| 145 | + fontFamily: 'mono', |
| 146 | + fontSize: '10px', |
| 147 | + fontWeight: 'bold', |
| 148 | + letterSpacing: 1 |
| 149 | + }) |
| 150 | +) |
| 151 | + |
| 152 | +const FooterResult = styled(Text)` |
| 153 | + font-family: inherit; |
| 154 | + font-size: inherit; |
| 155 | + color: ${colors.black50}; |
| 156 | +
|
| 157 | + b { |
| 158 | + color: ${colors.orange8}; |
| 159 | + font-weight: bold; |
| 160 | + } |
| 161 | +` |
| 162 | + |
| 163 | +const curvesIn = CURVE_X.map(x => `M${x} 0 C ${x} 40, 220 24, 220 60`) |
| 164 | + |
| 165 | +const curvesOut = CURVE_X.map(x => `M220 0 C 220 22, ${x} 38, ${x} 60`) |
| 166 | + |
| 167 | +export const ConversionCapabilitiesVisual = () => ( |
| 168 | + <DemoCard |
| 169 | + maxWidth='620px' |
| 170 | + footer={ |
| 171 | + <FooterResult as='span'> |
| 172 | + <b>✓ readable content</b> · structure preserved |
| 173 | + </FooterResult> |
| 174 | + } |
| 175 | + > |
| 176 | + <Body> |
| 177 | + <TileGrid> |
| 178 | + {INPUTS.map(({ name, type }) => ( |
| 179 | + <FileTile key={name}> |
| 180 | + <FileType type={type} size={40} /> |
| 181 | + <FileName as='span'>{name}</FileName> |
| 182 | + </FileTile> |
| 183 | + ))} |
| 184 | + </TileGrid> |
| 185 | + <Bus viewBox='0 0 440 60' preserveAspectRatio='none' aria-hidden='true'> |
| 186 | + {curvesIn.map(d => ( |
| 187 | + <path key={d} d={d} /> |
| 188 | + ))} |
| 189 | + </Bus> |
| 190 | + <NodeWrap> |
| 191 | + <NodeGlow /> |
| 192 | + <NodeCircle> |
| 193 | + <img |
| 194 | + src={Microlink.logoUri} |
| 195 | + alt='' |
| 196 | + css={{ width: '42px', height: 'auto', display: 'block' }} |
| 197 | + /> |
| 198 | + </NodeCircle> |
| 199 | + </NodeWrap> |
| 200 | + <Bus viewBox='0 0 440 60' preserveAspectRatio='none' aria-hidden='true'> |
| 201 | + {curvesOut.map(d => ( |
| 202 | + <path key={d} d={d} /> |
| 203 | + ))} |
| 204 | + </Bus> |
| 205 | + <TileGrid> |
| 206 | + {OUTPUTS.map(({ label, icon: Icon, bg, color }) => ( |
| 207 | + <OutTile key={label} css={{ background: bg, color }}> |
| 208 | + {label} |
| 209 | + <Icon width='20px' height='20px' /> |
| 210 | + </OutTile> |
| 211 | + ))} |
| 212 | + </TileGrid> |
| 213 | + </Body> |
| 214 | + </DemoCard> |
| 215 | +) |
0 commit comments