@ossy/resources 1.1.0 → 1.2.0

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ossy/resources",
3
3
  "description": "Resource domain — aggregate and events for the Ossy resource model",
4
- "version": "1.1.0",
4
+ "version": "1.2.0",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "./src/index.js",
@@ -22,5 +22,5 @@
22
22
  "/src",
23
23
  "README.md"
24
24
  ],
25
- "gitHead": "c71b23b5721bfd12dec0dfb4b50d945b65314898"
25
+ "gitHead": "ada54e62aeb87c197fa18891e995fbf22e23cc94"
26
26
  }
@@ -0,0 +1,27 @@
1
+ import React from 'react'
2
+ import { useResource } from '@ossy/sdk-react'
3
+ import { Stack, View } from '@ossy/design-system'
4
+
5
+ export const AudioResource = ({
6
+ resourceId,
7
+ onClose: _onClose
8
+ }) => {
9
+ const { resource } = useResource(resourceId)
10
+
11
+ return (
12
+ <Stack bordered>
13
+ <Stack.Item fill style={{ padding: '16px 8px', height: '100%' }}>
14
+
15
+ <View layout="off-center-s" inset="m" style={{ height: '100%'}}>
16
+ <View
17
+ as="audio"
18
+ controls
19
+ slot="content"
20
+ src={resource.content.src}
21
+ />
22
+ </View>
23
+
24
+ </Stack.Item>
25
+ </Stack>
26
+ )
27
+ }
@@ -0,0 +1,98 @@
1
+ import React, { useState, useRef } from 'react'
2
+ import { useResources } from '@ossy/sdk-react'
3
+ import {
4
+ Input,
5
+ Title,
6
+ Button,
7
+ View,
8
+ useInputValue,
9
+ Text
10
+ } from '@ossy/design-system'
11
+ import { useRouter } from '@ossy/router-react'
12
+
13
+ export const CreateDirectory = () => {
14
+ const router = useRouter()
15
+ const { createDirectory } = useResources()
16
+ const [directoryName, setDirectoryName] = useInputValue('')
17
+ const [error, setError] = useState()
18
+ const formRef = useRef()
19
+ const directoryLocation = router.searchParams.location || '/'
20
+
21
+ const onCreateDirectory = event => {
22
+ event.preventDefault()
23
+ setError()
24
+
25
+
26
+ if (!directoryName || directoryName.trim() === '') {
27
+ return setError('Directory name cannot be empty')
28
+ }
29
+
30
+ if (directoryName?.startsWith?.('@ossy') || directoryName?.startsWith?.('/@ossy')) {
31
+ setError('Directory name cannot start with @ossy')
32
+ return
33
+ }
34
+
35
+ formRef.current.reportValidity() && createDirectory({
36
+ name: directoryName,
37
+ location: directoryLocation
38
+ })
39
+ .then(() => {
40
+ setDirectoryName()
41
+ router.navigate(`@storage/home?location=${directoryLocation}`)
42
+ })
43
+ .catch(err => {
44
+ setError(err.message)
45
+ })
46
+ }
47
+
48
+ return (
49
+ <View gap="s" style={{ height: '100%' }}>
50
+
51
+ <Title variant="primary" style={{ marginBottom: 'var(--space-m)' }}>Create a new directory</Title>
52
+
53
+ <Text style={{ marginBottom: 'var(--space-m)' }}>
54
+ Create a new directory to organize your resources.
55
+ The new directory will be created in the location: {directoryLocation}
56
+ </Text>
57
+
58
+ <form
59
+ ref={formRef}
60
+ onSubmit={onCreateDirectory}
61
+ style={{ width: '100%', flexGrow: '1', display: 'flex', flexDirection: 'column', gap: 'var(--space-m)', justifyContent: 'space-between' }}
62
+ >
63
+
64
+ <Input
65
+ id="path"
66
+ type="text"
67
+ placeholder="Directory name"
68
+ value={directoryName}
69
+ onChange={setDirectoryName}
70
+ style={{ width: '100%', marginBottom: 'var(--space-l)' }}
71
+ />
72
+
73
+ <div>{ error }</div>
74
+
75
+
76
+ <View layout="row" style={{ gap: 'var(--space-s)', justifyContent: 'flex-end' }} >
77
+
78
+ <Button
79
+ id="cancel"
80
+ onClick={() => router.navigate('@back')}
81
+ >Cancel
82
+ </Button>
83
+
84
+ <Button
85
+ id="createDirectory"
86
+ variant="cta"
87
+ onClick={onCreateDirectory}
88
+ >Create directory
89
+ </Button>
90
+
91
+ </View>
92
+ </form>
93
+
94
+ </View>
95
+ )
96
+ }
97
+
98
+
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import { CreateDirectory } from './CreateDirectory.jsx'
3
+ import { View } from '@ossy/design-system'
4
+
5
+ export const metadata = {
6
+ id: 'create-directory',
7
+ path: {
8
+ sv: '/resources/create/mapp',
9
+ en: '/resources/create/directory',
10
+ },
11
+ }
12
+
13
+
14
+ export const CreateDirectoryPage = () => {
15
+ return (
16
+ <View layout="off-center-s" style={{ height: '100%' }}>
17
+ <View slot="content" surface="primary" roundness="m" inset="m">
18
+ <CreateDirectory/>
19
+ </View>
20
+ </View>
21
+ )
22
+ }
23
+
24
+ export default CreateDirectoryPage
@@ -0,0 +1,73 @@
1
+ import React, { useState } from 'react'
2
+ import { useResources, useResourceTemplate } from '@ossy/sdk-react'
3
+ import {
4
+ Alert,
5
+ InputTitle,
6
+ Button,
7
+ useInputValue,
8
+ Fields,
9
+ applyFieldChange,
10
+ } from '@ossy/design-system'
11
+ import { useRouter } from '@ossy/router-react'
12
+
13
+ export const CreateDocument = () => {
14
+ const router = useRouter()
15
+ const templateId = router.searchParams.templateId
16
+ const location = router.searchParams.location
17
+ const template = useResourceTemplate(templateId)
18
+ const [documentData, setDocumentData] = useState({})
19
+ const { createDocument } = useResources()
20
+ const [documentName, setDocumentName] = useInputValue()
21
+ const [error, setError] = useState()
22
+
23
+ const onCancel = () => {
24
+ setDocumentData({})
25
+ const search = new URLSearchParams({ location }).toString()
26
+ router.navigate(`@storage/home?${search}`)
27
+ }
28
+
29
+ const onFinish = () => {
30
+ setDocumentData({})
31
+ const search = new URLSearchParams({ location }).toString()
32
+ router.navigate(`@storage/home?${search}`)
33
+ }
34
+
35
+ const onCreateDocument = () => {
36
+ if (documentName === '' || documentName === undefined) {
37
+ setError('Document name needs to be set')
38
+ return ''
39
+ }
40
+
41
+ createDocument({
42
+ type: templateId,
43
+ location: location,
44
+ name: documentName,
45
+ content: documentData
46
+ })
47
+ .then(() => onFinish())
48
+ .catch(error => { setError(error.message) })
49
+ }
50
+
51
+ const updateFieldData = event => {
52
+ setDocumentData(prev => applyFieldChange(prev, event))
53
+ }
54
+
55
+ return (
56
+ <>
57
+ <InputTitle
58
+ id="document-name"
59
+ type="text"
60
+ className="d-block"
61
+ placeholder="Untitled document"
62
+ value={documentName}
63
+ onChange={setDocumentName}
64
+ />
65
+ <Fields data={documentData} onChange={updateFieldData} fields={template?.fields || []} />
66
+ { error && <Alert>{error}</Alert>}
67
+ <div style={{ display: 'flex', justifyContent: 'flex-end', paddingTop: 'var(--space-l)'}}>
68
+ <Button variant="link" onClick={onCancel}>Cancel</Button>
69
+ <Button variant="cta" onClick={onCreateDocument}>Create {template?.name}</Button>
70
+ </div>
71
+ </>
72
+ )
73
+ }
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import { View } from '@ossy/design-system'
3
+ import { CreateDocument } from './CreateDocument.jsx'
4
+
5
+ export const metadata = {
6
+ id: 'create-document',
7
+ path: {
8
+ sv: '/resources/create/dokument',
9
+ en: '/resources/create/document',
10
+ },
11
+ }
12
+
13
+
14
+ export const CreateDocumentPage = () => {
15
+ return (
16
+ <View layout="off-center-m" style={{ height: '100%' }}>
17
+ <View slot="content" surface='primary' roundness='m' inset="m">
18
+ <CreateDocument />
19
+ </View>
20
+ </View>
21
+ )
22
+ }
23
+
24
+ export default CreateDocumentPage
@@ -0,0 +1,19 @@
1
+ export const Definition = {
2
+ id: 'resources',
3
+ title: 'Free Resources',
4
+ description: `
5
+ We believe in providing value at every step of your journey with us.
6
+ That's why we've curated a collection of free resources.
7
+ Whether you're looking to enhance your creative projects or simply seeking inspiration,
8
+ explore the gallery below to discover valuable assets that align with your vision.
9
+ We hope you find them useful, and we're here if you have any questions!
10
+ `,
11
+ module: {
12
+ id: 'resources',
13
+ enabled: true
14
+ },
15
+ statuses: ['beta'],
16
+ actions: ['resources.create', 'resources.update-content', 'resources.remove'],
17
+ views: ['home.page', 'resources.list', 'resources.get'],
18
+ tasks: []
19
+ }
@@ -0,0 +1,48 @@
1
+ import React from 'react'
2
+ import { useResource, useResourceTemplate } from '@ossy/sdk-react'
3
+ import {
4
+ Text,
5
+ View,
6
+ DelayedRender,
7
+ Fields,
8
+ } from '@ossy/design-system'
9
+
10
+ export const DocumentEdit = ({
11
+ resourceId,
12
+ form,
13
+ }) => {
14
+ const { resource } = useResource(resourceId)
15
+
16
+ const template = useResourceTemplate(resource.type)
17
+
18
+ if (template.fields && form.data) {
19
+ return (
20
+ <View style={{ padding: '16px 0' }}>
21
+ <Fields data={form.data} onChange={form.onChange} fields={template.fields} />
22
+ </View>
23
+ )
24
+ }
25
+
26
+ // Loading
27
+ if (template.fields && !form.data) {
28
+ return (
29
+ <DelayedRender>
30
+ <View style={{ padding: '16px 0' }}>
31
+ Loading...
32
+ </View>
33
+ </DelayedRender>
34
+ )
35
+ }
36
+
37
+ return (
38
+ <View style={{ padding: '16px 0' }}>
39
+ <View inset="m" >
40
+ <Text>
41
+ This documents template has been deleted and can therefore not be edited
42
+ </Text>
43
+ </View>
44
+ </View>
45
+ )
46
+
47
+
48
+ }
@@ -0,0 +1,32 @@
1
+ import React from 'react'
2
+ import { pipe, keys, map } from 'ramda'
3
+ import { useResource, useResourceTemplate } from '@ossy/sdk-react'
4
+ import { Text, View } from '@ossy/design-system'
5
+
6
+ export const DocumentView = ({
7
+ resourceId
8
+ }) => {
9
+ const { resource } = useResource(resourceId)
10
+ const template = useResourceTemplate(resource.type)
11
+
12
+ return (
13
+ <View style={{ padding: '16px 0' }}>
14
+ <View gap="m">
15
+ {
16
+ !!resource?.content && (template.fields || [])
17
+ .map(field => ({ name: field.name, value: resource?.content?.[field.name] }))
18
+ .map(field => (
19
+ <View gap="s" key={field.name}>
20
+ <Text style={{ fontWeight: 'bold' }} >{field.name}</Text>
21
+ {
22
+ typeof field.value === 'object'
23
+ ? pipe(keys, map(key => field.value[key] && <div>{key}</div>))(field.value)
24
+ : <Text style={{ maxWidth: '500px' }}>{field.value}</Text>
25
+ }
26
+ </View>
27
+ ))
28
+ }
29
+ </View>
30
+ </View>
31
+ )
32
+ }
@@ -0,0 +1,22 @@
1
+ import React from 'react'
2
+ import { useResource } from '@ossy/sdk-react'
3
+ import {
4
+ Stack,
5
+ Image
6
+ } from '@ossy/design-system'
7
+
8
+ export const ImageResource = ({
9
+ resourceId
10
+ }) => {
11
+ const { resource } = useResource(resourceId)
12
+
13
+ return (
14
+ <div style={{ display: 'flex', justifyContent: 'center', padding: 'var(--space-m) var(--space-s) var(--space-xl)' }}>
15
+ <Image
16
+ src={resource?.content?.sizes?.galleryLarge || resource.content.src}
17
+ placeholderSrc={resource?.content?.sizes?.['loader-square-blurred-after'] || resource.content.src}
18
+ style={{ width: 'auto', height: '400px', margin: 'var(--space-m) auto var(--space-l)' }}
19
+ />
20
+ </div>
21
+ )
22
+ }
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+ import { useResource } from '@ossy/sdk-react'
3
+ import { Stack } from '@ossy/design-system'
4
+
5
+ export const PDFResource = ({
6
+ resourceId
7
+ }) => {
8
+ const { resource } = useResource(resourceId)
9
+
10
+ return (
11
+ <Stack bordered>
12
+ <Stack.Item fill>
13
+ <Stack bordered>
14
+
15
+
16
+
17
+ <Stack.Item fill style={{ padding: '16px 8px' }}>
18
+
19
+ <div style={{ display: 'flex', justifyContent: 'center' }}>
20
+ <embed
21
+ src={resource.content.src}
22
+ type={resource.type}
23
+ width="100%"
24
+ height="800px"
25
+ />
26
+ </div>
27
+ </Stack.Item>
28
+
29
+ </Stack>
30
+ </Stack.Item>
31
+ </Stack>
32
+ )
33
+ }
@@ -0,0 +1,145 @@
1
+ import React from 'react'
2
+ import { useResource, AsyncStatus } from '@ossy/sdk-react'
3
+ import { Switch, View, DelayedRender, Button, Icon, PageSection, Title, Text, Tags, ImageCard } from '@ossy/design-system'
4
+ import { useRouter } from '@ossy/router-react'
5
+
6
+
7
+ export const ResourceContentPage = (props) => {
8
+ const router = useRouter()
9
+ const resourceId = router.params.resourceId
10
+ const { status, resource } = useResource(resourceId)
11
+
12
+ return (
13
+ <View {...props} slot="content" style={{ flexDirection: 'column', wrap: 'no-wrap', height: '100%' }}>
14
+
15
+ <style>
16
+ {`
17
+
18
+ .resource-content-page__resource-container {
19
+ height: 100%;
20
+ margin: 0 auto;
21
+ display: flex;
22
+ flex-direction: column;
23
+ wrap: wrap;
24
+ gap: var(--space-m);
25
+ }
26
+
27
+ .resource-content-page__text-view {
28
+ display: flex;
29
+ flex-direction: column;
30
+ gap: var(--space-m);
31
+ padding: var(--space-s);
32
+ max-width: 500px;
33
+ }
34
+
35
+ @media(min-width: 768px) {
36
+ .resource-content-page__resource-container {
37
+ display: grid;
38
+ grid-template-columns: 1fr 2fr;
39
+ grid-template-rows: auto;
40
+
41
+ }
42
+
43
+ .resource-content-page__text-view {
44
+ padding: var(--space-m);
45
+ order: 2;
46
+ }
47
+
48
+ }
49
+ `}
50
+ </style>
51
+
52
+ <PageSection maxWidth="xl">
53
+
54
+ <View style={{ padding: '0 ar(--space-l)'}} >
55
+
56
+ <View layout="row" style={{ justifyContent: 'space-between', borderRadius: 'var(--space-l)', padding: 'var(--space-xxs)', background: 'transparent' }}>
57
+ <Button variant="neutral" onClick={() => router.back()} style={{ padding: 'var(--space-xs)', borderRadius: '50%' }}>
58
+ <Icon name="Previous" />
59
+ </Button>
60
+ </View>
61
+
62
+ </View>
63
+
64
+ </PageSection>
65
+
66
+ <View layout="off-center" style={{ flexGrow: '1' }}>
67
+ <View slot="content" style={{ padding: 'var(--space-m) var(--space-m) var(--space-xxl)'}}>
68
+ <Switch on={status}>
69
+
70
+ <Switch.Case match={[AsyncStatus.Error]}>
71
+ Something went wrong
72
+ </Switch.Case>
73
+
74
+ <Switch.Case match={[AsyncStatus.Loading, AsyncStatus.NotInitialized]}>
75
+ <DelayedRender>
76
+ Loading...
77
+ </DelayedRender>
78
+ </Switch.Case>
79
+
80
+ <Switch.Case match={[AsyncStatus.Success]}>
81
+
82
+ <PageSection maxWidth="l">
83
+ <div className="resource-content-page__resource-container">
84
+
85
+ <View gap="l" className="resource-content-page__text-view">
86
+
87
+ <View gap="m">
88
+ <Title>{resource?.name}</Title>
89
+ <Text>{resource?.content?.description}</Text>
90
+ </View>
91
+
92
+ <View layout="row" gap="m">
93
+ <Button
94
+ variant="cta"
95
+ target="_blank"
96
+ href={resource?.content?.src}
97
+ download={resource?.name}
98
+ suffix="software-download"
99
+ >Download
100
+ </Button>
101
+ </View>
102
+
103
+ <View gap="m">
104
+ <Text variant="s" style={{ fontWeight: 'bold' }}>Tags</Text>
105
+ <Tags tags={resource?.content?.tags}/>
106
+ </View>
107
+
108
+ </View>
109
+
110
+ {
111
+ !!resource && (
112
+ <ImageCard
113
+ onClick={() => { }}
114
+ src={resource?.content?.sizes?.galleryLarge || resource?.content?.src}
115
+ placeholderSrc={resource?.content?.sizes?.['loader-square-blurred-after'] || resource?.content?.src}
116
+ style={{ pageBreakInside: 'avoid', order: 1 }}
117
+ />
118
+ )
119
+ }
120
+
121
+ </div>
122
+ </PageSection>
123
+
124
+ </Switch.Case>
125
+
126
+ </Switch>
127
+ </View>
128
+ </View>
129
+
130
+ </View>
131
+ )
132
+ }
133
+
134
+ // {
135
+ // !!resource && (
136
+ // <Button
137
+ // as="a"
138
+ // href="https://d1yuixo7x29bj4.cloudfront.net/36zDqF0TKZZ5KkJdyg7NH/MRHX4agbiHC9p3N9_Wzfd.png"
139
+ // download
140
+ // variant="cta"
141
+ // >
142
+ // Download
143
+ // </Button>
144
+ // )
145
+ // }
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+ import { ResourceContentPage } from './ResourceContentPage.jsx'
3
+
4
+ export default {
5
+ title: 'Websites/Ossy/ResourceContentPage',
6
+ component: ResourceContentPage,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ workspaceId: '36zDqF0TKZZ5KkJdyg7NH',
10
+ params: {
11
+ resourceId: 'yBa6GdMeHg2EQr-u5xDd3'
12
+ }
13
+ },
14
+ }
15
+
16
+ const Story = props => <ResourceContentPage {...props}/>
17
+
18
+ export const Default = Story.bind({})
19
+ Default.args = { }
@@ -0,0 +1,28 @@
1
+ import React from 'react'
2
+ import { useResource, useResourceTemplate } from '@ossy/sdk-react'
3
+ import { View, Text } from '@ossy/design-system'
4
+
5
+ export const ResourceDescription = ({ resourceId }) => {
6
+ const { resource } = useResource(resourceId)
7
+ const template = useResourceTemplate(resource.type)
8
+
9
+ const description = resource?.content?.description;
10
+
11
+ if (!description) {
12
+ return (
13
+ <View>
14
+ <Text variant="small">
15
+ No description available.
16
+ </Text>
17
+ </View>
18
+ )
19
+ }
20
+
21
+ return (
22
+ <View style={{ maxWidth: '450px' }}>
23
+ <Text variant="small">
24
+ {description}
25
+ </Text>
26
+ </View>
27
+ )
28
+ }