• npx create-react-app tailwindreact-app --template typescript
npm install tailwindcss postcss autoprefixer
npm uninstall tailwindcss postcss autoprefixer
npm install tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
npx tailwindcss init -p
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
{
"name": "tailwindreact-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"autoprefixer": "^10.2.4",
"postcss": "^8.2.6",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.2",
"tailwindcss": "^2.0.3",
"typescript": "^4.1.5",
"web-vitals": "^1.0.1"
},
"scripts": {
"build:tailwind": "tailwindcss build src/css/tailwind.css -o src/css/tailwind.output.css",
"prestart": "npm run build:tailwind",
"prebuild": "npm run build:tailwind",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/react": "^17.0.1",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7"
}
}
import React from 'react';
import ReactDOM from 'react-dom';
import './css/tailwind.output.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
import React from 'react';
export function NewPost() {
return <div>New Post Comment</div>
}
import React from 'react';
import * as api from '../api/posts';
import Post from './Post';
const MockPosts: api.Post[] = [
{
id: 'AXY_001',
text: 'Hello Everyone! Welcome to my first: Microblogging App Page',
createdAt: '2021-02-06T05:56:09Z',
authorId: '001',
authorUserName: '@Shiromani',
authorDisplayName: 'Shiromani Soni',
authorImageUrl: '*******',
likeCount: 2,
replyCount: 3,
attachmentType: 'image',
attachmentUrl: '*******',
},
{
id: 'AXY_002',
text: 'Sample Post',
createdAt: '2021-02-10T05:56:09Z',
authorId: '002',
authorUserName: '@John',
authorDisplayName: 'John Rowlands',
likeCount: 0,
replyCount: 0,
},
];
export function PostList() {
return (
<ul className='border border-t-8 divide-y divide-grey-300'>
{MockPosts.map((p) => {
return (
<li key={p.id} className='px-6 py-4'>
<Post post={p} />
</li>
);
})}
</ul>
);
}
type AttachmentType = 'image' | 'video' | { custom: string }
export interface Post {
id: string;
text: string;
createdAt: string;
authorId: string;
authorUserName: string;
authorDisplayName: string;
authorImageUrl?: string;
likeCount: number;
replyCount: number;
conversationId?: string;
replies?: Post[];
attachmentUrl?: string;
attachmentType?: AttachmentType;
}
import React from 'react';
import * as api from '../api/posts';
import { getRelativeTime } from '../utils/time';
type postProps = {
post: api.Post;
};
function PhotoPlaceHolder() {
return (
<svg
className='block w-12 h-12 mt-1'
viewBox='0 0 50 50'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<circle cx='25' cy='25' r='25' fill='#4A5568'/>
</svg>
);
}
export default function Post({ post }: postProps) {
const {
authorDisplayName,
authorImageUrl,
authorUserName,
createdAt,
text,
attachmentType,
attachmentUrl,
} = post;
return (
<div className='flex'>
<div className= 'block w-12 h-12'>
{
authorImageUrl ? (
<img className='rounded-full'
src={authorImageUrl}
alt={authorDisplayName}
/>
) : (
<PhotoPlaceHolder></PhotoPlaceHolder>
)
}
</div>
<div className='ml-2'>
<div>
<span className='font-semibold text-black cursor-pointer hover:underline'>{authorDisplayName}</span>
<span className='ml-1 text-gray-600'>{authorUserName}</span>
<span className='mx-1 text-gray-600'>.</span>
<span className='text-gray-600 cursor-pointer hover:underline'>
{getRelativeTime(createdAt)}
</span>
</div>
{attachmentType && attachmentType === 'image' && (
<div className='mt-2'>
<img alt={text} src={attachmentUrl}/>
</div>
)}
</div>
</div>
);
}
import React from 'react';
import { NewPost } from './components/NewPost';
import { PostList } from './components/PostList';
export function Home() {
return (
<div className='h-screen bg-white'>
<h1 className='text-3xl text-center text-grey-900'>Home Page</h1>
<div className="flex justify-center mx-2 mt-12">
<div className='max-w-xl'>
<NewPost></NewPost>
<PostList></PostList>
</div>
</div>
</div>
);
}
export function getRelativeTime(dateString: string): string {
const msPerMinute = 60 * 1000;
const msPerHour = msPerMinute * 60;
const msPerDay = msPerHour * 24;
const elapsed = Date.now() - Date.parse(dateString);
if (elapsed < msPerMinute) {
return Math.round(elapsed / 1000) + 's';
}
else if (elapsed < msPerHour) {
return Math.round(elapsed / msPerMinute) + 'm';
}
else if (elapsed < msPerDay) {
return Math.round(elapsed / msPerHour) + 'h';
}
else {
const d = new Date(dateString);
return d.toLocaleString('default', { month: 'short', day: 'numeric'})
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
4 | |
4 | |
3 | |
3 | |
3 | |
3 | |
3 | |
3 | |
3 | |
2 |