@ossy/resources 1.1.0 → 1.2.1

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.
@@ -0,0 +1,272 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import { useWorkspace, useResource, useResourceTemplate } from '@ossy/sdk-react'
3
+ import {
4
+ Title,
5
+ Overlay,
6
+ Switch,
7
+ Stack,
8
+ Guide,
9
+ View,
10
+ Text,
11
+ Button,
12
+ InputTitle,
13
+ useInputValue,
14
+ } from '@ossy/design-system'
15
+ import { ResourceFactory } from './ResourceFactory.jsx'
16
+ import { useRouter } from '@ossy/router-react'
17
+ import { ResourceDetails } from './ResourceDetails.jsx'
18
+ import { ResourceTags } from './ResourceTags.jsx'
19
+ import { ResourceDescription } from './ResourceDescription.jsx'
20
+ import { useForm } from './useForm.js'
21
+
22
+ const ViewMode = {
23
+ Closed: 'Closed',
24
+ View: 'View',
25
+ Edit: 'Edit'
26
+ }
27
+
28
+ const Overlays = {
29
+ None: 'None',
30
+ Removedirectory : 'RemoveDirectory'
31
+ }
32
+
33
+ const DefaultViewModes = {
34
+ 'panel-resource-content': ViewMode.View,
35
+ 'panel-header': ViewMode.View,
36
+ 'panel-resource-details': ViewMode.Closed,
37
+ 'panel-resource-description': ViewMode.Closed,
38
+ 'panel-resource-tags': ViewMode.Closed,
39
+ }
40
+
41
+ export const ResourcePanel = ({
42
+ resourceId,
43
+ onClose: _onClose,
44
+ extraPanels = [],
45
+ }) => {
46
+ const router = useRouter()
47
+ const { workspace } = useWorkspace()
48
+ const [overlay, setOverlay] = useState(Overlays.None)
49
+ const [error] = useState()
50
+ const [resourceName, setResourceName] = useInputValue('')
51
+ const [panelViewModes, setPanelViewModes] = useState(DefaultViewModes)
52
+
53
+ const {
54
+ resource,
55
+ removeResource,
56
+ updateResourceContent,
57
+ renameResource
58
+ } = useResource(resourceId)
59
+
60
+ const form = useForm({ defaultData: resource.content })
61
+
62
+ const onCloseResource = () => {
63
+ if (!_onClose) return
64
+ setPanelViewModes(DefaultViewModes)
65
+ setResourceName('')
66
+ _onClose()
67
+ }
68
+
69
+ const onRenameResource = () => {
70
+ if (resourceName === resource.name) return
71
+ renameResource(resourceName)
72
+ .then(() => setPanelViewModes(x => ({ ...x, 'panel-header': ViewMode.View })))
73
+ }
74
+
75
+ const onUpdateResource = () => {
76
+ updateResourceContent(form.data)
77
+ .then(() => setPanelViewModes(x => ({ ...x, 'panel-resource-content': ViewMode.View })))
78
+ .catch(() => alert('Something went wrong!'))
79
+ }
80
+
81
+ const onRemoveResource = () => {
82
+ removeResource()
83
+ .then(onCloseResource)
84
+ }
85
+
86
+ const onPanelToggle = (panelId) => {
87
+ setPanelViewModes(prev => {
88
+ const currentMode = prev[panelId] || ViewMode.Closed
89
+ const newMode = currentMode === ViewMode.Closed ? ViewMode.View : ViewMode.Closed
90
+ return { ...prev, [panelId]: newMode }
91
+ })
92
+ }
93
+
94
+ useEffect(() => {
95
+ setResourceName(resource.name)
96
+ }, [resource])
97
+
98
+ const panels = [
99
+ {
100
+ id: 'panel-resource-content',
101
+ label: 'View',
102
+ suffix: panelViewModes['panel-resource-content'] === ViewMode.Edit
103
+ ? [
104
+ { prefix: 'close', variant: 'command', onClick: () => setPanelViewModes(x => ({ ...x, 'panel-resource-content': ViewMode.View })) },
105
+ { prefix: 'check', variant: 'command', onClick: onUpdateResource }
106
+ ]
107
+ : [{ prefix: 'pen', variant: 'command', onClick: () => setPanelViewModes(x => ({ ...x, 'panel-resource-content': ViewMode.Edit })) }],
108
+ fill: true,
109
+ content: ResourceFactory
110
+ },
111
+ {
112
+ id: 'panel-resource-details',
113
+ label: 'Details',
114
+ content: ResourceDetails
115
+ },
116
+ {
117
+ id: 'panel-resource-description',
118
+ label: 'Description',
119
+ suffix: [{ prefix: 'copy', variant: 'command' }],
120
+ content: ResourceDescription
121
+ },
122
+ {
123
+ id: 'panel-resource-tags',
124
+ label: 'Tags',
125
+ suffix: [{ prefix: 'copy', variant: 'command' }],
126
+ content: ResourceTags
127
+ },
128
+ ...extraPanels,
129
+ ]
130
+
131
+ if (!resourceId) {
132
+ return <></>
133
+ }
134
+
135
+ return (
136
+ <Stack surface="primary" bordered style={{ height: '100%', width: '50%' }}>
137
+
138
+ <style href="@design-system/scroll" precedence='low'>{`
139
+ [data-scroll-hide] {
140
+ -ms-overflow-style: none; /* For Internet Explorer and Edge */
141
+ scrollbar-width: none; /* For Firefox */
142
+ }
143
+
144
+ .hide-scrollbar::-webkit-scrollbar {
145
+ display: none; /* For Chrome, Safari, and Opera */
146
+ }
147
+ `}</style>
148
+
149
+ {
150
+ !!error && (
151
+ <Stack.Item>
152
+ {error}
153
+ </Stack.Item>
154
+ )
155
+ }
156
+
157
+ <Stack.Item>
158
+
159
+ <Stack horizontal style={{ height: '48px', alignItems: 'center', gap: '4px' }}>
160
+
161
+ <Switch on={panelViewModes['panel-header']}>
162
+
163
+ <Switch.Case match={[ViewMode.View]}>
164
+
165
+ <Stack.Item fill surface="primary" style={{ padding: '4px 8px' }}>
166
+ <Title as="h3" variant="tertiary">{resourceName}</Title>
167
+ </Stack.Item>
168
+
169
+ <Button prefix="trash-empty" variant="command-danger" onClick={onRemoveResource}/>
170
+ <Button prefix="pen" variant="command" onClick={() => setPanelViewModes(x => ({ ...x, 'panel-header': ViewMode.Edit }))} />
171
+ { !!_onClose && (<Button prefix="close" variant="command" onClick={onCloseResource} /> ) }
172
+
173
+ </Switch.Case>
174
+
175
+ <Switch.Case match={[ViewMode.Edit]}>
176
+
177
+ <Stack.Item fill surface="primary" style={{ padding: '4px 8px' }}>
178
+ <InputTitle
179
+ id="document-name"
180
+ type="text"
181
+ style={{ display: 'block', width: '100%', padding: '16px 8px' }}
182
+ value={resourceName}
183
+ onChange={setResourceName}
184
+ onBlur={onRenameResource}
185
+ />
186
+ </Stack.Item>
187
+
188
+ <Button prefix="close" variant="command" onClick={() => setPanelViewModes(x => ({ ...x, 'panel-header': ViewMode.View }))} />
189
+ <Button prefix="check" variant="command" onClick={onRenameResource}/>
190
+
191
+ </Switch.Case>
192
+
193
+ </Switch>
194
+
195
+ </Stack>
196
+
197
+ </Stack.Item>
198
+
199
+ <Stack.Item fill={true} data-scroll-hide style={{ display: 'flex', flexDirection: 'column', height: '100%', overflowY: 'auto' }}>
200
+
201
+ {panels.map(({ content: Content, ...panel }) => {
202
+ const isExpanded = [ViewMode.View, ViewMode.Edit].includes(panelViewModes[panel.id])
203
+
204
+ return (
205
+ <View surface="primary" roundness="xs" key={panel.id} style={{ flexShrink: 0, flexGrow: panel.fill && isExpanded ? 1 : undefined }}>
206
+
207
+ <View
208
+ layout="row"
209
+ inset="s"
210
+ gap="s"
211
+ alignItems="center"
212
+ style={{ height: '40px', borderBottom: isExpanded ? undefined : '1px solid var(--separator)' }}
213
+ >
214
+
215
+ <Button
216
+ variant="command"
217
+ prefix={isExpanded ? 'chevron-down' : 'chevron-right'}
218
+ onClick={() => onPanelToggle(panel.id)}
219
+ />
220
+
221
+ { panel.prefix && <Button {...panel.prefix} /> }
222
+ <Text variant="small" style={{ fontWeight: 'bold', flexGrow: 1 }}>{panel.label}</Text>
223
+ { panel.suffix && panel.suffix.map(x => <Button {...x} />) }
224
+
225
+ </View>
226
+
227
+ {isExpanded && Content && (
228
+ <View style={{
229
+ flexGrow: 1,
230
+ overflowY: 'auto',
231
+ borderBottom: '1px solid var(--separator)',
232
+ padding: 'var(--space-s) var(--space-m) var(--space-m) calc(var(--space-l) + var(--space-m))' }
233
+ }>
234
+ <Content resourceId={resourceId} mode={panelViewModes[panel.id]} form={form} />
235
+ </View>
236
+ )}
237
+
238
+ </View>
239
+ )
240
+ })}
241
+
242
+ </Stack.Item>
243
+
244
+ {
245
+ overlay === Overlays.RemoveDirectory && (
246
+ <Overlay isVisible={true} onClose={() => setOverlay(Overlays.None)}>
247
+ <View layout="off-center-s" style={{ height: '100%' }}>
248
+ <View slot="content">
249
+ <View surface="primary" roundness="s">
250
+ <View surface="primary" inset="l" roundness="s">
251
+ <Guide
252
+ title="Remove directory"
253
+ text="Are you sure you want to remove this directory and everything in it?"
254
+ actions={[
255
+ { label: 'Cancel', variant: "command", onClick: () => setOverlay(Overlays.None) },
256
+ { label: 'Remove', variant: 'command-danger', onClick: () => {
257
+ removeResource(resourceId)
258
+ setOverlay(Overlays.None)
259
+ }}
260
+ ]}
261
+ />
262
+ </View>
263
+ </View>
264
+ </View>
265
+ </View>
266
+ </Overlay>
267
+ )
268
+ }
269
+
270
+ </Stack>
271
+ )
272
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react'
2
+ import { useResource, useResourceTemplate } from '@ossy/sdk-react'
3
+ import { View, Tags, Text } from '@ossy/design-system'
4
+
5
+ export const ResourceTags = ({ resourceId }) => {
6
+ const { resource } = useResource(resourceId)
7
+ const template = useResourceTemplate(resource.type)
8
+
9
+ let resourceContentTags = resource?.content?.Tags || []
10
+
11
+ if (typeof resourceContentTags === 'string') {
12
+ resourceContentTags = resourceContentTags.split(',').map(tag => tag.trim())
13
+ }
14
+
15
+ let resourceContenttags = resource?.content?.tags || []
16
+
17
+ if (typeof resourceContenttags === 'string') {
18
+ resourceContenttags = resourceContenttags.split(',').map(tag => tag.trim())
19
+ }
20
+
21
+
22
+ const resourceTags = resource?.tags || []
23
+ const allTags = [...resourceContentTags, ...resourceContenttags, ...resourceTags].sort()
24
+
25
+ if (allTags.length === 0) {
26
+ return (
27
+ <View>
28
+ <Text variant="small">
29
+ No tags available.
30
+ </Text>
31
+ </View>
32
+ )
33
+ }
34
+
35
+ return (
36
+ <View style={{ maxWidth: '450px' }}>
37
+ <Tags size="s" gap="s" tags={allTags} />
38
+ </View>
39
+ )
40
+ }
@@ -0,0 +1,66 @@
1
+ import React from 'react'
2
+ import { SDK } from '@ossy/sdk'
3
+ import { useResources, AsyncStatus, WorkspaceProvider } from '@ossy/sdk-react'
4
+ import { Title, Text, Switch, View, ImageCard, Tags } from '@ossy/design-system'
5
+ import { useRouter } from '@ossy/router-react'
6
+ import { Definition } from './Definition.js'
7
+
8
+ const sdk = SDK.of({
9
+ /** Ossy.se workspaceID - used to fetch free resources */
10
+ workspaceId: "36zDqF0TKZZ5KkJdyg7NH"
11
+ })
12
+
13
+ const freeResourcesGridStyles = {
14
+ height: '100%',
15
+ columns: '6 200px',
16
+ columnGap: '16px'
17
+ }
18
+
19
+ export const ResourcesPage= () => {
20
+ const router = useRouter()
21
+ const { status, resources } = useResources('/publications/images/')
22
+ const tags = resources.flatMap(resource => resource?.content?.tags || [])
23
+ const tagsCount = tags.reduce((acc, t) => ({ ...acc, [t]: (acc?.[t] ?? 0) + 1 }), {})
24
+
25
+ return (
26
+ <Switch on={status}>
27
+ <Switch.Case match={[AsyncStatus.Success]}>
28
+
29
+ <main style={{
30
+ height: '100%',
31
+ gridArea: 'main',
32
+ padding: '32px 16px 0'
33
+ }}>
34
+ <View gap="l" style={{ margin: '0 auto' }}>
35
+
36
+ <View gap="m">
37
+ <Title>{Definition.title}</Title>
38
+ <Text style={{ maxWidth: '900px'}}>{Definition.description}</Text>
39
+ </View>
40
+
41
+ <WorkspaceProvider sdk={sdk}>
42
+ <section style={freeResourcesGridStyles}>
43
+ { resources.map(resource => (
44
+ <ImageCard
45
+ href={router.getHref({ id: "@resource", params: { resourceId: resource?.id } })}
46
+ src={resource?.content?.sizes?.galleryMedium || resource?.content?.src}
47
+ placeholderSrc={resource?.content?.sizes?.['loader-square-blurred-after'] || resource?.content?.src}
48
+ style={{ pageBreakInside: 'avoid', cursor: 'pointer' }}
49
+ key={resources.id}
50
+ />
51
+ ))}
52
+ </section>
53
+ </WorkspaceProvider>
54
+
55
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--space-xxs)', marginTop: '24px' }}>
56
+ <Tags tags={Object.entries(tagsCount).map(([tag, count]) => `${count} ${tag}`)} />
57
+ </div>
58
+ </View>
59
+
60
+
61
+ </main>
62
+
63
+ </Switch.Case>
64
+ </Switch>
65
+ )
66
+ }
package/src/Upload.jsx ADDED
@@ -0,0 +1,177 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import { Button, View, Text, Upload as _Upload, Icon2 } from '@ossy/design-system'
3
+ import { useRouter } from '@ossy/router-react'
4
+
5
+ const FlowStage = {
6
+ Error: 'Error',
7
+ Preview: 'Preview',
8
+ Uploading: 'Uploading',
9
+ Done: 'Done'
10
+ }
11
+
12
+ export const Upload = ({
13
+ onUpload = () => Promise.reject(),
14
+ onCancel: _onCancel = () => {},
15
+ onDone,
16
+ }) => {
17
+ const router = useRouter()
18
+ const location = router.searchParams.location
19
+ const finishUpload = onDone ?? _onCancel
20
+ const [files, setFilesMetadata] = useState([])
21
+ const flowStage = getFlowStage(files)
22
+
23
+ const uploadFiles = () => {
24
+ setFilesMetadata(files => files.map(x => ({ ...x, status: 'uploading' })))
25
+
26
+ const uploadRequests = files.map((file) =>
27
+ onUpload(file.file)
28
+ .then(() => ({...file, status: 'uploaded' }))
29
+ .catch(() => ({...file, status: 'error' }))
30
+ )
31
+
32
+ return Promise.all(uploadRequests)
33
+ .then(setFilesMetadata)
34
+ }
35
+
36
+ const remove = (file) => {
37
+ setFilesMetadata(files => files.filter(x => x.file !== file))
38
+ }
39
+
40
+ const onUserInput = (e) => {
41
+ setFilesMetadata(Array.from(e.target.files).map(file => ({ file, status: 'preview' })))
42
+ }
43
+
44
+ const onCancel = () => {
45
+ setFilesMetadata([])
46
+ _onCancel()
47
+ }
48
+
49
+ return (
50
+ <View gap="s" style={{ height: '100%' }}>
51
+ {
52
+ files.length > 0 && (
53
+ <View gap="s" style={{ flexGrow: '1', overflow: 'auto', padding: 'var(--space-m) 0' }}>
54
+ {
55
+ files.map(({ status, file }) => (
56
+ <View layout="row" gap="m" alignItems="center">
57
+ <UploadImgPreview file={file} />
58
+ <Text style={{ margin: '0', lineHeight: '1', textWrap: 'nowrap', textOverflow: 'ellipsis', flexGrow: '1' }}>{file?.name || 'Untitled'}</Text>
59
+ <View layout="row" gap="xs">
60
+ <UploadStatus status={status} size="8px" />
61
+ <Button variant="command-danger" prefix="close" size="s" onClick={() => remove(file)} />
62
+ </View>
63
+ </View>
64
+ ))
65
+ }
66
+ </View>
67
+ )
68
+ }
69
+
70
+ {files.length === 0 && (
71
+ <_Upload
72
+ type="file"
73
+ multiple
74
+ onChange={onUserInput}
75
+ style={{ flexGrow: '1', borderRadius: 'var(--space-s)' }}
76
+ />
77
+ )}
78
+
79
+ <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 'var(--space-m)' }}>
80
+ <Button
81
+ id="cancel"
82
+ onClick={onCancel}
83
+ >Cancel
84
+ </Button>
85
+
86
+ {
87
+ flowStage === FlowStage.Preview && (
88
+ <Button
89
+ id="upload"
90
+ variant="cta"
91
+ onClick={uploadFiles}
92
+ >Upload
93
+ </Button>
94
+ )
95
+ }
96
+
97
+ {
98
+ flowStage === FlowStage.Uploading && (
99
+ <Button
100
+ id="upload"
101
+ variant="cta"
102
+ disabled
103
+ >Upploading...
104
+ </Button>
105
+ )
106
+ }
107
+
108
+ {
109
+ flowStage === FlowStage.Error && (
110
+ <Button
111
+ id="upload"
112
+ variant="cta"
113
+ onClick={uploadFiles}
114
+ >Retry failed uploads
115
+ </Button>
116
+ )
117
+ }
118
+
119
+ {
120
+ flowStage === FlowStage.Done && (
121
+ <Button
122
+ id="upload"
123
+ variant="cta"
124
+ onClick={finishUpload}
125
+ >Done
126
+ </Button>
127
+ )
128
+ }
129
+ </div>
130
+ </View>
131
+ )
132
+ }
133
+
134
+
135
+
136
+ function UploadImgPreview({ file, size = "32px" }) {
137
+ const [src, setSrc] = useState()
138
+
139
+ useEffect(() => {
140
+ const reader = new FileReader()
141
+ reader.onload = (e) => setSrc(e.target.result)
142
+ reader.readAsDataURL(file)
143
+ }, [file])
144
+
145
+ return (
146
+ <View
147
+ as="img"
148
+ src={src}
149
+ width={size}
150
+ height={size}
151
+ style={{ backgroundSize: 'cover', borderRadius: 'var(--space-s)' }}
152
+ />
153
+ )
154
+ }
155
+
156
+ function UploadStatus({ status }) {
157
+ if (status === 'preview') return <></>
158
+ if (status === 'uploading') return <Icon2 name="spinner" size="s" animation="rotate" />
159
+ if (status === 'uploaded') return <Icon2 name="check" size="s" />
160
+ if (status === 'error') return <Icon2 name="close" size="s" />
161
+ }
162
+
163
+ function getFlowStage(files = []) {
164
+
165
+ if (files.length === 0) return FlowStage.Preview
166
+
167
+ const didSomeUploadsFail = files.some(({ status }) => status === 'error')
168
+ if (didSomeUploadsFail) return FlowStage.Error
169
+
170
+ const areSomeUploadsInProgress = files.some(({ status }) => status === 'uploading')
171
+ if (areSomeUploadsInProgress) return FlowStage.Uploading
172
+
173
+ const areAllFilesUploadedSuccessfully = files.every(({ status }) => status === 'uploaded')
174
+ if (areAllFilesUploadedSuccessfully) return FlowStage.Done
175
+
176
+ return FlowStage.Preview
177
+ }
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import { UploadResources } from './UploadResources.jsx'
3
+ import { View } from '@ossy/design-system'
4
+
5
+ export const metadata = {
6
+ id: 'upload-media',
7
+ path: {
8
+ sv: '/resources/ladda-upp',
9
+ en: '/resources/upload',
10
+ },
11
+ }
12
+
13
+
14
+ export const UploadPage = () => {
15
+ return (
16
+ <View layout="off-center-s" style={{ height: '100%' }}>
17
+ <View slot="content" surface="primary" roundness="m" inset="m">
18
+ <UploadResources/>
19
+ </View>
20
+ </View>
21
+ )
22
+ }
23
+
24
+ export default UploadPage
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import { useResources } from '@ossy/sdk-react'
3
+ import { Title, View, Text, Upload as _Upload } from '@ossy/design-system'
4
+ import { useRouter } from '@ossy/router-react'
5
+ import { Upload } from './Upload.jsx'
6
+
7
+ export const UploadResources = () => {
8
+ const router = useRouter()
9
+ const location = router.searchParams.location
10
+ const { uploadFile } = useResources()
11
+
12
+ return (
13
+ <View gap="s" style={{ height: '100%' }}>
14
+
15
+ <View gap="s">
16
+ <Title variant="tertiary" style={{ marginBottom: '0' }}>
17
+ Upload
18
+ </Title>
19
+ <View layout="row" gap="s">
20
+ <Text variant="small" >Location: {location}</Text>
21
+ </View>
22
+ </View>
23
+
24
+ <Upload
25
+ onUpload={(file) => uploadFile(location, file)}
26
+ onCancel={() => router.navigate(`@storage/home?location=${location}`)}
27
+ onDone={() => router.navigate(`@storage/home?location=${location}`)}
28
+ />
29
+ </View>
30
+ )
31
+ }
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import { useResource } from '@ossy/sdk-react'
3
+ import { Stack } from '@ossy/design-system'
4
+
5
+ export const VideoResource = ({
6
+ resourceId
7
+ }) => {
8
+ const { resource } = useResource(resourceId)
9
+
10
+ return (
11
+ <Stack bordered>
12
+ <Stack.Item fill style={{ padding: '16px 8px' }}>
13
+
14
+ <div style={{ display: 'flex', justifyContent: 'center' }}>
15
+ <video
16
+ controls
17
+ src={resource.content.src}
18
+ style={{ width: 'auto', height: '400px', margin: 'var(--space-l) auto' }}
19
+ />
20
+ </div>
21
+ </Stack.Item>
22
+ </Stack>
23
+ )
24
+ }
package/src/index.js CHANGED
@@ -1,2 +1,27 @@
1
1
  export * from './resource.aggregate.js'
2
2
  export * from './resources.events.js'
3
+
4
+ export * from './AudioResource.jsx'
5
+ export * from './CreateDirectory.jsx'
6
+ export * from './CreateDocument.jsx'
7
+ export * from './Definition.js'
8
+ export * from './DocumentEdit.jsx'
9
+ export * from './DocumentView.jsx'
10
+ export * from './ImageResource.jsx'
11
+ export * from './PDFResource.jsx'
12
+ export * from './ResourceContentPage.jsx'
13
+ export * from './ResourceDescription.jsx'
14
+ export * from './ResourceDetails.jsx'
15
+ export * from './ResourceDialogMove.jsx'
16
+ export * from './ResourceFactory.jsx'
17
+ export * from './ResourceGenericView.jsx'
18
+ export * from './ResourceList.jsx'
19
+ export * from './ResourcePage.jsx'
20
+ export * from './ResourcePanel.jsx'
21
+ export * from './ResourceTags.jsx'
22
+ export * from './ResourcesPage.jsx'
23
+ export * from './Upload.jsx'
24
+ export * from './UploadResources.jsx'
25
+ export * from './VideoResource.jsx'
26
+ export * from './useActivePath.jsx'
27
+ export * from './useForm.js'
@@ -0,0 +1,23 @@
1
+ import {
2
+ unless,
3
+ startsWith,
4
+ o,
5
+ endsWith
6
+ } from 'ramda'
7
+ import { useRouter } from '@ossy/router-react'
8
+ import React, { useEffect } from 'react'
9
+
10
+ const prependSlash = unless(startsWith('/'), path => `/${path}`)
11
+ const appendSlash = unless(endsWith('/'), path => `${path}/`)
12
+ const addSlashes = o(prependSlash, appendSlash)
13
+
14
+ export const useActivePath = () => {
15
+ const router = useRouter()
16
+ const activePath = addSlashes(router.searchParams.location || '/')
17
+
18
+ // useEffect(() => {
19
+ // console.log('useActivePath', activePath)
20
+ // }, [activePath])
21
+
22
+ return activePath
23
+ }