@sanity/dashboard 2.35.2 → 2.36.0-v2-studio.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.
- package/LICENSE +1 -1
- package/dts/components/dashboardWidget.d.ts +10 -0
- package/dts/legacyParts.d.ts +7 -0
- package/lib/DashboardTool.js +2 -1
- package/lib/DashboardTool.js.map +1 -0
- package/lib/components/DashboardLayout.js +2 -1
- package/lib/components/DashboardLayout.js.map +1 -0
- package/lib/components/NotFoundWidget.js +2 -1
- package/lib/components/NotFoundWidget.js.map +1 -0
- package/lib/components/WidgetGroup.js +2 -1
- package/lib/components/WidgetGroup.js.map +1 -0
- package/lib/components/dashboardWidget.js +2 -1
- package/lib/components/dashboardWidget.js.map +1 -0
- package/lib/containers/Dashboard.js +2 -1
- package/lib/containers/Dashboard.js.map +1 -0
- package/lib/containers/WidgetContainer.js +2 -1
- package/lib/containers/WidgetContainer.js.map +1 -0
- package/lib/dashboardConfig.js +2 -1
- package/lib/dashboardConfig.js.map +1 -0
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -0
- package/lib/legacyParts.js +2 -1
- package/lib/legacyParts.js.map +1 -0
- package/lib/versionedClient.js +2 -1
- package/lib/versionedClient.js.map +1 -0
- package/lib/widgets/projectInfo/ProjectInfo.js +5 -4
- package/lib/widgets/projectInfo/ProjectInfo.js.map +1 -0
- package/lib/widgets/projectInfo/index.js +2 -1
- package/lib/widgets/projectInfo/index.js.map +1 -0
- package/lib/widgets/projectUsers/ProjectUsers.js +2 -1
- package/lib/widgets/projectUsers/ProjectUsers.js.map +1 -0
- package/lib/widgets/projectUsers/index.js +2 -1
- package/lib/widgets/projectUsers/index.js.map +1 -0
- package/lib/widgets/sanityTutorials/SanityTutorials.js +2 -1
- package/lib/widgets/sanityTutorials/SanityTutorials.js.map +1 -0
- package/lib/widgets/sanityTutorials/Tutorial.js +2 -1
- package/lib/widgets/sanityTutorials/Tutorial.js.map +1 -0
- package/lib/widgets/sanityTutorials/dataAdapter.js +2 -1
- package/lib/widgets/sanityTutorials/dataAdapter.js.map +1 -0
- package/lib/widgets/sanityTutorials/index.js +2 -1
- package/lib/widgets/sanityTutorials/index.js.map +1 -0
- package/package.json +52 -20
- package/sanity.json +0 -4
- package/src/DashboardTool.js +30 -0
- package/src/components/DashboardLayout.js +42 -0
- package/src/components/NotFoundWidget.js +41 -0
- package/src/components/WidgetGroup.js +98 -0
- package/src/components/dashboardWidget.tsx +76 -0
- package/src/containers/Dashboard.js +21 -0
- package/src/containers/WidgetContainer.js +57 -0
- package/src/dashboardConfig.js +13 -0
- package/src/index.js +2 -0
- package/src/legacyParts.ts +11 -0
- package/src/versionedClient.js +9 -0
- package/src/widget.css +62 -0
- package/src/widgets/projectInfo/ProjectInfo.js +232 -0
- package/src/widgets/projectInfo/index.js +7 -0
- package/src/widgets/projectUsers/ProjectUsers.js +176 -0
- package/src/widgets/projectUsers/index.js +6 -0
- package/src/widgets/sanityTutorials/SanityTutorials.js +152 -0
- package/src/widgets/sanityTutorials/Tutorial.js +158 -0
- package/src/widgets/sanityTutorials/dataAdapter.js +17 -0
- package/src/widgets/sanityTutorials/index.js +7 -0
- package/.babelrc +0 -4
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// @todo: remove the following line when part imports has been removed from this file
|
|
2
|
+
///<reference types="@sanity/types/parts" />
|
|
3
|
+
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import {map, switchMap} from 'rxjs/operators'
|
|
6
|
+
import {Stack, Card, Box, Text, Button} from '@sanity/ui'
|
|
7
|
+
import {RobotIcon} from '@sanity/icons'
|
|
8
|
+
import styled from 'styled-components'
|
|
9
|
+
import {DefaultPreview} from '@sanity/base/components'
|
|
10
|
+
import Spinner from 'part:@sanity/components/loading/spinner'
|
|
11
|
+
import {versionedClient} from '../../versionedClient'
|
|
12
|
+
import {DashboardWidget} from '../../'
|
|
13
|
+
import {userStore} from '../../legacyParts'
|
|
14
|
+
|
|
15
|
+
const AvatarWrapper = styled(Card)`
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
border-radius: 50%;
|
|
18
|
+
border-color: transparent;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
|
|
23
|
+
& > img {
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: auto;
|
|
26
|
+
}
|
|
27
|
+
`
|
|
28
|
+
|
|
29
|
+
function getInviteUrl(projectId) {
|
|
30
|
+
return `https://manage.sanity.io/projects/${projectId}/team/invite`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function sortUsersByRobotStatus(userA, userB, project) {
|
|
34
|
+
const {members} = project
|
|
35
|
+
const membershipA = members.find((member) => member.id === userA.id)
|
|
36
|
+
const membershipB = members.find((member) => member.id === userB.id)
|
|
37
|
+
if (membershipA.isRobot) {
|
|
38
|
+
return 1
|
|
39
|
+
}
|
|
40
|
+
if (membershipB.isRobot) {
|
|
41
|
+
return -1
|
|
42
|
+
}
|
|
43
|
+
return 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class ProjectUsers extends React.PureComponent {
|
|
47
|
+
static propTypes = {}
|
|
48
|
+
static defaultProps = {}
|
|
49
|
+
|
|
50
|
+
state = {
|
|
51
|
+
project: null,
|
|
52
|
+
users: null,
|
|
53
|
+
error: null,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
componentDidMount() {
|
|
57
|
+
this.fetchData()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
componentWillUnmount() {
|
|
61
|
+
if (this.subscription) {
|
|
62
|
+
this.subscription.unsubscribe()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fetchData() {
|
|
67
|
+
if (this.subscription) {
|
|
68
|
+
this.subscription.unsubscribe()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const {projectId} = versionedClient.config()
|
|
72
|
+
this.subscription = versionedClient.observable
|
|
73
|
+
.request({
|
|
74
|
+
uri: `/projects/${projectId}`,
|
|
75
|
+
})
|
|
76
|
+
.pipe(
|
|
77
|
+
switchMap((project) =>
|
|
78
|
+
userStore.observable
|
|
79
|
+
.getUsers(project.members.map((mem) => mem.id))
|
|
80
|
+
.pipe(map((users) => ({project, users})))
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
.subscribe({
|
|
84
|
+
next: ({users, project}) =>
|
|
85
|
+
this.setState({
|
|
86
|
+
project,
|
|
87
|
+
users: (Array.isArray(users) ? users : [users]).sort((userA, userB) =>
|
|
88
|
+
sortUsersByRobotStatus(userA, userB, project)
|
|
89
|
+
),
|
|
90
|
+
}),
|
|
91
|
+
error: (error) => this.setState({error}),
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
handleRetryFetch = () => {
|
|
96
|
+
this.fetchData()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
render() {
|
|
100
|
+
const {error, project, users} = this.state
|
|
101
|
+
const isLoading = !users || !project
|
|
102
|
+
|
|
103
|
+
if (error) {
|
|
104
|
+
return (
|
|
105
|
+
<DashboardWidget header="Project users">
|
|
106
|
+
<Box padding={4}>
|
|
107
|
+
<Text>
|
|
108
|
+
Something went wrong while fetching data. You could{' '}
|
|
109
|
+
<a
|
|
110
|
+
onClick={this.handleRetryFetch}
|
|
111
|
+
title="Retry users fetch"
|
|
112
|
+
style={{cursor: 'pointer'}}
|
|
113
|
+
>
|
|
114
|
+
retry
|
|
115
|
+
</a>
|
|
116
|
+
..?
|
|
117
|
+
</Text>
|
|
118
|
+
</Box>
|
|
119
|
+
</DashboardWidget>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<DashboardWidget
|
|
125
|
+
header="Project users"
|
|
126
|
+
footer={
|
|
127
|
+
<Button
|
|
128
|
+
style={{width: '100%'}}
|
|
129
|
+
paddingX={2}
|
|
130
|
+
paddingY={4}
|
|
131
|
+
mode="bleed"
|
|
132
|
+
tone="primary"
|
|
133
|
+
text="Invite members"
|
|
134
|
+
as="a"
|
|
135
|
+
loading={isLoading}
|
|
136
|
+
href={isLoading ? undefined : getInviteUrl(project.id)}
|
|
137
|
+
/>
|
|
138
|
+
}
|
|
139
|
+
>
|
|
140
|
+
{isLoading && (
|
|
141
|
+
<Card padding={4}>
|
|
142
|
+
<Spinner center message="Loading..." />
|
|
143
|
+
</Card>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
{!isLoading && (
|
|
147
|
+
<Stack space={3} padding={3}>
|
|
148
|
+
{users.map((user) => {
|
|
149
|
+
const membership = project.members.find((member) => member.id === user.id)
|
|
150
|
+
const media = membership.isRobot ? (
|
|
151
|
+
<Text size={3}>
|
|
152
|
+
<RobotIcon />
|
|
153
|
+
</Text>
|
|
154
|
+
) : (
|
|
155
|
+
<AvatarWrapper tone="transparent">
|
|
156
|
+
{user?.imageUrl && <img src={user.imageUrl} alt={user?.displayName} />}
|
|
157
|
+
</AvatarWrapper>
|
|
158
|
+
)
|
|
159
|
+
return (
|
|
160
|
+
<Box key={user.id}>
|
|
161
|
+
<DefaultPreview
|
|
162
|
+
title={user.displayName}
|
|
163
|
+
subtitle={membership.role}
|
|
164
|
+
media={media}
|
|
165
|
+
/>
|
|
166
|
+
</Box>
|
|
167
|
+
)
|
|
168
|
+
})}
|
|
169
|
+
</Stack>
|
|
170
|
+
)}
|
|
171
|
+
</DashboardWidget>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export default ProjectUsers
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import {Flex, Grid, Stack, Heading, Container, Card, Text, Button} from '@sanity/ui'
|
|
4
|
+
import Tutorial from './Tutorial'
|
|
5
|
+
import dataAdapter from './dataAdapter'
|
|
6
|
+
|
|
7
|
+
const FeedItem = ({feedItem}) => {
|
|
8
|
+
// Check to see if the feed item has the content needed to render an item with a link and poster image
|
|
9
|
+
const isEmpty =
|
|
10
|
+
!feedItem.title || (!feedItem.guideOrTutorial && !feedItem.externalLink && !feedItem.feedItems)
|
|
11
|
+
|
|
12
|
+
if (isEmpty) {
|
|
13
|
+
return null
|
|
14
|
+
}
|
|
15
|
+
const subtitle = feedItem.description
|
|
16
|
+
const {guideOrTutorial = {}} = feedItem
|
|
17
|
+
return (
|
|
18
|
+
<Tutorial
|
|
19
|
+
title={feedItem.title}
|
|
20
|
+
href={createUrl(guideOrTutorial.slug, guideOrTutorial._type) || feedItem.externalLink}
|
|
21
|
+
presenterSubtitle={subtitle}
|
|
22
|
+
showPlayIcon={feedItem.hasVideo}
|
|
23
|
+
posterURL={feedItem.poster ? urlBuilder.image(feedItem.poster).height(360).url() : undefined}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const {urlBuilder, getFeed} = dataAdapter
|
|
29
|
+
|
|
30
|
+
function createUrl(slug, type) {
|
|
31
|
+
if (type === 'tutorial') {
|
|
32
|
+
return `https://www.sanity.io/docs/tutorials/${slug.current}`
|
|
33
|
+
} else if (type === 'guide') {
|
|
34
|
+
return `https://www.sanity.io/docs/guides/${slug.current}`
|
|
35
|
+
}
|
|
36
|
+
return false
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class SanityTutorials extends React.Component {
|
|
40
|
+
static propTypes = {
|
|
41
|
+
templateRepoId: PropTypes.string,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static defaultProps = {
|
|
45
|
+
templateRepoId: null,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
state = {
|
|
49
|
+
feedItems: [],
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
componentDidMount() {
|
|
53
|
+
const {templateRepoId} = this.props
|
|
54
|
+
this.subscription = getFeed(templateRepoId).subscribe((response) => {
|
|
55
|
+
this.setState({
|
|
56
|
+
title: response.title,
|
|
57
|
+
feedItems: response.items,
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
componentWillUnmount() {
|
|
63
|
+
if (this.subscription) {
|
|
64
|
+
this.subscription.unsubscribe()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
render() {
|
|
69
|
+
const {title = 'Learn about Sanity', feedItems} = this.state
|
|
70
|
+
|
|
71
|
+
// Filter out items and sections for layout purposes
|
|
72
|
+
const sections = feedItems.filter((i) => i._type === 'feedSection')
|
|
73
|
+
const items = feedItems.filter((i) => i._type === 'feedItem')
|
|
74
|
+
|
|
75
|
+
const columns = (length) => (length < 4 ? [1, 2, 3] : [1, 2, 3, 4])
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Container width={4}>
|
|
79
|
+
<Stack space={6} paddingBottom={4}>
|
|
80
|
+
<Card
|
|
81
|
+
tone="primary"
|
|
82
|
+
padding={4}
|
|
83
|
+
radius={2}
|
|
84
|
+
border
|
|
85
|
+
marginTop={4}
|
|
86
|
+
data-name="sanity-tutorials-widget-docs-link"
|
|
87
|
+
>
|
|
88
|
+
<Flex direction={['column', 'column', 'row']}>
|
|
89
|
+
<Stack space={4} flex={1} paddingRight={[0, 0, 4]}>
|
|
90
|
+
<Heading as="h2">Getting started guide</Heading>
|
|
91
|
+
<Text as="p">
|
|
92
|
+
{`It's time to learn how to build schemas, create content, and connect it to other
|
|
93
|
+
applications.`}
|
|
94
|
+
</Text>
|
|
95
|
+
</Stack>
|
|
96
|
+
<Flex paddingTop={[4, 4, 0]} align="center">
|
|
97
|
+
<Stack flex={1}>
|
|
98
|
+
<Button
|
|
99
|
+
paddingY={3}
|
|
100
|
+
paddingX={5}
|
|
101
|
+
tone="primary"
|
|
102
|
+
as="a"
|
|
103
|
+
target="_blank"
|
|
104
|
+
href="https://www.sanity.io/docs?ref=studio-dashboard"
|
|
105
|
+
text="Go to docs"
|
|
106
|
+
/>
|
|
107
|
+
</Stack>
|
|
108
|
+
</Flex>
|
|
109
|
+
</Flex>
|
|
110
|
+
</Card>
|
|
111
|
+
{sections &&
|
|
112
|
+
sections?.length > 0 &&
|
|
113
|
+
sections.map((section) => {
|
|
114
|
+
return (
|
|
115
|
+
section?.sectionItems && (
|
|
116
|
+
<Stack space={4} key={section._id}>
|
|
117
|
+
<Heading>{section.title}</Heading>
|
|
118
|
+
<Grid
|
|
119
|
+
as="ul"
|
|
120
|
+
columns={columns(section?.sectionItems?.length)}
|
|
121
|
+
gap={4}
|
|
122
|
+
data-name="sanity-dashboard-widget-tutorials-section"
|
|
123
|
+
>
|
|
124
|
+
{section?.sectionItems.map((item) => (
|
|
125
|
+
<Flex as="li" key={item._id}>
|
|
126
|
+
<FeedItem feedItem={item} />
|
|
127
|
+
</Flex>
|
|
128
|
+
))}
|
|
129
|
+
</Grid>
|
|
130
|
+
</Stack>
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
})}
|
|
134
|
+
{items && items.length > 0 && (
|
|
135
|
+
<Stack space={4}>
|
|
136
|
+
<Heading>{title}</Heading>
|
|
137
|
+
<Grid as="ul" columns={columns(items?.length)} gap={4}>
|
|
138
|
+
{items.map((feedItem) => (
|
|
139
|
+
<Flex as="li" key={feedItem._id}>
|
|
140
|
+
<FeedItem feedItem={feedItem} />
|
|
141
|
+
</Flex>
|
|
142
|
+
))}
|
|
143
|
+
</Grid>
|
|
144
|
+
</Stack>
|
|
145
|
+
)}
|
|
146
|
+
</Stack>
|
|
147
|
+
</Container>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export default SanityTutorials
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {Card, Box, Flex, Text, Stack} from '@sanity/ui'
|
|
3
|
+
import styled from 'styled-components'
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line no-useless-escape
|
|
6
|
+
const youtubeRegex = /youtu(?:.*\/v\/|.*v\=|\.be\/)([A-Za-z0-9_-]{11})/
|
|
7
|
+
|
|
8
|
+
const PlayIconBox = styled(Box)`
|
|
9
|
+
position: absolute;
|
|
10
|
+
top: 50%;
|
|
11
|
+
left: 50%;
|
|
12
|
+
transform: translate(-50%, -50%);
|
|
13
|
+
|
|
14
|
+
&:before {
|
|
15
|
+
content: '';
|
|
16
|
+
position: absolute;
|
|
17
|
+
top: 50%;
|
|
18
|
+
left: 50%;
|
|
19
|
+
transform: translate(-50%, -50%);
|
|
20
|
+
width: 2.75em;
|
|
21
|
+
height: 2.75em;
|
|
22
|
+
border-radius: 50%;
|
|
23
|
+
background: ${({theme}) => theme.sanity.color.card.enabled.bg};
|
|
24
|
+
opacity: 0.75;
|
|
25
|
+
}
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
const Root = styled(Flex)`
|
|
29
|
+
&:hover {
|
|
30
|
+
${PlayIconBox} {
|
|
31
|
+
&:before {
|
|
32
|
+
opacity: 1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
const PosterCard = styled(Card)`
|
|
39
|
+
width: 100%;
|
|
40
|
+
padding-bottom: calc(9 / 16 * 100%);
|
|
41
|
+
position: relative;
|
|
42
|
+
border-bottom-left-radius: 0;
|
|
43
|
+
border-bottom-right-radius: 0;
|
|
44
|
+
`
|
|
45
|
+
|
|
46
|
+
const Poster = styled.img`
|
|
47
|
+
position: absolute;
|
|
48
|
+
top: 0;
|
|
49
|
+
left: 0;
|
|
50
|
+
height: 100%;
|
|
51
|
+
width: 100%;
|
|
52
|
+
object-fit: cover;
|
|
53
|
+
display: block;
|
|
54
|
+
border-radius: inherit;
|
|
55
|
+
|
|
56
|
+
&:not([src]) {
|
|
57
|
+
display: none;
|
|
58
|
+
}
|
|
59
|
+
`
|
|
60
|
+
const YoutubeContainer = styled(Card)`
|
|
61
|
+
position: relative;
|
|
62
|
+
padding-bottom: 56.25%;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
border-bottom-left-radius: 0;
|
|
65
|
+
border-bottom-right-radius: 0;
|
|
66
|
+
|
|
67
|
+
iframe {
|
|
68
|
+
position: absolute;
|
|
69
|
+
top: 0;
|
|
70
|
+
left: 0;
|
|
71
|
+
width: 100%;
|
|
72
|
+
height: 100%;
|
|
73
|
+
}
|
|
74
|
+
`
|
|
75
|
+
const YoutubeEmbed = ({embedId}) => (
|
|
76
|
+
<YoutubeContainer radius={3}>
|
|
77
|
+
<iframe
|
|
78
|
+
width="853"
|
|
79
|
+
height="480"
|
|
80
|
+
src={`https://www.youtube.com/embed/${embedId}`}
|
|
81
|
+
frameBorder="0"
|
|
82
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
83
|
+
allowFullScreen
|
|
84
|
+
/>
|
|
85
|
+
</YoutubeContainer>
|
|
86
|
+
)
|
|
87
|
+
class Tutorial extends React.PureComponent {
|
|
88
|
+
static defaultProps = {
|
|
89
|
+
posterURL: null,
|
|
90
|
+
showPlayIcon: false,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
render() {
|
|
94
|
+
const {title, posterURL, showPlayIcon, href, presenterSubtitle} = this.props
|
|
95
|
+
|
|
96
|
+
const isYoutube = showPlayIcon && href && href.match(youtubeRegex)
|
|
97
|
+
|
|
98
|
+
return isYoutube ? (
|
|
99
|
+
<Card
|
|
100
|
+
space={2}
|
|
101
|
+
sizing="border"
|
|
102
|
+
flex={1}
|
|
103
|
+
radius={3}
|
|
104
|
+
style={{position: 'relative'}}
|
|
105
|
+
border
|
|
106
|
+
paddingBottom={2}
|
|
107
|
+
>
|
|
108
|
+
<Stack space={2} height="fill">
|
|
109
|
+
<YoutubeEmbed embedId={href.match(youtubeRegex)[1]} />
|
|
110
|
+
<Stack space={3} flex={1} padding={2}>
|
|
111
|
+
<Text as="h3" size={1} weight="bold">
|
|
112
|
+
{title}
|
|
113
|
+
</Text>
|
|
114
|
+
{presenterSubtitle && (
|
|
115
|
+
<Text size={1} muted>
|
|
116
|
+
{presenterSubtitle}
|
|
117
|
+
</Text>
|
|
118
|
+
)}
|
|
119
|
+
</Stack>
|
|
120
|
+
</Stack>
|
|
121
|
+
</Card>
|
|
122
|
+
) : (
|
|
123
|
+
<Root flex={1}>
|
|
124
|
+
<Card
|
|
125
|
+
sizing="border"
|
|
126
|
+
flex={1}
|
|
127
|
+
radius={3}
|
|
128
|
+
as="a"
|
|
129
|
+
href={href}
|
|
130
|
+
target="_blank"
|
|
131
|
+
style={{position: 'relative'}}
|
|
132
|
+
border
|
|
133
|
+
paddingBottom={2}
|
|
134
|
+
>
|
|
135
|
+
<Stack space={2} height="fill">
|
|
136
|
+
{posterURL && (
|
|
137
|
+
<PosterCard radius={3}>
|
|
138
|
+
<Poster src={posterURL} />
|
|
139
|
+
</PosterCard>
|
|
140
|
+
)}
|
|
141
|
+
<Stack space={3} flex={1} padding={2}>
|
|
142
|
+
<Text as="h3" size={1} weight="bold">
|
|
143
|
+
{title}
|
|
144
|
+
</Text>
|
|
145
|
+
{presenterSubtitle && (
|
|
146
|
+
<Text size={1} muted>
|
|
147
|
+
{presenterSubtitle}
|
|
148
|
+
</Text>
|
|
149
|
+
)}
|
|
150
|
+
</Stack>
|
|
151
|
+
</Stack>
|
|
152
|
+
</Card>
|
|
153
|
+
</Root>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export default Tutorial
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import imageUrlBuilder from '@sanity/image-url'
|
|
2
|
+
import {versionedClient} from '../../versionedClient'
|
|
3
|
+
|
|
4
|
+
const tutorialsProjectConfig = {
|
|
5
|
+
projectId: '3do82whm',
|
|
6
|
+
dataset: 'next',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
getFeed: (templateRepoId) => {
|
|
11
|
+
const uri = templateRepoId
|
|
12
|
+
? `/addons/dashboard?templateRepoId=${templateRepoId}`
|
|
13
|
+
: '/addons/dashboard'
|
|
14
|
+
return versionedClient.observable.request({uri, withCredentials: false})
|
|
15
|
+
},
|
|
16
|
+
urlBuilder: imageUrlBuilder(tutorialsProjectConfig),
|
|
17
|
+
}
|
package/.babelrc
DELETED
package/tsconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../../tsconfig",
|
|
3
|
-
"include": ["src"],
|
|
4
|
-
"compilerOptions": {
|
|
5
|
-
"composite": true,
|
|
6
|
-
"outDir": "./dist/dts",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"jsx": "react",
|
|
9
|
-
"noImplicitAny": false
|
|
10
|
-
},
|
|
11
|
-
"references": [
|
|
12
|
-
{
|
|
13
|
-
"path": "../base"
|
|
14
|
-
},
|
|
15
|
-
]
|
|
16
|
-
}
|
|
17
|
-
|