Skip to content

Commit 1e9036b

Browse files
authored
Merge pull request #117 from mysilio-co/staging
Ship editor improvements, left nav bar, login/register improvements and more
2 parents 0097347 + 5cefe6c commit 1e9036b

54 files changed

Lines changed: 12777 additions & 50465 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
14
1+
16

components/Avatar.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
export default function Avatar({ src, className, border=true, ...rest }) {
2+
const borderClasses = border ? (border === true ? 'border-2 border-white' : border) : ""
23
if (src) {
34
return (
45
<img
56
src={src}
6-
className={`rounded-full ${border ? 'border-2 border-white' : ''} ${className}`}
7+
className={`rounded-full ${borderClasses} ${className}`}
78
{...rest}
89
/>
910
);
1011
} else {
1112
return (
1213
<span
13-
className={`inline-block rounded-full overflow-hidden bg-gray-100 cursor-pointer ${className}`}
14+
className={`inline-block rounded-full overflow-hidden bg-gray-100 cursor-pointer ${borderClasses} ${className}`}
1415
{...rest}
1516
>
1617
<svg

components/ConceptBody.jsx

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import { useState, useMemo, Fragment } from 'react';
22
import { Transition } from '@headlessui/react'
3+
import { FOAF } from "@inrupt/vocab-common-rdf";
4+
import { getUrl, setUrl, isThingLocal } from "@inrupt/solid-client";
35

46
import NoteEditor from "./NoteEditor";
57
import ConnectionsPanel from "./ConnectionsPanel";
68
import { InlineLoader } from './elements'
79
import { Share as ShareIcon, ArrowSquareLeft as ArrowSquareLeftIcon } from './icons'
810
import { EmptySlateJSON } from "../utils/slate";
11+
import { useImageUploadUri } from "../hooks/uris";
12+
import { Tooltip } from './elements'
13+
import ImageUploadModal from './modals/ImageUpload'
14+
15+
import { UploadImage } from './icons'
916

1017
function CreateNote({ conceptName, onNoteBodyChange }) {
1118
return (
@@ -21,36 +28,64 @@ function CreateNote({ conceptName, onNoteBodyChange }) {
2128
}
2229

2330
export default function ConceptBody({
24-
concept, note, noteError, conceptPrefix, conceptIndex, myNote,
31+
concept, saveConcept, note, noteError, conceptPrefix, conceptIndex, myNote,
2532
conceptName, tagPrefix, onNoteBodyChange, conceptNames, editorId, panelStartsOpen = false,
2633
workspaceSlug, webId, authorWebId
2734
}) {
2835
const [panelOpen, setPanelOpen] = useState(panelStartsOpen)
36+
const coverImage = concept && getUrl(concept, FOAF.img)
37+
38+
const imageUploadUri = useImageUploadUri(webId)
39+
const [coverImageUploaderOpen, setCoverImageUploaderOpen] = useState(false)
40+
async function setCoverImage(url) {
41+
await saveConcept(setUrl(concept, FOAF.img, url))
42+
setCoverImageUploaderOpen(false)
43+
}
44+
const isSavedConcept = concept && !isThingLocal(concept)
2945
return (
3046

3147
<div className="relative">
32-
<Transition
33-
show={!panelOpen} as={Fragment}
34-
as={Fragment}
35-
enter="transform transition ease-in-out duration-500 sm:duration-700"
36-
enterFrom="translate-x-full"
37-
enterTo="translate-x-0"
38-
leave="transform transition ease-in-out duration-500 sm:duration-700"
39-
leaveFrom="translate-x-0"
40-
leaveTo="translate-x-full"
41-
>
42-
<button onClick={() => setPanelOpen(true)}
43-
className="absolute top-0 right-0 w-18 h-18 bg-gray-100 rounded-bl-lg flex flex-row py-6 pl-2 pr-4"
48+
{isSavedConcept && (
49+
<Transition
50+
show={!panelOpen} as={Fragment}
51+
enter="transform transition ease-in-out duration-500 sm:duration-700"
52+
enterFrom="translate-x-full"
53+
enterTo="translate-x-0"
54+
leave="transform transition ease-in-out duration-500 sm:duration-700"
55+
leaveFrom="translate-x-0"
56+
leaveTo="translate-x-full"
4457
>
45-
<ArrowSquareLeftIcon className="w-6 h-6" />
46-
<ShareIcon className="w-6 h-6" />
47-
</button>
48-
</Transition>
58+
<button onClick={() => setPanelOpen(true)}
59+
className="absolute top-0 right-0 w-18 h-18 text-gray-500 hover:text-gray-400 bg-gray-100 rounded-bl-lg flex flex-row py-6 pl-2 pr-4 z-40"
60+
>
61+
<ArrowSquareLeftIcon className="w-6 h-6 pointer-events-none" />
62+
<ShareIcon className="w-6 h-6 pointer-events-none" />
63+
</button>
64+
</Transition>
65+
)}
4966

5067
<div className="flex flex-row w-full">
51-
<div className={`flex-grow py-6 bg-white p-18 ${panelOpen ? 'pr-9' : 'pr-18'}`}>
68+
<div className={`flex-grow py-6 bg-white pl-6 sm:pl-12 md:pl-18 ${panelOpen ? 'pr-12 hidden md:block' : 'pr-6 sm:pr-12 md:pr-18'}`}>
5269
{note ? (
53-
<NoteEditor myNote={myNote} editorId={editorId} note={note} onNoteBodyChange={onNoteBodyChange} conceptNames={conceptNames} />
70+
<div className="flex-col">
71+
<div className={`relative flex flex-row justify-center group overflow-hidden ${coverImage ? 'h-40' : ''}`}>
72+
{coverImage && (
73+
<img className="absolute top-0 left-0 w-full overflow-hidden" src={coverImage} alt={conceptName} />
74+
)}
75+
{myNote && (
76+
<>
77+
<Tooltip content={<span>Upload Cover Image</span>}>
78+
<button className="hover:shadow-menu" onClick={() => setCoverImageUploaderOpen(true)}>
79+
<UploadImage className="w-6 h-6 text-gray-700 mt-4 opacity-10 group-hover:opacity-90" />
80+
</button>
81+
</Tooltip>
82+
<ImageUploadModal open={coverImageUploaderOpen} setOpen={setCoverImageUploaderOpen}
83+
onSave={(url) => setCoverImage(url)} uploadContainerUri={imageUploadUri} />
84+
</>
85+
)}
86+
</div>
87+
<NoteEditor myNote={myNote} editorId={editorId} note={note} onNoteBodyChange={onNoteBodyChange} conceptNames={conceptNames} />
88+
</div>
5489
) : (noteError ? (
5590
(webId === authorWebId) ? (
5691
<CreateNote conceptName={conceptName} onNoteBodyChange={onNoteBodyChange} />
@@ -65,20 +100,22 @@ export default function ConceptBody({
65100
))}
66101

67102
</div>
68-
<Transition
69-
show={panelOpen} as={Fragment}
70-
enter="transform transition ease-in-out duration-500 sm:duration-700"
71-
enterFrom="translate-x-full"
72-
enterTo="translate-x-0"
73-
leave="transform transition ease-in-out duration-500 sm:duration-700"
74-
leaveFrom="translate-x-0"
75-
leaveTo="translate-x-full"
76-
>
77-
<ConnectionsPanel
78-
concept={concept} conceptName={conceptName} conceptPrefix={conceptPrefix} tagPrefix={tagPrefix}
79-
webId={authorWebId} workspaceSlug={workspaceSlug} conceptIndex={conceptIndex}
80-
onClose={() => setPanelOpen(false)} />
81-
</Transition>
103+
{isSavedConcept && (
104+
<Transition
105+
show={panelOpen} as={Fragment}
106+
enter="transform transition ease-in-out duration-500 sm:duration-700"
107+
enterFrom="translate-x-full"
108+
enterTo="translate-x-0"
109+
leave="transform transition ease-in-out duration-500 sm:duration-700"
110+
leaveFrom="translate-x-0"
111+
leaveTo="translate-x-full"
112+
>
113+
<ConnectionsPanel className="w-full md:w-auto"
114+
concept={concept} conceptName={conceptName} conceptPrefix={conceptPrefix} tagPrefix={tagPrefix}
115+
webId={authorWebId} workspaceSlug={workspaceSlug} conceptIndex={conceptIndex}
116+
onClose={() => setPanelOpen(false)} />
117+
</Transition>
118+
)}
82119
</div>
83120
</div>
84121
)

components/ConceptEditor.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function useAutosave(note, save) {
3939
return { onChange: setUpdatedValue }
4040
}
4141

42-
export default function ConceptEditor({ webId, authorWebId, workspaceSlug, concept, conceptName, conceptIndex, note, noteError, maybeSaveNoteBody, editorId, myNote }) {
42+
export default function ConceptEditor({ webId, authorWebId, workspaceSlug, concept, saveConcept, conceptName, conceptIndex, note, noteError, maybeSaveNoteBody, editorId, myNote }) {
4343
const { workspace } = useWorkspace(authorWebId, workspaceSlug)
4444
const conceptPrefix = workspace && getUrl(workspace, US.conceptPrefix);
4545
const tagPrefix = workspace && getUrl(workspace, US.tagPrefix);
@@ -48,7 +48,8 @@ export default function ConceptEditor({ webId, authorWebId, workspaceSlug, conce
4848
const conceptNames = useConceptNames(authorWebId)
4949
return (
5050
<ConceptBody editorId={editorId} myNote={myNote}
51-
concept={concept} conceptName={conceptName} authorWebId={authorWebId}
51+
concept={concept} conceptName={conceptName}
52+
saveConcept={saveConcept} authorWebId={authorWebId}
5253
note={note} noteError={noteError}
5354
saveNoteBody={maybeSaveNoteBody}
5455
tagPrefix={tagPrefix} conceptPrefix={conceptPrefix}

components/ConceptPage.jsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import { useMemo } from 'react'
2+
import Head from 'next/head'
3+
14
import { useProfile, useMyProfile, useWebId } from "swrlit";
25

36
import { urlSafeIdToConceptName } from "../utils/uris";
47
import { useConceptAndNote } from '../hooks/app';
58
import { useCombinedWorkspaceIndexDataset } from '../hooks/concepts'
69

10+
import LeftNavLayout from './LeftNavLayout'
711
import NoteHeader from './NoteHeader';
812
import ConceptEditor from './ConceptEditor';
913
import WebMonetization from './WebMonetization';
@@ -16,14 +20,22 @@ export default function ConceptPage({ editorId = 'concept-page', webId, workspac
1620
const { profile: currentUserProfile } = useMyProfile();
1721
const { index } = useCombinedWorkspaceIndexDataset(webId, workspaceSlug);
1822
const myNote = (webId === myWebId)
23+
const headerProps = useMemo(() => ({
24+
concept, saveConcept, conceptName, authorProfile,
25+
currentUserProfile, myNote, privacy, deleteConcept
26+
}), [
27+
concept, saveConcept, conceptName, authorProfile,
28+
currentUserProfile, myNote, privacy, deleteConcept
29+
])
1930
return (
20-
<div>
31+
<LeftNavLayout pageName={conceptName} HeaderComponent={NoteHeader} headerProps={headerProps} >
32+
<Head>
33+
<title>{conceptName}</title>
34+
</Head>
2135
<WebMonetization webId={webId} />
22-
<NoteHeader concept={concept} saveConcept={saveConcept} conceptName={conceptName} authorProfile={authorProfile}
23-
currentUserProfile={currentUserProfile} myNote={myNote} privacy={privacy} deleteConcept={deleteConcept} />
2436
<ConceptEditor webId={webId} authorWebId={webId} workspaceSlug={workspaceSlug} slug={slug} myNote={myNote}
25-
conceptIndex={index} concept={concept} conceptName={conceptName} editorId={conceptName}
37+
conceptIndex={index} concept={concept} conceptName={conceptName} saveConcept={saveConcept} editorId={conceptName}
2638
note={note} noteError={noteError} maybeSaveNoteBody={maybeSaveNoteBody} />
27-
</div>
39+
</LeftNavLayout>
2840
)
2941
}

components/ConnectionsPanel.jsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { useState, forwardRef, Suspense } from 'react'
22
import { asUrl } from '@inrupt/solid-client'
33
import Link from 'next/link'
4+
import {
5+
HomeIcon,
6+
MenuIcon,
7+
UserGroupIcon,
8+
XIcon,
9+
} from '@heroicons/react/outline'
410

511
import {
612
getTags, getLinks, tagUrlToTagName,
@@ -12,6 +18,7 @@ import { notePath, urlSafeIdToConceptName } from "../utils/uris";
1218
import { Close as CloseIcon } from "./icons"
1319
import ConnectionsTabs from './ConnectionsTabs'
1420

21+
1522
function TagsSection({ concept, tagPrefix, workspaceSlug }) {
1623
const tags = getTags(concept)
1724
return (
@@ -21,7 +28,7 @@ function TagsSection({ concept, tagPrefix, workspaceSlug }) {
2128
return (
2229
<div>
2330
<Link href={`/tags/${workspaceSlug}/${tagName}`}>
24-
<a className="text-lagoon">
31+
<a className="text-my-green">
2532
#{tagName}
2633
</a>
2734
</Link>
@@ -100,9 +107,16 @@ const ConnectionsPanel = forwardRef(({ onClose, concept, conceptName, tagPrefix,
100107
const [activeTab, setActiveTab] = useState('links')
101108
return (
102109
<div className={`flex flex-col ${className}`} ref={ref}>
103-
<div className="flex flex-row justify-between p-6 bg-gray-100">
110+
<div className="flex flex-row gap-4 justify-between items-center p-4 bg-gray-100">
104111
<h3 className="font-bold text-gray-500 leading-7 text-2xl">Connections</h3>
105-
<CloseIcon className="w-6 h-6 text-gray-700 cursor-pointer" onClick={onClose} />
112+
<button
113+
type="button"
114+
className="ml-1 flex items-center justify-center h-6 w-6 rounded-full focus:outline-none ring-1 ring-inset ring-gray-500 hover:ring-gray-400 text-gray-500 hover:text-gray-400"
115+
onClick={onClose}
116+
>
117+
<span className="sr-only">Close connections panel</span>
118+
<XIcon className="h-4 w-4" aria-hidden="true" />
119+
</button>
106120
</div>
107121
<ConnectionsTabs active={activeTab} onChange={setActiveTab} />
108122
<ConnectionsSection subSection={activeTab} concept={concept} conceptName={conceptName} tagPrefix={tagPrefix} conceptPrefix={conceptPrefix}

components/Dashboard.jsx

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,30 @@
1-
import { useState } from 'react'
1+
import { useState, useMemo } from 'react'
22
import { useWebId } from 'swrlit'
33

44
import WebMonetization from '../components/WebMonetization'
5-
import HeaderWithData from '../components/HeaderWithData'
5+
import GardenHeader from './GardenHeader'
6+
import LeftNavLayout from '../components/LeftNavLayout'
67
import { WorkspaceProvider } from '../contexts/WorkspaceContext'
78
import { useFilteredGarden } from '../hooks/concepts';
89
import Cards from '../components/Cards';
9-
import ProfileDrawerWithData from './ProfileDrawerWithData'
1010

1111
export default function Dashboard() {
1212
const webId = useWebId();
1313
const workspaceSlug = 'default';
1414
const [search, setSearch] = useState('');
1515
const { garden } = useFilteredGarden(webId, workspaceSlug, search);
16-
const [profileDrawerOpen, setProfileDrawerOpen] = useState(false)
16+
const headerProps = useMemo(() => ({
17+
onSearch: setSearch,
18+
type: 'dashboard'
19+
}), [setSearch])
1720
return (
18-
<>
21+
<LeftNavLayout pageName="Dashboard" HeaderComponent={GardenHeader} headerProps={headerProps} >
1922
<WebMonetization webId={webId} />
20-
<HeaderWithData
21-
type="dashboard"
22-
onSearch={(s) => {
23-
setSearch(s);
24-
}}
25-
setDrawerOpen={setProfileDrawerOpen}
26-
drawerOpen={profileDrawerOpen}
27-
/>
28-
<div className="py-6 px-18">
23+
<div className="p-6">
2924
<WorkspaceProvider webId={webId} slug={workspaceSlug}>
3025
<Cards webId={webId} garden={garden} workspaceSlug={workspaceSlug} />
31-
<ProfileDrawerWithData isOpen={profileDrawerOpen} setIsOpen={setProfileDrawerOpen} webId={webId}/>
3226
</WorkspaceProvider>
3327
</div>
34-
</>
28+
</LeftNavLayout>
3529
);
3630
}

0 commit comments

Comments
 (0)