Merge branch 'main' into adding-logo
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
"@redwoodjs/forms": "^0.19.2",
|
||||
"@redwoodjs/router": "^0.19.2",
|
||||
"@redwoodjs/web": "^0.19.2",
|
||||
"cloudinary-react": "^1.6.7",
|
||||
"controlkit": "^0.1.9",
|
||||
"golden-layout": "^1.5.9",
|
||||
"jquery": "^3.5.1",
|
||||
@@ -28,6 +29,8 @@
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-dropzone": "^11.2.1",
|
||||
"react-image-crop": "^8.6.6",
|
||||
"rich-markdown-editor": "^11.0.2",
|
||||
"styled-components": "^5.2.0",
|
||||
"three": "^0.118.3"
|
||||
|
||||
Submodule web/src/cascade updated: 62f961293d...e634591e27
76
web/src/components/EmojiReaction/EmojiReaction.js
Normal file
76
web/src/components/EmojiReaction/EmojiReaction.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import { useState } from 'react'
|
||||
import Fab from '@material-ui/core/Fab'
|
||||
import IconButton from '@material-ui/core/IconButton'
|
||||
import Popover from '@material-ui/core/Popover'
|
||||
import Svg from 'src/components/Svg'
|
||||
|
||||
const emojiMenu = ['🏆', '❤️', '👍', '😊', '😄', '🚀', '👏', '🙌']
|
||||
|
||||
const EmojiReaction = ({ emotes, callback = () => {} }) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [anchorEl, setAnchorEl] = useState(null)
|
||||
const [popoverId, setPopoverId] = useState(undefined)
|
||||
|
||||
const openPopover = (target) => {
|
||||
setAnchorEl(target)
|
||||
setPopoverId('simple-popover')
|
||||
setIsOpen(true)
|
||||
}
|
||||
|
||||
const closePopover = () => {
|
||||
setAnchorEl(null)
|
||||
setPopoverId(undefined)
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
const togglePopover = ({ currentTarget }) => {
|
||||
if (isOpen) {
|
||||
return closePopover()
|
||||
}
|
||||
|
||||
openPopover(currentTarget)
|
||||
}
|
||||
|
||||
const handleEmojiClick = (emoji) => {
|
||||
callback(emoji)
|
||||
closePopover()
|
||||
}
|
||||
|
||||
return [
|
||||
<div className="flex justify-between">
|
||||
<Fab size="medium" variant="round" aria-describedby={popoverId} onClick={togglePopover}>
|
||||
<div className="bg-gray-200 border-2 m-px border-gray-300 text-gray-500 absolute inset-0 rounded-full flex justify-center items-center">
|
||||
<Svg name="dots-vertical" />
|
||||
</div>
|
||||
</Fab>
|
||||
|
||||
<div>
|
||||
{emotes.map((emote, i) => (
|
||||
<IconButton key={`${emote.emoji}--${i}`} onClick={() => handleEmojiClick(emote.emoji)}>
|
||||
{emote.emoji} <span>{emote.count}</span>
|
||||
</IconButton>
|
||||
))}
|
||||
</div>
|
||||
</div>,
|
||||
<Popover
|
||||
id={popoverId}
|
||||
open={isOpen}
|
||||
anchorEl={anchorEl}
|
||||
onClose={closePopover}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'center',
|
||||
}}
|
||||
>
|
||||
{emojiMenu.map((emoji, i) => (
|
||||
<IconButton key={`${emoji}-${i}}`} onClick={() => handleEmojiClick(emoji)}>{emoji}</IconButton>
|
||||
))}
|
||||
</Popover>,
|
||||
]
|
||||
}
|
||||
|
||||
export default EmojiReaction
|
||||
@@ -0,0 +1,7 @@
|
||||
import EmojiReaction from './EmojiReaction'
|
||||
|
||||
export const generated = () => {
|
||||
return <EmojiReaction />
|
||||
}
|
||||
|
||||
export default { title: 'Components/EmojiReaction' }
|
||||
11
web/src/components/EmojiReaction/EmojiReaction.test.js
Normal file
11
web/src/components/EmojiReaction/EmojiReaction.test.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { render } from '@redwoodjs/testing'
|
||||
|
||||
import EmojiReaction from './EmojiReaction'
|
||||
|
||||
describe('EmojiReaction', () => {
|
||||
it('renders successfully', () => {
|
||||
expect(() => {
|
||||
render(<EmojiReaction />)
|
||||
}).not.toThrow()
|
||||
})
|
||||
})
|
||||
120
web/src/components/PartForm/ImageUploader.js
Normal file
120
web/src/components/PartForm/ImageUploader.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import axios from 'axios'
|
||||
import ReactCrop from 'react-image-crop'
|
||||
import { Dialog } from '@material-ui/core'
|
||||
import { Image as CloudinaryImage } from 'cloudinary-react'
|
||||
import 'react-image-crop/dist/ReactCrop.css'
|
||||
import Svg from 'src/components/Svg/Svg.js'
|
||||
|
||||
const CLOUDINARY_UPLOAD_PRESET = "CadHub_project_images";
|
||||
const CLOUDINARY_UPLOAD_URL = "https://api.cloudinary.com/v1_1/irevdev/upload";
|
||||
|
||||
export default function ImageUploader({ onImageUpload, imageUrl }) {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [file, setFile] = useState()
|
||||
const [cloudinaryId, setCloudinaryId] = useState(imageUrl)
|
||||
const [imageObj, setImageObj] = useState()
|
||||
const [crop, setCrop] = useState({
|
||||
aspect: 16 / 9,
|
||||
unit: '%',
|
||||
width: 100,
|
||||
});
|
||||
async function handleImageUpload() {
|
||||
const croppedFile = await getCroppedImg(imageObj, crop, 'avatar')
|
||||
console.log(croppedFile)
|
||||
const imageData = new FormData();
|
||||
imageData.append('upload_preset', CLOUDINARY_UPLOAD_PRESET);
|
||||
imageData.append('file', croppedFile);
|
||||
let upload = axios.post(CLOUDINARY_UPLOAD_URL, imageData)
|
||||
try {
|
||||
const { data } = await upload
|
||||
if (data && data.public_id !== "") {
|
||||
onImageUpload({cloudinaryPublicId: data.public_id})
|
||||
setCloudinaryId(data.public_id)
|
||||
setIsModalOpen(false)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('ERROR', e)
|
||||
}
|
||||
}
|
||||
// Drag and Drop
|
||||
const onDrop = useCallback(acceptedFiles => {
|
||||
setIsModalOpen(true)
|
||||
const fileReader = new FileReader()
|
||||
fileReader.onload = () => {
|
||||
setFile(fileReader.result)
|
||||
}
|
||||
fileReader.readAsDataURL(acceptedFiles[0])
|
||||
}, []);
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
|
||||
return (
|
||||
<div className="m-8">
|
||||
<div className="w-full relative" {...getRootProps()}>
|
||||
{cloudinaryId && <button className="absolute z-10 w-full inset-0 bg-indigo-900 opacity-50 flex justify-center items-center">
|
||||
<Svg name="pencil" strokeWidth={2} className="text-gray-300 h-48 w-48" />
|
||||
</button>}
|
||||
<input {...getInputProps()} />
|
||||
{cloudinaryId && <div className="relative">
|
||||
<CloudinaryImage
|
||||
className="object-cover w-full rounded shadow"
|
||||
cloudName="irevdev"
|
||||
publicId={cloudinaryId}
|
||||
width="600"
|
||||
crop="scale"
|
||||
/>
|
||||
</div>}
|
||||
{!cloudinaryId && <button className="absolute inset-0"></button>}
|
||||
{!cloudinaryId && <div className="mt-3 text-indigo-500 border-dashed border border-indigo-500 py-8 text-center rounded-lg w-full">
|
||||
Drop files here ...
|
||||
or <span className="group flex w-full items-center justify-center py-4">
|
||||
<span className="bg-indigo-500 shadow rounded text-gray-200 cursor-pointer p-2 hover:shadow-lg transform hover:-translate-y-1 transition-all duration-150">upload</span>
|
||||
</span>
|
||||
</div>}
|
||||
</div>
|
||||
<Dialog
|
||||
open={isModalOpen}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
>
|
||||
<div className="p-4">
|
||||
<ReactCrop src={file} crop={crop} onImageLoaded={(image) => setImageObj(image)} onChange={newCrop => setCrop(newCrop)} />
|
||||
<Button onClick={handleImageUpload} variant="outlined">Upload</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getCroppedImg(image, crop, fileName) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const scaleX = image.naturalWidth / image.width;
|
||||
const scaleY = image.naturalHeight / image.height;
|
||||
canvas.width = crop.width;
|
||||
canvas.height = crop.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(
|
||||
image,
|
||||
crop.x * scaleX,
|
||||
crop.y * scaleY,
|
||||
crop.width * scaleX,
|
||||
crop.height * scaleY,
|
||||
0,
|
||||
0,
|
||||
crop.width,
|
||||
crop.height
|
||||
);
|
||||
|
||||
// As Base64 string
|
||||
// const base64Image = canvas.toDataURL('image/jpeg');
|
||||
|
||||
// As a blob
|
||||
return new Promise((resolve, reject) => {
|
||||
canvas.toBlob(blob => {
|
||||
blob.name = fileName;
|
||||
resolve(blob);
|
||||
}, 'image/jpeg', 1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,23 +4,26 @@ import {
|
||||
FieldError,
|
||||
Label,
|
||||
TextField,
|
||||
TextAreaField,
|
||||
Submit,
|
||||
} from '@redwoodjs/forms'
|
||||
import { useState } from 'react';
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import { useFlash } from '@redwoodjs/web'
|
||||
import ImageUploader from './ImageUploader.js'
|
||||
|
||||
|
||||
import Editor from "rich-markdown-editor";
|
||||
|
||||
const PartForm = (props) => {
|
||||
const { addMessage } = useFlash()
|
||||
const [description, setDescription] = useState(props?.part?.description)
|
||||
const [imageUrl, setImageUrl] = useState(props?.part?.mainImage)
|
||||
const onSubmit = async (data, e) => {
|
||||
|
||||
await props.onSave({
|
||||
...data,
|
||||
description,
|
||||
mainImage: imageUrl
|
||||
}, props?.part?.id)
|
||||
const shouldOpenIde = e?.nativeEvent?.submitter?.dataset?.openIde
|
||||
if(shouldOpenIde) {
|
||||
@@ -57,21 +60,8 @@ const PartForm = (props) => {
|
||||
/>
|
||||
<FieldError name="title" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="mainImage"
|
||||
className="p-0"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Main image
|
||||
</Label>
|
||||
<TextField
|
||||
name="mainImage"
|
||||
defaultValue={props.part?.mainImage}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: false }}
|
||||
/>
|
||||
<FieldError name="mainImage" className="rw-field-error" />
|
||||
<ImageUploader onImageUpload={({cloudinaryPublicId}) => setImageUrl(cloudinaryPublicId)} />
|
||||
|
||||
|
||||
<Label
|
||||
name="description"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
import { Image as CloudinaryImage } from 'cloudinary-react'
|
||||
|
||||
import avatar from 'src/assets/harold.jpg'
|
||||
|
||||
@@ -52,7 +53,7 @@ const PartsList = ({ parts }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto grid gap-8 grid-cols-4">
|
||||
<div className="max-w-xs sm:max-w-sm md:max-w-2xl lg:max-w-5xl xl:max-w-6xl mx-auto grid gap-8 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid- cols-4">
|
||||
{parts.map((part) => {
|
||||
return (
|
||||
<Link
|
||||
@@ -64,11 +65,19 @@ const PartsList = ({ parts }) => {
|
||||
<div className="rounded-t-2xl bg-gray-900">
|
||||
<div className="flex items-center p-2 text-indigo-200">
|
||||
<div className="h-full absolute inset-0 text-6xl flex items-center justify-center text-indigo-700" ><span>?</span></div>
|
||||
<div className="mr-4"><img src={avatar} className="rounded-full h-10 w-10" /></div>
|
||||
<div className="mr-4">
|
||||
<img src={avatar} className="rounded-full h-10 w-10" />
|
||||
</div>
|
||||
<h3>{part.title}</h3>
|
||||
</div>
|
||||
<div className="relative z-10">
|
||||
<img className="h-full" src={part.mainImage}/>
|
||||
<CloudinaryImage
|
||||
className="object-cover w-full rounded shadow"
|
||||
cloudName="irevdev"
|
||||
publicId={part.mainImage}
|
||||
width="300"
|
||||
crop="scale"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
const Svg = ({name, className: className2}) => {
|
||||
const Svg = ({name, className: className2, strokeWidth = 2}) => {
|
||||
|
||||
const svgs = {
|
||||
"plus-circle": <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1} d="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={strokeWidth} d="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>,
|
||||
"plus":<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={strokeWidth} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
||||
</svg>,
|
||||
"pencil": <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={strokeWidth} d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
||||
</svg>,
|
||||
"dots-vertical": <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={strokeWidth} d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" />
|
||||
</svg>
|
||||
}
|
||||
|
||||
return <div className={"h-10 w-10 " + className2}>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { Link, routes, navigate } from '@redwoodjs/router'
|
||||
|
||||
import { Image as CloudinaryImage } from 'cloudinary-react'
|
||||
const DELETE_USER_MUTATION = gql`
|
||||
mutation DeleteUserMutation($id: Int!) {
|
||||
deleteUser(id: $id) {
|
||||
@@ -72,7 +72,13 @@ const User = ({ user }) => {
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<td>{user.image}</td>
|
||||
<td><CloudinaryImage
|
||||
className="object-cover w-full rounded shadow"
|
||||
cloudName="irevdev"
|
||||
publicId={user.image}
|
||||
width="300"
|
||||
crop="scale"
|
||||
/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bio</th>
|
||||
|
||||
@@ -6,10 +6,21 @@ import {
|
||||
TextField,
|
||||
Submit,
|
||||
} from '@redwoodjs/forms'
|
||||
|
||||
import { useState } from 'react';
|
||||
import { navigate, routes } from '@redwoodjs/router'
|
||||
import { useFlash } from '@redwoodjs/web'
|
||||
import ImageUploader from '../PartForm/ImageUploader'
|
||||
const UserForm = (props) => {
|
||||
const onSubmit = (data) => {
|
||||
props.onSave(data, props?.user?.id)
|
||||
const { addMessage } = useFlash()
|
||||
// const [bio, setBio] = useState(props?.user?.bio)
|
||||
const [imageUrl, setImageUrl] = useState(props?.user?.image)
|
||||
const onSubmit = async (data, e) => {
|
||||
|
||||
await props.onSave({
|
||||
...data,
|
||||
image: imageUrl
|
||||
}, props?.user?.id)
|
||||
addMessage('User updated.', { classes: 'rw-flash-success' })
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -37,21 +48,7 @@ const UserForm = (props) => {
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="email" className="rw-field-error" />
|
||||
|
||||
<Label
|
||||
name="image"
|
||||
className="rw-label"
|
||||
errorClassName="rw-label rw-label-error"
|
||||
>
|
||||
Image
|
||||
</Label>
|
||||
<TextField
|
||||
name="image"
|
||||
defaultValue={props.user?.image}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
/>
|
||||
<FieldError name="image" className="rw-field-error" />
|
||||
<ImageUploader onImageUpload={({cloudinaryPublicId}) => setImageUrl(cloudinaryPublicId)} />
|
||||
|
||||
<Label
|
||||
name="bio"
|
||||
@@ -65,6 +62,7 @@ const UserForm = (props) => {
|
||||
defaultValue={props.user?.bio}
|
||||
className="rw-input"
|
||||
errorClassName="rw-input rw-input-error"
|
||||
validation={{ required: true }}
|
||||
/>
|
||||
<FieldError name="bio" className="rw-field-error" />
|
||||
|
||||
|
||||
16
web/src/components/UserPart/UserPart.js
Normal file
16
web/src/components/UserPart/UserPart.js
Normal file
@@ -0,0 +1,16 @@
|
||||
function UserPart({ userName, partName }) {
|
||||
return (
|
||||
<h3 className="text-xl font-roboto">
|
||||
<div className="w-1 inline-block text-indigo-800 bg-indigo-800 mr-2">.</div>
|
||||
<span className="text-gray-500">
|
||||
{userName}
|
||||
</span>
|
||||
<div className="w-1 inline-block bg-gray-400 text-gray-400 mx-3 transform -skew-x-20" >.</div>
|
||||
<span className="text-indigo-800">
|
||||
{partName}
|
||||
</span>
|
||||
</h3>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserPart
|
||||
@@ -8,6 +8,9 @@
|
||||
@import "tailwindcss/base";
|
||||
@import "tailwindcss/components";
|
||||
@import "tailwindcss/utilities";
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Ropa+Sans&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,300;0,500;1,700&display=swap')
|
||||
/**
|
||||
* END --- TAILWIND GENERATOR EDIT
|
||||
*/
|
||||
@@ -33,7 +36,7 @@
|
||||
|
||||
body {
|
||||
/* TODO can I use a tailwind class here? */
|
||||
background-color: #4a5568;
|
||||
background-color: #E5E5E5;
|
||||
}
|
||||
|
||||
button, input, label, textarea {
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<link rel="icon" type="image/png" href="/favi2.jpg" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
|
||||
<script>
|
||||
// Install Cascade Studio as a Progressive Web App for Offline Access
|
||||
// This needs to be put before ANY HTTP Requests are made, so it can cache them.
|
||||
|
||||
@@ -12,36 +12,44 @@ const MainLayout = ({ children }) => {
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<nav className="flex justify-between h-20 bg-gray-900">
|
||||
<nav className="flex justify-between h-20 px-12 bg-gradient-to-r from-gray-900 to-indigo-900">
|
||||
<ul className="flex items-center">
|
||||
<li>
|
||||
<Link to={routes.home()}>
|
||||
<Tooltip title="We need a logo!" >
|
||||
<img src={logo} style={{marginLeft : '50px'}}/>
|
||||
|
||||
<img src={logo} style={{marginLeft : '50px'}}/>
|
||||
|
||||
</Tooltip>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Tooltip title="Very alpha, there's lots of work todo" >
|
||||
<div className="ml-8 flex">
|
||||
<h2 className="text-indigo-200 text-2xl">CadHub</h2>
|
||||
<div className="text-pink-500 pb-4 text-sm" >pre-alpha</div>
|
||||
<div className="ml-12 flex">
|
||||
{/* Because of how specific these styles are to this heading/logo and it doesn't need to be replicated else where as well as it's very precise with the placement of "pre-alpha" I think it's appropriate. */}
|
||||
<h2 className="text-indigo-300 text-5xl font-ropa-sans py-1 tracking-wider" style={{letterSpacing: '0.3em'}}>CadHub</h2>
|
||||
<div className="text-pink-400 text-sm font-bold font-ropa-sans" style={{paddingBottom: '2rem', marginLeft: '-1.8rem'}}>pre-alpha</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="flex items-center">
|
||||
<li className="mr-8 rounded-full border-2 border-indigo-300">
|
||||
<li className="mr-8 h-10 w-10 rounded-full border-2 border-indigo-300 flex items-center justify-center">
|
||||
<Link to={routes.newPart()}>
|
||||
<Svg name="plus" className="text-indigo-300" />
|
||||
</Link>
|
||||
</li>
|
||||
<li className="mr-12 p-px border-2 rounded-full border-indigo-300 text-indigo-200">
|
||||
<a href="#" onClick={isAuthenticated ? logOut : logIn}>
|
||||
{isAuthenticated ? 'Log Out' : 'Log In'}
|
||||
<img src={avatar} className="rounded-full h-10 w-10" />
|
||||
</a>
|
||||
</li>
|
||||
{
|
||||
isAuthenticated ?
|
||||
<li className="h-10 w-10 border-2 rounded-full border-indigo-300 text-indigo-200">
|
||||
<a href="#" onClick={logOut}>
|
||||
<img src={avatar} className="rounded-full object-cover" />
|
||||
</a>
|
||||
</li>:
|
||||
<li>
|
||||
<a href="#" className='text-indigo-200 font-semibold underline' onClick={logIn}>Sign in/up</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -16,7 +16,13 @@ module.exports = {
|
||||
minHeight: {
|
||||
'md': '28rem'
|
||||
},
|
||||
|
||||
fontFamily: {
|
||||
'ropa-sans': ['Ropa Sans', 'Arial', 'sans-serif'],
|
||||
'roboto': ['Roboto', 'Arial', 'sans-serif'],
|
||||
},
|
||||
skew: {
|
||||
'-20': "-20deg"
|
||||
}
|
||||
}
|
||||
},
|
||||
variants: {},
|
||||
|
||||
Reference in New Issue
Block a user