Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/config/env.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Load environment variables from .env file
export const VITE_SERVER_DOMAIN =
import.meta.env.VITE_SERVER_DOMAIN || 'https://code-a2z.onrender.com';
import.meta.env.VITE_SERVER_DOMAIN || 'https://code-a2z-server.vercel.app'; // https://code-a2z.onrender.com for production

// Token configuration
export const TOKEN_CONFIG = {
Expand Down
207 changes: 136 additions & 71 deletions client/src/modules/project/components/project-content.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,161 @@
import { useState } from 'react';
import { Box, Typography, Button } from '@mui/material';
import { OutputBlockData } from '@editorjs/editorjs';

const Img = ({ url, caption }: { url: string; caption: string }) => {
const ParagraphBlock = ({ text }: { text: string }) => {
return <Typography dangerouslySetInnerHTML={{ __html: text }} />;
};

const HeaderBlock = ({ level, text }: { level: number; text: string }) => {
const Tag = level === 3 ? 'h3' : 'h2';
const size = level === 3 ? 'h5' : 'h4';
return (
<div>
<img src={url} alt="" />
{caption.length ? (
<p className="w-full text-center my-3 md:mb-12 text-base text-gray-700">
{caption}
</p>
) : (
''
)}
</div>
<Typography
component={Tag}
variant={size}
fontWeight="bold"
dangerouslySetInnerHTML={{ __html: text }}
/>
);
};

const Quote = ({ quote, caption }: { quote: string; caption: string }) => {
const ImageBlock = ({ url, caption }: { url: string; caption: string }) => {
return (
<div className="bg-purple opacity-10 p-3 pl-5 border-l-4 border-purple">
<p className="text-xl leading-10 md:text-2xl">{quote}</p>
{caption.length ? (
<p className="w-full text-purple text-base">{caption}</p>
) : (
''
<Box textAlign="center" my={2}>
<img
src={url}
alt={caption}
style={{ maxWidth: '100%', borderRadius: '8px' }}
/>
{caption && (
<Typography variant="body2" color="text.secondary" mt={1}>
{caption}
</Typography>
)}
</div>
</Box>
);
};

const List = ({
style,
items,
}: {
style: 'ordered' | 'unordered';
items: string[];
}) => {
const QuoteBlock = ({ text, caption }: { text: string; caption: string }) => {
return (
<ol
className={`pl-5 ${style === 'ordered' ? ' list-decimal' : ' list-disc'}`}
<Box
sx={{
backgroundColor: 'rgba(128, 0, 128, 0.1)',
borderLeft: '4px solid purple',
p: 2,
pl: 3,
my: 2,
}}
>
{items.map((listItem, i) => {
return (
<li
key={i}
className="my-4"
dangerouslySetInnerHTML={{ __html: listItem }}
></li>
);
})}
</ol>
<Typography variant="h6" gutterBottom>
{text}
</Typography>
{caption && (
<Typography variant="body2" color="purple">
{caption}
</Typography>
)}
</Box>
);
};

const ProjectContent = ({ block }: { block: OutputBlockData }) => {
const { type, data } = block;
const ListBlock = ({ style, items }: { style: string; items: string[] }) => {
const Tag = style === 'ordered' ? 'ol' : 'ul';
const styleType = style === 'ordered' ? 'decimal' : 'disc';
return (
<Box component={Tag} pl={3} sx={{ listStyleType: styleType }}>
{items.map((item, i) => (
<li key={i}>
<Typography
dangerouslySetInnerHTML={{ __html: item }}
variant="body1"
/>
</li>
))}
</Box>
);
};

if (type === 'paragraph') {
return <p dangerouslySetInnerHTML={{ __html: data.text || '' }}></p>;
}
const CodeBlock = ({ code, language }: { code: string; language: string }) => {
const codeText = code || '';
const [copied, setCopied] = useState(false);

if (type === 'header') {
if (data.level === 3) {
return (
<h3
className="text-3xl font-bold"
dangerouslySetInnerHTML={{ __html: data.text || '' }}
></h3>
);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(codeText);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
setCopied(false);
}
return (
<h2
className="text-4xl font-bold"
dangerouslySetInnerHTML={{ __html: data.text || '' }}
></h2>
);
}
};

if (type === 'image') {
return <Img url={data.file?.url || ''} caption={data.caption || ''} />;
}
return (
<Box
sx={{
bgcolor: '#1e1e1e',
color: '#f5f5f5',
p: 2,
borderRadius: 1,
overflow: 'auto',
position: 'relative',
}}
>
{language ? (
<Typography
sx={{
position: 'absolute',
top: 8,
left: 8,
fontSize: 12,
opacity: 0.7,
}}
>
{language}
</Typography>
) : null}
<Button
size="small"
onClick={handleCopy}
variant="outlined"
sx={{ position: 'absolute', top: 8, right: 8 }}
>
{copied ? 'Copied' : 'Copy'}
</Button>
<Typography
component="pre"
sx={{ fontFamily: 'monospace', mt: 4, whiteSpace: 'pre-wrap' }}
>
{codeText}
</Typography>
</Box>
);
};

if (type === 'quote') {
return <Quote quote={data.text || ''} caption={data.caption || ''} />;
}
const ProjectContent = ({ block }: { block: OutputBlockData }) => {
const { type, data } = block || {};

if (type === 'list') {
return (
<List
style={(data.style as 'ordered' | 'unordered') || 'unordered'}
items={data.items || []}
/>
);
switch (type) {
case 'paragraph':
return <ParagraphBlock text={data?.text ?? ''} />;
case 'header':
return <HeaderBlock level={data?.level ?? 2} text={data?.text ?? ''} />;
case 'image':
return (
<ImageBlock url={data?.file?.url ?? ''} caption={data?.caption ?? ''} />
);
case 'quote':
return (
<QuoteBlock text={data?.text ?? ''} caption={data?.caption ?? ''} />
);
case 'list':
return <ListBlock style={data?.style} items={data?.items || []} />;
case 'code':
return (
<CodeBlock code={data?.code ?? ''} language={data?.language ?? ''} />
);
default:
return null;
}
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"lint-staged": {
"client/src/**/*.{ts,tsx,js,jsx,css,html}": [
"prettier --write",
"eslint --fix"
"eslint --config client/eslint.config.js --fix"
],
"server/**/*.js": [
"prettier --write",
Expand Down
4 changes: 3 additions & 1 deletion server/src/config/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ dotenv.config();
export const PORT = process.env.PORT || 8000;
export const SERVER_ENV = process.env.SERVER_ENV || 'development';
export const VITE_SERVER_DOMAIN =
process.env.VITE_SERVER_DOMAIN || 'https://code-a2z-server.vercel.app';
process.env.VITE_SERVER_DOMAIN || 'http://localhost:8000';
export const VITE_CLIENT_DOMAIN =
process.env.VITE_CLIENT_DOMAIN || 'http://localhost:5173';

// MongoDB Configuration
export const MONGODB_URL =
Expand Down
4 changes: 3 additions & 1 deletion server/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ server.use(express.json());
server.use(cookieParser());
server.use(
cors({
origin: process.env.VITE_CLIENT_DOMAIN || 'http://localhost:5173',
origin: '*',
credentials: true,
methods: 'GET,POST,PUT,DELETE',
allowedHeaders: 'Content-Type,Authorization',
})
);

Expand Down
Loading