@ossy/connected-components 0.0.3-alpha → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/.storybook/main.js +19 -0
  2. package/.storybook/preview.js +13 -0
  3. package/CHANGELOG.md +64 -0
  4. package/LICENSE +21 -0
  5. package/build/cjs/index.js +656 -0
  6. package/build/esm/index.js +638 -0
  7. package/package.json +55 -15
  8. package/rollup.config.js +35 -0
  9. package/src/app/App.jsx +29 -0
  10. package/src/app/App.stories.jsx +36 -0
  11. package/src/app/AppSettings.jsx +22 -0
  12. package/src/app/index.js +3 -0
  13. package/src/app/useAnalytics.jsx +18 -0
  14. package/src/index.js +11 -0
  15. package/src/layout/Layout.jsx +25 -0
  16. package/src/layout/Layout.stories.jsx +16 -0
  17. package/src/layout/index.js +1 -0
  18. package/src/ossybot/Ossybot.jsx +67 -0
  19. package/src/ossybot/Ossybot.stories.jsx +26 -0
  20. package/src/ossybot/index.js +1 -0
  21. package/src/page/Page.jsx +33 -0
  22. package/src/page/Page.stories.jsx +17 -0
  23. package/src/page/index.js +1 -0
  24. package/src/page-data-loader/PageDataLoader.jsx +90 -0
  25. package/src/page-data-loader/PageDataLoader.stories.jsx +16 -0
  26. package/src/page-data-loader/index.js +1 -0
  27. package/src/pages-module/PagesModule.jsx +8 -0
  28. package/src/pages-module/PagesModule.stories.jsx +17 -0
  29. package/src/pages-module/index.js +1 -0
  30. package/src/resume/Resume.jsx +13 -0
  31. package/src/resume/Resume.stories.jsx +23 -0
  32. package/src/resume/Resume.template.js +80 -0
  33. package/src/resume/index.js +3 -0
  34. package/src/resume/useResume.js +112 -0
  35. package/src/section/Section.jsx +93 -0
  36. package/src/section/Section.stories.jsx +17 -0
  37. package/src/section/index.js +1 -0
  38. package/src/stories/Button.jsx +39 -0
  39. package/src/stories/Button.stories.js +49 -0
  40. package/src/stories/Configure.mdx +364 -0
  41. package/src/stories/Header.jsx +56 -0
  42. package/src/stories/Header.stories.js +29 -0
  43. package/src/stories/Page.jsx +69 -0
  44. package/src/stories/Page.stories.js +28 -0
  45. package/src/stories/assets/accessibility.png +0 -0
  46. package/src/stories/assets/accessibility.svg +1 -0
  47. package/src/stories/assets/addon-library.png +0 -0
  48. package/src/stories/assets/assets.png +0 -0
  49. package/src/stories/assets/avif-test-image.avif +0 -0
  50. package/src/stories/assets/context.png +0 -0
  51. package/src/stories/assets/discord.svg +1 -0
  52. package/src/stories/assets/docs.png +0 -0
  53. package/src/stories/assets/figma-plugin.png +0 -0
  54. package/src/stories/assets/github.svg +1 -0
  55. package/src/stories/assets/share.png +0 -0
  56. package/src/stories/assets/styling.png +0 -0
  57. package/src/stories/assets/testing.png +0 -0
  58. package/src/stories/assets/theming.png +0 -0
  59. package/src/stories/assets/tutorials.svg +1 -0
  60. package/src/stories/assets/youtube.svg +1 -0
  61. package/src/stories/button.css +30 -0
  62. package/src/stories/header.css +32 -0
  63. package/src/stories/page.css +68 -0
  64. package/src/theme-editor/ThemeEditor.jsx +132 -0
  65. package/src/theme-editor/ThemeEditor.stories.jsx +16 -0
  66. package/src/theme-editor/index.js +1 -0
  67. package/src/theme-provider/ThemeProvider.jsx +9 -0
  68. package/src/theme-provider/ThemeProvider.stories.jsx +16 -0
  69. package/src/theme-provider/index.js +1 -0
  70. package/src/use-active-page-location/index.js +1 -0
  71. package/src/use-active-page-location/useActivePageLocation.js +54 -0
  72. package/index.cjs.js +0 -8
  73. package/index.esm.js +0 -8
@@ -0,0 +1,68 @@
1
+ .storybook-page {
2
+ margin: 0 auto;
3
+ padding: 48px 20px;
4
+ max-width: 600px;
5
+ color: #333;
6
+ font-size: 14px;
7
+ line-height: 24px;
8
+ font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
9
+ }
10
+
11
+ .storybook-page h2 {
12
+ display: inline-block;
13
+ vertical-align: top;
14
+ margin: 0 0 4px;
15
+ font-weight: 700;
16
+ font-size: 32px;
17
+ line-height: 1;
18
+ }
19
+
20
+ .storybook-page p {
21
+ margin: 1em 0;
22
+ }
23
+
24
+ .storybook-page a {
25
+ color: inherit;
26
+ }
27
+
28
+ .storybook-page ul {
29
+ margin: 1em 0;
30
+ padding-left: 30px;
31
+ }
32
+
33
+ .storybook-page li {
34
+ margin-bottom: 8px;
35
+ }
36
+
37
+ .storybook-page .tip {
38
+ display: inline-block;
39
+ vertical-align: top;
40
+ margin-right: 10px;
41
+ border-radius: 1em;
42
+ background: #e7fdd8;
43
+ padding: 4px 12px;
44
+ color: #357a14;
45
+ font-weight: 700;
46
+ font-size: 11px;
47
+ line-height: 12px;
48
+ }
49
+
50
+ .storybook-page .tip-wrapper {
51
+ margin-top: 40px;
52
+ margin-bottom: 40px;
53
+ font-size: 13px;
54
+ line-height: 20px;
55
+ }
56
+
57
+ .storybook-page .tip-wrapper svg {
58
+ display: inline-block;
59
+ vertical-align: top;
60
+ margin-top: 3px;
61
+ margin-right: 4px;
62
+ width: 12px;
63
+ height: 12px;
64
+ }
65
+
66
+ .storybook-page .tip-wrapper svg path {
67
+ fill: #1ea7fd;
68
+ }
@@ -0,0 +1,132 @@
1
+ import { useState, useMemo, useCallback, useEffect } from 'react'
2
+ import { useResource } from '@ossy/sdk-react'
3
+ import { Overlay, Button, useTheme, View, Text } from '@ossy/design-system'
4
+
5
+ const overlayStyles = {
6
+ background: 'transparent',
7
+ display: 'content',
8
+ pointerEvents: 'none'
9
+ }
10
+
11
+ const blobStyles = {
12
+ boxShadow: '2px 2px 5px hsla(0, 0%, 0%, .2)',
13
+ borderRadius: '999px',
14
+ position: 'absolute',
15
+ right: 'var(--space-m)',
16
+ bottom: 'var(--space-m)',
17
+ cursor: 'pointer',
18
+ transition: 'transform .5s',
19
+ pointerEvents: 'auto',
20
+ padding: 'var(--space-m)'
21
+ }
22
+
23
+ const editorContainerStyles = {
24
+ position: 'absolute',
25
+ right: '0',
26
+ top: '0',
27
+ height: '100%',
28
+ width: '100%',
29
+ display: 'flex',
30
+ justifyContent: 'flex-end',
31
+ alignItems: 'stretch',
32
+ padding: '8px 32px'
33
+ }
34
+
35
+ const editorStyles = {
36
+ width: '100%',
37
+ maxWidth: '350px',
38
+ height: '100%',
39
+ boxShadow: '2px 2px 5px hsla(0, 0%, 0%, .2)',
40
+ padding: '16px 16px 76px 16px',
41
+ overflowX: 'none',
42
+ overflowY: 'auto',
43
+ pointerEvents: 'auto'
44
+ }
45
+
46
+ const ThemeSwitcher = () => {
47
+ const { activeTheme, setTheme, themes } = useTheme()
48
+ return (
49
+ <View gap="s">
50
+ <Text>Theme</Text>
51
+ <View layout="row-wrap" gap="s">
52
+ {
53
+ themes.map(themeName => <Button variant={themeName === activeTheme ? 'tag-active' : 'tag'} onClick={() => setTheme(themeName)}>{themeName}</Button>)
54
+ }
55
+ </View>
56
+ </View>
57
+ )
58
+ }
59
+
60
+ export const ThemeEditor = () => {
61
+ const { updateResourceContent } = useResource('PCX53TaGviq4_8KvK-VOp')
62
+ const [isEditorOpen, setIsEditorOpen] = useState(false)
63
+ const [viewCount, setViewCount] = useState(0)
64
+ // const [theme, temporarilyUpdateTheme] = useTheme()
65
+ const theme = {}
66
+ const temporarilyUpdateTheme = () => {}
67
+
68
+ const toggleStyles = useMemo(() => !isEditorOpen
69
+ ? blobStyles
70
+ : { ...blobStyles, transform: 'rotate(-45deg)' }, [isEditorOpen])
71
+
72
+ const onToggle = useCallback(() => {
73
+ setIsEditorOpen(!isEditorOpen)
74
+ }, [isEditorOpen, setIsEditorOpen])
75
+
76
+ const onThemeChange = (event) => {
77
+
78
+ const name = event.target.dataset.name
79
+ const updatedValue = event.target.value
80
+
81
+ if (!name) return
82
+ if (!updatedValue) return
83
+
84
+ temporarilyUpdateTheme(theme => ({
85
+ ...theme,
86
+ [name]: updatedValue
87
+ }))
88
+
89
+ }
90
+
91
+ const onSaveTheme = event => {
92
+ event.preventDefault()
93
+ updateResourceContent(theme)
94
+ }
95
+
96
+ useEffect(() => {
97
+ if (!isEditorOpen) return
98
+ const views = document.querySelectorAll('[data-view]')
99
+ views.forEach(view => view.style.border = '1px solid red')
100
+ setViewCount(views.length)
101
+ }, [isEditorOpen])
102
+
103
+ return (
104
+ <Overlay isVisible={true} style={overlayStyles}>
105
+
106
+ {
107
+ isEditorOpen && (
108
+ <div style={editorContainerStyles}>
109
+ <View surface="primary" roundness="m" gap="m" style={editorStyles}>
110
+ <View as="form" gap="s" onSubmit={onSaveTheme} onChange={onThemeChange}>
111
+ {Object.entries(theme).map(([name, value]) => (
112
+ <div style={{ marginBottom: '16px' }}>
113
+ <label style={{ display: 'block', fontFamily: 'sans-serif', marginBottom: '4px', fontWeight: 'bold' }}>{name}</label>
114
+ <input value={value} data-name={name} style={{ width: '100%', padding: '4px' }}/>
115
+ </div>
116
+ ))}
117
+ <Button type="submit" variant="cta">
118
+ Save
119
+ </Button>
120
+ </View>
121
+ <ThemeSwitcher/>
122
+ <Text>Views: {viewCount}</Text>
123
+ </View>
124
+ </div>
125
+ )
126
+ }
127
+
128
+ <Button variant="cta" prefix="math-plus" style={toggleStyles} onClick={onToggle} />
129
+
130
+ </Overlay>
131
+ )
132
+ }
@@ -0,0 +1,16 @@
1
+ import React from 'react'
2
+ import { ThemeEditor } from './ThemeEditor.jsx'
3
+
4
+ export default {
5
+ title: 'Connected components/ThemeEditor',
6
+ component: ThemeEditor,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ workspaceId: '36zDqF0TKZZ5KkJdyg7NH'
10
+ },
11
+ }
12
+
13
+ const Story = props => <ThemeEditor {...props}/>
14
+
15
+ export const Default = Story.bind({})
16
+ Default.args = { }
@@ -0,0 +1 @@
1
+ export * from './ThemeEditor.jsx'
@@ -0,0 +1,9 @@
1
+ import { useResource, AsyncStatus } from '@ossy/sdk-react'
2
+ import { Theme } from '@ossy/design-system'
3
+
4
+ export const ThemeProvider = props => {
5
+ const { status, resource: theme } = useResource('PCX53TaGviq4_8KvK-VOp')
6
+ return status === AsyncStatus.Success
7
+ ? <Theme theme={theme.data} {...props}/>
8
+ : <></>
9
+ }
@@ -0,0 +1,16 @@
1
+ import React from 'react'
2
+ import { ThemeProvider } from './ThemeProvider.jsx'
3
+
4
+ export default {
5
+ title: 'Connected components/ThemeProvider',
6
+ component: ThemeProvider,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ workspaceId: '36zDqF0TKZZ5KkJdyg7NH'
10
+ },
11
+ }
12
+
13
+ const Story = props => <ThemeProvider {...props}/>
14
+
15
+ export const Default = Story.bind({})
16
+ Default.args = { }
@@ -0,0 +1 @@
1
+ export * from './ThemeProvider.jsx'
@@ -0,0 +1 @@
1
+ export * from './useActivePageLocation.js'
@@ -0,0 +1,54 @@
1
+ import { useAppSettings } from '../app/AppSettings.jsx'
2
+ const appendSlash = string => string[string.length - 1] === '/'
3
+ ? string : `${string}/`
4
+
5
+ const prependSlash = string => string[0] === '/'
6
+ ? string : `/${string}`
7
+
8
+ const padWithSlash = string => appendSlash(prependSlash(string))
9
+
10
+ const Predicates = {
11
+ byLength: desiredLength => route => {
12
+ const routeParts = route.split('/').filter(x => !!x)
13
+ return routeParts.length === desiredLength
14
+ },
15
+ byParamPlaceHolders: activePathname => route => {
16
+ const routeParts = route.split('/').filter(x => !!x).reduce(
17
+ (parts, part) => part.startsWith(':') ? [...parts, '.+?'] : [...parts, part],
18
+ []
19
+ ).join('/')
20
+
21
+ const regex = new RegExp(`^${padWithSlash(routeParts)}$`)
22
+ const passes = regex.test(activePathname)
23
+ return passes
24
+ }
25
+ }
26
+
27
+ export const useActivePageLocation = (path) => {
28
+ console.log('useActivePageLocation path', path)
29
+ const { routes: pages } = useAppSettings()
30
+
31
+ if (!path) return
32
+
33
+ // TODO: this needs tests because I don't think it works right
34
+ const activePathname = path === '' ? '/' : padWithSlash(path)
35
+ const registeredPageRoutes = pages.map(page => padWithSlash(page.path))
36
+ const exactRouteMatch = registeredPageRoutes.find(route => route === activePathname)
37
+ let activePageLocation
38
+
39
+ if (!!exactRouteMatch) {
40
+ activePageLocation = exactRouteMatch
41
+ } else {
42
+ const activePathnameParts = activePathname.split('/').filter(x => !!x)
43
+ const dynamicRouteMatch = registeredPageRoutes.find(route => (
44
+ Predicates.byLength(activePathnameParts.length)(route) && Predicates.byParamPlaceHolders(activePathname)(route)
45
+ ))
46
+
47
+ activePageLocation = dynamicRouteMatch
48
+ }
49
+
50
+ console.log('useActivePageLocation exactRouteMatch', exactRouteMatch)
51
+ console.log('useActivePageLocation activePageLocation', activePageLocation)
52
+
53
+ return activePageLocation
54
+ }