Merge branch 'master' into fix/icon
3
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [rutikwankhade]
|
3
.gitignore
vendored
@ -12,6 +12,7 @@
|
||||
/build
|
||||
|
||||
# misc
|
||||
.env
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
@ -21,3 +22,5 @@
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
|
||||
|
23
README.md
@ -1,6 +1,8 @@
|
||||
<p align="center">
|
||||
<img width="300px" src="https://user-images.githubusercontent.com/47467468/90390293-b8eeb280-e0a8-11ea-82cf-9efa89773094.png" align="center" alt="" />
|
||||
<p align="center">
|
||||
|
||||
|
||||
## Coverview
|
||||
Creating cover images for your blogs is now super easy.
|
||||
<p>
|
||||
<a href="https://github.com/rutikwankhade/CoverView"><img src="https://img.shields.io/github/stars/rutikwankhade/CoverView.svg?style=social&label=Star"></a>
|
||||
<a href="https://github.com/rutikwankhade/CoverView"><img src="https://badges.frapsoft.com/os/v1/open-source.svg?v=103"></a>
|
||||
<a href="https://lbesson.mit-license.org"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
|
||||
@ -10,20 +12,21 @@
|
||||
</p>
|
||||
|
||||
|
||||
<p align="center">🛠 Create awesome cover images for your blog posts quickly.</p>
|
||||
<p align="center">
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/47467468/148546132-2b608b8c-ab27-4888-9898-e0b489142c47.png" height="auto" width="800px" margin="20px">
|
||||
|
||||
</p>
|
||||
</p>
|
||||
<img src="https://user-images.githubusercontent.com/47467468/175771056-bf7fa9a0-801b-4887-80b5-169735923d64.png" height="auto" width="800px" margin="20px">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## ⚡ Features
|
||||
- 🛠 Create cover images for your blogs quickly and easily
|
||||
- 🚀 super fast and easy to use
|
||||
- 🌈 4 different themes, multiple fonts
|
||||
- 🌠 100+ dev icons with option to upload custom icon
|
||||
- ✨ 15+ different background patterns
|
||||
- 💾 Download cover images in `.png` as well as `.jpeg` format
|
||||
- 💾 Cover size based on blogging platform (i.e hashnode and dev)
|
||||
|
||||
## 👩💻 Developing
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
68
package-lock.json
generated
@ -1946,6 +1946,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@headlessui/react": {
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.7.tgz",
|
||||
"integrity": "sha512-BqDOd/tB9u2tA0T3Z0fn18ktw+KbVwMnkxxsGPIH2hzssrQhKB5n/6StZOyvLYP/FsYtvuXfi9I0YowKPv2c1w==",
|
||||
"requires": {
|
||||
"client-only": "^0.0.1"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
|
||||
@ -3327,6 +3335,11 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/content-type": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/content-type/-/content-type-1.1.5.tgz",
|
||||
"integrity": "sha512-dgMN+syt1xb7Hk8LU6AODOfPlvz5z1CbXpPuJE5ZrX9STfBOIXF09pEB8N7a97WT9dbngt3ksDCm6GW6yMrxfQ=="
|
||||
},
|
||||
"@types/eslint": {
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz",
|
||||
@ -5027,6 +5040,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"client-only": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
@ -5759,6 +5777,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dom-to-image": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-to-image/-/dom-to-image-2.6.0.tgz",
|
||||
"integrity": "sha512-Dt0QdaHmLpjURjU7Tnu3AgYSF2LuOmksSGsUcE6ItvJoCWTBEmiMXcqBdNSAm9+QbbwD7JMoVsuuKX6ZVQv1qA=="
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
|
||||
@ -5820,9 +5843,9 @@
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
|
||||
"integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ=="
|
||||
},
|
||||
"dotenv-expand": {
|
||||
"version": "5.1.0",
|
||||
@ -7370,6 +7393,14 @@
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||
},
|
||||
"history": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
|
||||
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.7.6"
|
||||
}
|
||||
},
|
||||
"hoopy": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||
@ -12428,6 +12459,23 @@
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
|
||||
},
|
||||
"react-router": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
||||
"integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
|
||||
"requires": {
|
||||
"history": "^5.2.0"
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
|
||||
"integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
|
||||
"requires": {
|
||||
"history": "^5.2.0",
|
||||
"react-router": "6.3.0"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||
@ -12483,6 +12531,11 @@
|
||||
"workbox-webpack-plugin": "^6.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
@ -14069,6 +14122,15 @@
|
||||
"resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
|
||||
"integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ="
|
||||
},
|
||||
"unsplash-js": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/unsplash-js/-/unsplash-js-7.0.15.tgz",
|
||||
"integrity": "sha512-WGqKp9wl2m2tAUPyw2eMZs/KICR+A52tCaRapzVXWxkA4pjHqsaGwiJXTEW7hBy4Pu0QmP6KxTt2jST3tluawA==",
|
||||
"requires": {
|
||||
"@types/content-type": "^1.1.3",
|
||||
"content-type": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"upath": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
|
||||
|
@ -3,14 +3,19 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.7.7",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"dom-to-image": "^2.6.0",
|
||||
"dotenv": "^16.0.1",
|
||||
"react": "^16.13.1",
|
||||
"react-component-export-image": "^0.1.6",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-select": "^3.1.0"
|
||||
"react-select": "^3.1.0",
|
||||
"unsplash-js": "^7.0.15"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
@ -6,30 +6,37 @@
|
||||
<link rel="icon" href="./logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://coverview.vercel.app/">
|
||||
<meta property="og:title" content="Coverview">
|
||||
<meta property="og:description" content="Creating cover images for your blogs is now super easy">
|
||||
<meta property="og:image" content="https://user-images.githubusercontent.com/47467468/164884365-f5533a4a-1c5e-42a1-adb8-c1843ee33b92.png">
|
||||
|
||||
<meta name="description" content="Creating cover images for your blogs is now super easy" />
|
||||
<meta property="og:url" content="https://coverview.vercel.app/">
|
||||
<meta property="og:title" content="Coverview: Creating cover images for your blogs is now super easy">
|
||||
<meta property="og:description" content="Coverview is an open-source tool to create cover images for your blogs quickly and easily. Customize with different themes, colors, fonts and more.">
|
||||
<meta property="og:image"
|
||||
content="https://user-images.githubusercontent.com/47467468/180610249-d24b4ffa-e059-4678-8788-5795498b168c.png">
|
||||
|
||||
<meta name="description" content="Coverview is an open-source tool to create cover images for your blogs quickly and easily. Customize with different themes, colors, fonts and more." />
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:url" content="https://coverview.now.sh/">
|
||||
<meta property="twitter:title" content="CoverView">
|
||||
<meta property="twitter:description" content="Create an awesome cover image for your next blog post ">
|
||||
<meta property="twitter:url" content="https://coverview.vercel.app/">
|
||||
<meta property="twitter:title" content="CoverView: Creating cover images for your blogs is now super easy">
|
||||
<meta property="twitter:description" content="Coverview is an open-source tool to create cover images for your blogs quickly and easily. Customize with different themes, colors, fonts and more.">
|
||||
<meta property="twitter:image"
|
||||
content="https://user-images.githubusercontent.com/47467468/164884365-f5533a4a-1c5e-42a1-adb8-c1843ee33b92.png">
|
||||
content="https://user-images.githubusercontent.com/47467468/180610249-d24b4ffa-e059-4678-8788-5795498b168c.png">
|
||||
<link rel="apple-touch-icon" href="./logo.png" />
|
||||
<!-- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.1/css/bootstrap.min.css"
|
||||
integrity="sha384-VCmXjywReHh4PwowAiWNagnWcLhlEJLA5buUprzK8rxFgeH0kww/aWY76TfkUoSX" crossorigin="anonymous"> -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/konpa/devicon@master/devicon.min.css">
|
||||
<script defer data-domain="coverview.vercel.app" src="https://plausible.io/js/plausible.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/konpa/devicon@master/devicon.min.css" crossorigin="anonymous">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
|
||||
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Anek+Latin:wght@400;500;600;700&display=swap?" rel="stylesheet" crossorigin="anonymous">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap" rel="stylesheet" crossorigin="anonymous">
|
||||
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
@ -39,7 +46,11 @@
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>Coverview</title>
|
||||
<!-- Place this tag in your head or just before your close body tag. -->
|
||||
<script defer type="text/javascript" src="https://api.pirsch.io/pirsch.js" id="pirschjs"
|
||||
data-code="y1wOy094LZLgd8a0GcLjDsPVQygfceIB"></script>
|
||||
<meta name="google-site-verification" content="iC9xqg_PeFTmMUq-zSDqnsyaimqm8NQ2bp6Kxpbyzz4" />
|
||||
<title>Coverview - Creating cover images for your blogs is now super easy</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
BIN
public/logo.png
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 15 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"short_name": "Coverview",
|
||||
"name": "Coverview",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
@ -8,12 +8,12 @@
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"src": "logo.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"src": "logo.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
|
BIN
src/assets/icons/logo.png
Normal file
After Width: | Height: | Size: 15 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M12 16c1.671 0 3-1.331 3-3s-1.329-3-3-3-3 1.331-3 3 1.329 3 3 3z"></path><path d="M20.817 11.186a8.94 8.94 0 0 0-1.355-3.219 9.053 9.053 0 0 0-2.43-2.43 8.95 8.95 0 0 0-3.219-1.355 9.028 9.028 0 0 0-1.838-.18V2L8 5l3.975 3V6.002c.484-.002.968.044 1.435.14a6.961 6.961 0 0 1 2.502 1.053 7.005 7.005 0 0 1 1.892 1.892A6.967 6.967 0 0 1 19 13a7.032 7.032 0 0 1-.55 2.725 7.11 7.11 0 0 1-.644 1.188 7.2 7.2 0 0 1-.858 1.039 7.028 7.028 0 0 1-3.536 1.907 7.13 7.13 0 0 1-2.822 0 6.961 6.961 0 0 1-2.503-1.054 7.002 7.002 0 0 1-1.89-1.89A6.996 6.996 0 0 1 5 13H3a9.02 9.02 0 0 0 1.539 5.034 9.096 9.096 0 0 0 2.428 2.428A8.95 8.95 0 0 0 12 22a9.09 9.09 0 0 0 1.814-.183 9.014 9.014 0 0 0 3.218-1.355 8.886 8.886 0 0 0 1.331-1.099 9.228 9.228 0 0 0 1.1-1.332A8.952 8.952 0 0 0 21 13a9.09 9.09 0 0 0-.183-1.814z"></path></svg>
|
Before Width: | Height: | Size: 890 B |
BIN
src/assets/images/cover1.webp
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
src/assets/images/cover2.webp
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
src/assets/images/cover3.webp
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
src/assets/images/cover4.webp
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
src/assets/images/cover5.webp
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
src/assets/images/dev-logo.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/images/hashnode-logo.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
src/assets/images/step1.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/images/step2.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/theme1.webp
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/assets/images/theme2.webp
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/images/theme3.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/images/theme4.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/images/theme5.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/images/theme6.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/images/theme7.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
@ -1,16 +1,22 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
||||
|
||||
import Editor from './Editor';
|
||||
import Home from './Home'
|
||||
import Faq from './Faq';
|
||||
|
||||
class App extends React.Component {
|
||||
const App = () => {
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route exact path="/" element={<Home />} />
|
||||
<Route exact path="/editor" element={<Editor />} />
|
||||
<Route exact path="/faq" element={<Faq />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="content ">
|
||||
<Editor />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default App;
|
@ -1,25 +1,83 @@
|
||||
import React from "react";
|
||||
import { exportComponentAsPNG } from "react-component-export-image";
|
||||
import React, { useContext, useState } from "react";
|
||||
// import { exportComponentAsPNG } from "react-component-export-image";
|
||||
import "./CoverImage.css";
|
||||
import { ImgContext } from "../utils/ImgContext";
|
||||
import unsplash from "../utils/unsplashConfig";
|
||||
import domtoimage from "dom-to-image";
|
||||
|
||||
class ComponentToImg extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.componentRef = React.createRef();
|
||||
const ComponentToImg = (props) => {
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const { unsplashImage } = useContext(ImgContext);
|
||||
const componentRef = React.createRef();
|
||||
|
||||
|
||||
|
||||
|
||||
async function saveImage(data) {
|
||||
var a = document.createElement("A");
|
||||
a.href = data;
|
||||
a.download = `cover.png`;
|
||||
document.body.appendChild(a);
|
||||
setLoading(false)
|
||||
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
render() {
|
||||
const downloadImage = async () => {
|
||||
// exportComponentAsPNG(componentRef, 'cover')
|
||||
setLoading(true)
|
||||
|
||||
const element = componentRef.current;
|
||||
|
||||
// console.log(element)
|
||||
// console.log(element.offsetHeight)
|
||||
|
||||
let data = await domtoimage.toPng(componentRef.current, {
|
||||
height: element.offsetHeight * 2,
|
||||
width: element.offsetWidth * 2,
|
||||
style: {
|
||||
transform: "scale(" + 2 + ")",
|
||||
transformOrigin: "top left",
|
||||
width: element.offsetWidth + "px",
|
||||
height: element.offsetHeight + "px",
|
||||
}
|
||||
})
|
||||
|
||||
console.log(data)
|
||||
await saveImage(data);
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div ref={this.componentRef}>{this.props.children}</div>
|
||||
<button
|
||||
className="border p-2 bg-gray-700 hover:bg-gray-800 text-white text-xl rounded m-4 px-4"
|
||||
onClick={() => exportComponentAsPNG(this.componentRef, 'cover')}>Download</button>
|
||||
</React.Fragment>
|
||||
);
|
||||
if (unsplashImage) {
|
||||
unsplash.photos.trackDownload({ downloadLocation: unsplashImage.downloadLink, });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div ref={componentRef}>{props.children}</div>
|
||||
<button
|
||||
className="border p-2 bg-gray-700 hover:bg-gray-800 flex items-center text-white text-xl rounded-lg m-4 px-4"
|
||||
onClick={() => downloadImage()}>
|
||||
|
||||
|
||||
<span>
|
||||
{
|
||||
loading ?
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-6 h-6 text-white animate animate-spin" fill="currentColor" width="24" height="24" viewBox="0 0 24 24" ><path d="M12 22c5.421 0 10-4.579 10-10h-2c0 4.337-3.663 8-8 8s-8-3.663-8-8c0-4.336 3.663-8 8-8V2C6.579 2 2 6.58 2 12c0 5.421 4.579 10 10 10z"></path></svg>
|
||||
:
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
|
||||
}
|
||||
</span>
|
||||
|
||||
<span className="mx-2">Download</span>
|
||||
</button>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default ComponentToImg;
|
||||
|
@ -1,14 +1,10 @@
|
||||
.cover {
|
||||
display: flex;
|
||||
height: 420px;
|
||||
width: 800px;
|
||||
overflow-y: hidden;
|
||||
.dev {
|
||||
height: 340px;
|
||||
width: 860px;
|
||||
}
|
||||
|
||||
@media screen and (max-width:600px) {
|
||||
.cover {
|
||||
width: 90vw;
|
||||
height: 60vh;
|
||||
padding: 4vh;
|
||||
}
|
||||
.hashnode {
|
||||
height: 420px;
|
||||
width: 800px;
|
||||
|
||||
}
|
@ -5,6 +5,9 @@ import ModernTheme from "./Themes/ModernTheme";
|
||||
import BasicTheme from "./Themes/BasicTheme";
|
||||
import OutlineTheme from "./Themes/OutlineTheme";
|
||||
import PreviewTheme from "./Themes/PreviewTheme";
|
||||
import StylishTheme from "./Themes/StylishTheme";
|
||||
import MobileMockupTheme from "./Themes/MobileMockupTheme";
|
||||
import BackgroundTheme from "./Themes/BackgroundTheme";
|
||||
|
||||
const CoverImage = (props) => {
|
||||
// hexToRgbA(hex, opacity) {
|
||||
@ -28,6 +31,9 @@ const CoverImage = (props) => {
|
||||
case 'modern': return <ModernTheme config={props} />
|
||||
case 'outline': return <OutlineTheme config={props} />
|
||||
case 'preview': return <PreviewTheme config={props} />
|
||||
case 'stylish': return <StylishTheme config={props} />
|
||||
case 'mobile': return <MobileMockupTheme config={props} />
|
||||
case 'background': return <BackgroundTheme config={props} />
|
||||
|
||||
default: return <BasicTheme config={props} />
|
||||
}
|
||||
@ -35,7 +41,7 @@ const CoverImage = (props) => {
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="md:w-full md:scale-100 scale-50">
|
||||
{selectTheme(theme)} </div>
|
||||
);
|
||||
|
||||
|
@ -3,22 +3,35 @@ import CoverImage from "./CoverImage";
|
||||
import ComponentToImg from "./ComponentToImg";
|
||||
import Select from 'react-select';
|
||||
import RandomTheme from './RandomTheme';
|
||||
// import resetIcon from '../assets/icons/reset.svg'
|
||||
import { ImgProvider } from '../utils/ImgContext'
|
||||
import Header from "./Header";
|
||||
import { Tab } from '@headlessui/react'
|
||||
|
||||
import theme1 from '../assets/images/theme1.webp'
|
||||
import theme2 from '../assets/images/theme2.webp'
|
||||
import theme3 from '../assets/images/theme3.webp'
|
||||
import theme4 from '../assets/images/theme4.webp'
|
||||
import theme5 from '../assets/images/theme5.webp'
|
||||
import theme6 from '../assets/images/theme6.webp'
|
||||
import theme7 from '../assets/images/theme7.webp'
|
||||
|
||||
|
||||
|
||||
|
||||
const defaultIcon = { 'label': 'react', 'value': 'react' }
|
||||
|
||||
const defaultSettings = {
|
||||
title: "How I built my first project with react",
|
||||
bgColor: "#dcd6f7",
|
||||
title: "A begineers guide to frontend development",
|
||||
bgColor: "#949ee5",
|
||||
pattern: "",
|
||||
download: "PNG",
|
||||
author: 'Rutik Wankhade',
|
||||
icon: defaultIcon,
|
||||
devIconOptions: [defaultIcon],
|
||||
font: 'font-sans',
|
||||
theme: 'modern',
|
||||
customIcon: ''
|
||||
|
||||
font: 'font-Anek',
|
||||
theme: 'background',
|
||||
customIcon: '',
|
||||
platform: 'hashnode'
|
||||
};
|
||||
|
||||
const devIconsUrl = "https://raw.githubusercontent.com/devicons/devicon/master/devicon.json"
|
||||
@ -26,9 +39,12 @@ const devIconsUrl = "https://raw.githubusercontent.com/devicons/devicon/master/d
|
||||
// { value: 'None', label: 'None' },
|
||||
// { value: 'javascript', label: 'Javascript' },
|
||||
// { value: 'python', label: 'Python' },
|
||||
// ]
|
||||
|
||||
|
||||
class Editor extends React.Component {
|
||||
|
||||
|
||||
state = defaultSettings;
|
||||
componentDidMount() {
|
||||
console.log("Mount")
|
||||
@ -55,178 +71,215 @@ class Editor extends React.Component {
|
||||
);
|
||||
|
||||
|
||||
// customOption = props => {
|
||||
// const { data, innerRef, innerProps } = props;
|
||||
|
||||
// return data.name === 'custom' ? (
|
||||
// <div ref={innerRef} {...innerProps}>
|
||||
// <input type="file"
|
||||
// className="text-xl cursor-pointer mb-2 bg-white rounded border"
|
||||
// onChange={(e) => this.setState({ 'customIcon': URL.createObjectURL(e.target.files[0]) })}
|
||||
// />
|
||||
// </div>
|
||||
// ) : (
|
||||
// <components.Option {...props} />
|
||||
// );
|
||||
|
||||
|
||||
// };
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="flex md:flex-row flex-col bg-gray-50 ">
|
||||
<div className="bg-white shadow-sm p-4 flex flex-col md:w-1/4">
|
||||
{/* <p className="tagline"><span role="img" aria-label="tool"> 🛠 </span> Creating cover images for your blogs is now super easy</p> */}
|
||||
<div>
|
||||
<Header />
|
||||
|
||||
<div className="flex items-center mb-4 ">
|
||||
<h1 className=" text-gray-800 text-2xl font-bold ">Coverview</h1>
|
||||
<a href="https://github.com/rutikwankhade/CoverView"
|
||||
target="_blank" rel="noopener noreferrer"
|
||||
className="ml-auto mr-2 cursor-pointer">
|
||||
<i className=" devicon-github-plain dev-icon text-xl"></i>
|
||||
<ImgProvider>
|
||||
<div className="flex md:flex-row flex-col bg-gray-50 ">
|
||||
|
||||
</a>
|
||||
<div className="bg-white flex flex-col h-100 md:w-4/12">
|
||||
|
||||
</div>
|
||||
<div className="m-2 flex flex-col">
|
||||
<span className="font-medium">Blog Title</span>
|
||||
<textarea
|
||||
type="text"
|
||||
value={this.state.title}
|
||||
placeholder="Enter title here"
|
||||
className="border text-gray-700 text-xl rounded p-2 h-24"
|
||||
onChange={(e) => this.setState({ title: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<Tab.Group>
|
||||
<div className="flex md:flex-row flex-col">
|
||||
|
||||
<div className="flex flex-col m-2 ">
|
||||
<span className="font-medium">Author</span>
|
||||
<input
|
||||
type="text"
|
||||
value={this.state.author}
|
||||
placeholder="Author"
|
||||
className="border text-gray-700 text-xl rounded bg-white p-2"
|
||||
onChange={(e) => this.setState({ author: e.target.value })}
|
||||
></input>
|
||||
</div>
|
||||
<Tab.List className=" bg-white md:p-0 p-2 flex flex-row md:flex-col">
|
||||
<Tab className="flex items-center font-semibold ">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" className="text-gray- bg-white rounded-xl w-12 m-2 h-12 p-2 rounded border" width="24" height="24" viewBox="0 0 24 24" ><path d="M19.045 7.401c.378-.378.586-.88.586-1.414s-.208-1.036-.586-1.414l-1.586-1.586c-.378-.378-.88-.586-1.414-.586s-1.036.208-1.413.585L4 13.585V18h4.413L19.045 7.401zm-3-3 1.587 1.585-1.59 1.584-1.586-1.585 1.589-1.584zM6 16v-1.585l7.04-7.018 1.586 1.586L7.587 16H6zm-2 4h16v2H4z"></path></svg>
|
||||
</Tab>
|
||||
|
||||
<Tab className="flex items-center font-semibold text-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" className=" text-gray-800 bg-white rounded-xl w-12 h-12 p-2 m-2 rounded border" width="24" height="24" viewBox="0 0 24 24" ><path d="M11.024 11.536 10 10l-2 3h9l-3.5-5z"></path><circle cx="9.503" cy="7.497" r="1.503"></circle><path d="M19 2H6c-1.206 0-3 .799-3 3v14c0 2.201 1.794 3 3 3h15v-2H6.012C5.55 19.988 5 19.806 5 19s.55-.988 1.012-1H21V4c0-1.103-.897-2-2-2zm0 14H5V5c0-.806.55-.988 1-1h13v12z"></path></svg>
|
||||
</Tab>
|
||||
</Tab.List>
|
||||
|
||||
|
||||
<Tab.Panels className="bg-white border-l w-full p-4 ">
|
||||
<Tab.Panel>
|
||||
|
||||
<div className="flex items-center">
|
||||
<div className="m-2 flex flex-col">
|
||||
<span className="font-medium pb-1">Blog Title</span>
|
||||
<textarea
|
||||
type="text"
|
||||
value={this.state.title}
|
||||
placeholder="Enter title here"
|
||||
className="focus:outline-none border text-gray-700 text-xl rounded p-2 h-24"
|
||||
onChange={(e) => this.setState({ title: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col m-2 w-1/2">
|
||||
<span className="font-medium">Font</span>
|
||||
<div className="flex flex-col m-2 ">
|
||||
<span className="font-medium pb-1">Author</span>
|
||||
<input
|
||||
type="text"
|
||||
value={this.state.author}
|
||||
placeholder="Author"
|
||||
className="focus:outline-none border text-gray-700 text-xl rounded bg-white p-2"
|
||||
onChange={(e) => this.setState({ author: e.target.value })}
|
||||
></input>
|
||||
</div>
|
||||
|
||||
<select
|
||||
value={this.state.font}
|
||||
<div className="flex flex-col m-2 ">
|
||||
<span className="font-medium pb-1">Icon</span>
|
||||
<Select value={this.state.icon}
|
||||
onChange={(selectedOption) => this.setState({ icon: selectedOption })}
|
||||
options={this.state.devIconOptions}
|
||||
formatOptionLabel={this.formatOptionLabel}
|
||||
className="outline-none focus:outline-none text-xl text-gray-700"
|
||||
/>
|
||||
</div>
|
||||
|
||||
onChange={(e) => this.setState({ font: e.target.value })}
|
||||
{this.state.icon.label === 'custom' ?
|
||||
<div className="flex items-center justify-center m-2">
|
||||
<input type="file"
|
||||
className="focus:outline-none text-lg cursor-pointer bg-white rounded border"
|
||||
onChange={(e) => this.setState({ 'customIcon': URL.createObjectURL(e.target.files[0]) })}
|
||||
/>
|
||||
</div>
|
||||
:
|
||||
<div></div>
|
||||
}
|
||||
|
||||
className=" text-gray-700 text-xl p-2 rounded border">
|
||||
<option>font-serif</option>
|
||||
<option>font-sans</option>
|
||||
<option>font-mono</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex flex-col m-2 ">
|
||||
<span className="font-medium">Color</span>
|
||||
<div className="border rounded flex items-center p-2">
|
||||
<div className="flex items-center">
|
||||
|
||||
<span className="text-sm text-gray-700 font-semibold mx-2">{this.state.bgColor}</span>
|
||||
<input type="color" value={this.state.bgColor}
|
||||
onChange={(e) => this.setState({ bgColor: e.target.value })}
|
||||
className="h-8 w-8 rounded"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col m-2 w-1/2">
|
||||
<span className="font-medium pb-1">Font</span>
|
||||
|
||||
</div>
|
||||
<select
|
||||
value={this.state.font}
|
||||
onChange={(e) => this.setState({ font: e.target.value })}
|
||||
className="focus:outline-none text-gray-700 text-xl p-2 rounded border">
|
||||
<option>font-serif</option>
|
||||
<option>font-sans</option>
|
||||
<option>font-mono</option>
|
||||
<option>font-Inter</option>
|
||||
<option>font-Poppins</option>
|
||||
<option>font-Anek</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex flex-col m-2 w-1/2">
|
||||
<span className="font-medium pb-1">Color</span>
|
||||
<div className="border rounded flex items-center p-2">
|
||||
|
||||
<span className="text-xl text-gray-700 mx-2">{this.state.bgColor}</span>
|
||||
<input type="color" value={this.state.bgColor}
|
||||
onChange={(e) => this.setState({ bgColor: e.target.value })}
|
||||
className="h-8 w-8 ml-auto mr-1 rounded"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex items-center">
|
||||
<div className="flex flex-col m-2 w-1/2">
|
||||
<span className="font-medium pb-1">Pattern</span>
|
||||
<select
|
||||
onChange={(e) => this.setState({ pattern: e.target.value })}
|
||||
className="focus:outline-none border text-xl p-2 rounded"
|
||||
value={this.state.pattern}>
|
||||
|
||||
<option>none</option>
|
||||
<option>graph-paper</option>
|
||||
<option>jigsaw</option>
|
||||
<option>hideout</option>
|
||||
<option>dots</option>
|
||||
<option>falling-triangles</option>
|
||||
<option>circuit-board</option>
|
||||
<option>temple</option>
|
||||
<option>anchors</option>
|
||||
<option>brickwall</option>
|
||||
<option>overlapping-circles</option>
|
||||
<option>wiggle</option>
|
||||
<option>tic-tac-toe</option>
|
||||
<option>leaf</option>
|
||||
<option>bubbles</option>
|
||||
<option>squares</option>
|
||||
<option>explorer</option>
|
||||
<option>jupiter</option>
|
||||
<option>sun</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col m-2 w-1/2">
|
||||
<span className="font-medium pb-1">Platform</span>
|
||||
|
||||
<select
|
||||
onChange={(e) => this.setState({ platform: e.target.value })}
|
||||
value={this.state.platform}
|
||||
className="focus:outline-none text-gray-700 text-xl p-2 rounded border">
|
||||
<option>hashnode</option>
|
||||
<option>dev</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="flex items-center bg-gray-700 text-white rounded-lg mt-6 text-lg font-semibold p-1 px-4 mx-auto border"
|
||||
onClick={this.handleReset}>
|
||||
<span>Reset All</span>
|
||||
</button>
|
||||
|
||||
</Tab.Panel>
|
||||
|
||||
|
||||
<Tab.Panel className="h-99 w-full flex flex-col justify-center">
|
||||
|
||||
<div className="flex items-center border rounded-xl border-gray-50 px-4">
|
||||
<h2 className="text-lg pl-2 font-inter font-semibold">Themes</h2>
|
||||
<div className="ml-auto mr-1 p-2">
|
||||
<RandomTheme onThemeChange={this.getRandomTheme} />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 flex flex-wrap overflow-y-scroll ">
|
||||
|
||||
<img src={theme7} alt="basic theme"
|
||||
onClick={(e) => this.setState({ theme: "background" })}
|
||||
className=" cursor-pointer border border-gray-100 hover:border-gray-200 hover:scale-105 duration-300 m-2"
|
||||
/>
|
||||
<img src={theme1} alt="basic theme"
|
||||
onClick={(e) => this.setState({ theme: "basic" })}
|
||||
className=" cursor-pointer border-gray-100 hover:scale-105 duration-300 hover:border-gray-200 border m-2 "
|
||||
/>
|
||||
<img src={theme2} alt="basic theme"
|
||||
onClick={(e) => this.setState({ theme: "modern" })}
|
||||
className="cursor-pointer border-gray-100 hover:scale-105 hover:border-gray-200 duration-300 border m-2 "
|
||||
/>
|
||||
<img src={theme3} alt="basic theme"
|
||||
onClick={(e) => this.setState({ theme: "stylish" })}
|
||||
className=" cursor-pointer border border-gray-100 hover:border-gray-200 hover:scale-105 duration-300 m-2"
|
||||
/>
|
||||
|
||||
<img src={theme5} alt="basic theme"
|
||||
onClick={(e) => this.setState({ theme: "outline" })}
|
||||
className=" cursor-pointer border border-gray-100 hover:border-gray-200 hover:scale-105 duration-300 m-2"
|
||||
/>
|
||||
|
||||
<img src={theme4} alt="basic theme"
|
||||
onClick={(e) => this.setState({ theme: "preview" })}
|
||||
className=" cursor-pointer border border-gray-100 hover:border-gray-200 hover:scale-105 duration-300 m-2"
|
||||
/>
|
||||
<img src={theme6} alt="basic theme"
|
||||
onClick={(e) => this.setState({ theme: "mobile" })}
|
||||
className=" cursor-pointer border border-gray-100 hover:border-gray-200 hover:scale-105 duration-300 m-2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex flex-col m-2 ">
|
||||
<span className="font-medium">Icon</span>
|
||||
<Select value={this.state.icon}
|
||||
onChange={(selectedOption) => this.setState({ icon: selectedOption })}
|
||||
options={this.state.devIconOptions}
|
||||
formatOptionLabel={this.formatOptionLabel}
|
||||
className="text-xl text-gray-700"
|
||||
/>
|
||||
</div>
|
||||
</Tab.Panel>
|
||||
</Tab.Panels>
|
||||
|
||||
{this.state.icon.label === 'custom' ?
|
||||
<div className="flex items-center justify-center m-2">
|
||||
<input type="file"
|
||||
className="text-lg cursor-pointer bg-white rounded border"
|
||||
onChange={(e) => this.setState({ 'customIcon': URL.createObjectURL(e.target.files[0]) })}
|
||||
/>
|
||||
</div>
|
||||
:
|
||||
<div></div>
|
||||
}
|
||||
|
||||
<div className="flex">
|
||||
</div>
|
||||
</Tab.Group>
|
||||
|
||||
|
||||
<div className="flex flex-col m-2 w-1/2">
|
||||
<span className="font-medium">Pattern</span>
|
||||
<select
|
||||
onChange={(e) => this.setState({ pattern: e.target.value })}
|
||||
className="border text-xl p-2 rounded"
|
||||
value={this.state.pattern}>
|
||||
|
||||
<option>None</option>
|
||||
<option>graph-paper</option>
|
||||
<option>jigsaw</option>
|
||||
<option>hideout</option>
|
||||
<option>dots</option>
|
||||
<option>falling-triangles</option>
|
||||
<option>circuit-board</option>
|
||||
<option>temple</option>
|
||||
<option>anchors</option>
|
||||
<option>brickwall</option>
|
||||
<option>overlapping-circles</option>
|
||||
<option>wiggle</option>
|
||||
<option>tic-tac-toe</option>
|
||||
<option>leaf</option>
|
||||
<option>bubbles</option>
|
||||
<option>squares</option>
|
||||
<option>explorer</option>
|
||||
<option>jupiter</option>
|
||||
<option>sun</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col m-2 w-1/2">
|
||||
<span className="font-medium">Theme</span>
|
||||
|
||||
<select
|
||||
onChange={(e) => this.setState({ theme: e.target.value })}
|
||||
value={this.state.theme}
|
||||
|
||||
className="text-gray-700 text-xl p-2 rounded border">
|
||||
<option>basic</option>
|
||||
<option>modern</option>
|
||||
<option>outline</option>
|
||||
<option>preview</option>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<span className="text-sm mt-4 text-center text-gray-400">Made with 💖 by <a href="https://rutikwankhade.dev"
|
||||
target="_blank" rel="noopener noreferrer" className="underline hover:text-green-500">Rutik Wankhade</a></span>
|
||||
|
||||
|
||||
|
||||
|
||||
{/* <div className="mx-4 my-1">
|
||||
{/* <div className="mx-4 my-1">
|
||||
<h6>Download As</h6>
|
||||
<select onChange={(e) => this.setState({ download: e.target.value })}
|
||||
className="form-control input"
|
||||
@ -238,29 +291,19 @@ class Editor extends React.Component {
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="m-2 items-center justify-center flex flex-col">
|
||||
<RandomTheme onThemeChange={this.getRandomTheme} />
|
||||
{/* <button
|
||||
className="flex items-center mx-auto border"
|
||||
onClick={this.handleReset}>
|
||||
<img src={resetIcon} className="shuffle-btn border bg-white p-2 rounded cursor-pointer"/>
|
||||
</button> */}
|
||||
</div>
|
||||
<div className=" flex m-6 flex-col items-center justify-center ">
|
||||
|
||||
<div className="flex flex-col items-center justify-center ">
|
||||
<div className="flex mb-4 items-center bg-white p-2 mt-2 rounded justify-center w-full">
|
||||
<span className="mx-4 text-md font-semibold">Coverview is live on Product Hunt Today.</span>
|
||||
<a href="https://www.producthunt.com/posts/coverview-2?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-coverview-2" target="_blank" rel="noreferrer"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=343671&theme=light" alt="Coverview - Creating cover images for your blog is now super easy | Product Hunt" className="w-2/3" /></a>
|
||||
<ComponentToImg downloadAs={this.state.download}>
|
||||
<CoverImage {...this.state} />
|
||||
</ComponentToImg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<ComponentToImg downloadAs={this.state.download}>
|
||||
<CoverImage {...this.state} />
|
||||
</ComponentToImg>
|
||||
</div>
|
||||
|
||||
</ImgProvider>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
71
src/components/Faq.js
Normal file
@ -0,0 +1,71 @@
|
||||
import React, { useState } from 'react';
|
||||
import Header from './Header';
|
||||
const Faq = () => {
|
||||
|
||||
const [showMsg, setShowMsg] = useState(false)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
|
||||
<div className=" md:w-10/12 mx-auto md:p-20 p-4">
|
||||
<h1 className="font-bold md:text-4xl text-2xl font-Anek text-center">Frequently asked questions</h1>
|
||||
|
||||
|
||||
<div className="flex flex-wrap justify-center mt-20 font-Inter">
|
||||
|
||||
<div className="md:w-5/12 m-4 ">
|
||||
<p className="text-xl font-bold py-2">What is Coverview?</p>
|
||||
<p className="text-lg text-gray-700">Coverview is a tool to create cover images for your blogs quickly and easily.</p>
|
||||
</div>
|
||||
|
||||
<div className="md:w-5/12 m-4">
|
||||
<p className="text-xl font-bold py-2">Is Coverview free?</p>
|
||||
<p className="text-lg text-gray-700">Yes! Coverview is absolutely free to use.</p>
|
||||
</div>
|
||||
|
||||
<div className="md:w-5/12 m-4">
|
||||
<p className="text-xl font-bold py-2">Can I upload my custom brand logo?</p>
|
||||
<p className="text-lg text-gray-700">Yes.Just search and select <span className="font-semibold">custom</span> in icon section and you can upload your own logo to personalize your cover images.</p>
|
||||
<p className="italic mt-2">See <a href="https://twitter.com/WankhadeRutik/status/1518270774335111168?s=20&t=XMjbJpGAC7anadJ690_DUg" className="text-blue-400" target="_blank" rel="noreferrer">example</a></p>
|
||||
</div>
|
||||
|
||||
<div className="md:w-5/12 m-4">
|
||||
<p className="text-xl font-bold my-2">Can I use coverview for non-technical/personal blogs?</p>
|
||||
<p className="text-lg text-gray-700">Yes! Why not? Even though coverview was built with technical blogs in mind, you can still use it for your personal blogs. Check out the stylish theme for more.</p>
|
||||
</div>
|
||||
|
||||
<div className="md:w-5/12 m-4">
|
||||
<p className="text-xl font-bold my-2">Why use Coverview?</p>
|
||||
<p className="text-lg text-gray-700">Because it's simple, quick and easy to use. Why spend hours designing when you can create cover images in seconds?</p>
|
||||
</div>
|
||||
|
||||
<div className="md:w-5/12 m-4">
|
||||
<p className="text-xl font-bold my-2">Want to support/sponsor the project?</p>
|
||||
<p className="text-lg text-gray-700">If coverview adds value in your life and you wish to support this project, you can <a href="https://github.com/sponsors/rutikwankhade" target="_blank" rel="noreferrer" className="font-semibold hover:underline">sponsor me on Github</a> or <a href="https://www.buymeacoffee.com/rutikwankhade" target="_blank" rel="noreferrer" className="hover:underline text-pink-400 font-semibold">buy me a coffee</a>.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="md:w-1/2 mx-auto text-center mt-20">
|
||||
<button
|
||||
onClick={() => setShowMsg(!showMsg)}
|
||||
className="text-6xl text-center m-2">💡</button>
|
||||
<p className="text-xl font-Anek font-semibold text-gray-800">Want to know a secret? Click me</p>
|
||||
|
||||
</div>
|
||||
|
||||
{
|
||||
showMsg ?
|
||||
<div>
|
||||
<h2 className="md:w-7/12 text-4xl border text-center mx-auto my-10 p-10 rounded-xl shadow-sm font-Nunito">Blog titles with a minimum of 8 words have 21% better click-through</h2>
|
||||
</div> :
|
||||
<div></div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Faq;
|
28
src/components/Header.js
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom'
|
||||
import logo from '../assets/icons/logo.png'
|
||||
const Header = () => {
|
||||
|
||||
const tweetText = encodeURIComponent(`type your thoughts here, Try https://coverview.vercel.app by @WankhadeRutik`)
|
||||
|
||||
return (
|
||||
|
||||
<div className="text-xl md:px-2 flex border-b border-gray-100 p-2">
|
||||
<Link to="/" className="flex items-center">
|
||||
<img src={logo} alt="logo" className="w-8 h-8 mx-4" />
|
||||
<h1 className="font-semibold">Coverview</h1>
|
||||
|
||||
</Link>
|
||||
|
||||
<div className="ml-auto md:mr-4 ">
|
||||
<Link to="/faq" className="text-gray-700 hover:text-gray-800 text-base font-Nunito mx-4"><span className="hidden md:inline-block">How to use</span></Link>
|
||||
<a href="https://www.buymeacoffee.com/rutikwankhade" target="_blank" rel="noreferrer" className="text-base mx-2 font-Nunito">🥤 <span className="hidden md:inline-block">Buy me a coffee</span></a>
|
||||
<a href={`https://twitter.com/intent/tweet?text=${tweetText}`} className="mx-2 bg-blue-400 md:text-sm text-xs rounded-full px-4 font-semibold text-white p-1">Share on Twitter</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
210
src/components/Home.js
Normal file
@ -0,0 +1,210 @@
|
||||
import React from 'react';
|
||||
import logo from '../assets/icons/logo.png'
|
||||
import { Link } from 'react-router-dom';
|
||||
import cover1 from '../assets/images/cover1.webp'
|
||||
import cover2 from '../assets/images/cover2.webp'
|
||||
import cover3 from '../assets/images/cover3.webp'
|
||||
import cover4 from '../assets/images/cover4.webp'
|
||||
|
||||
|
||||
|
||||
import step1 from '../assets/images/step1.png'
|
||||
import step2 from '../assets/images/step2.png'
|
||||
|
||||
import hashnodeLogo from '../assets/images/hashnode-logo.png'
|
||||
import devLogo from '../assets/images/dev-logo.png'
|
||||
|
||||
import WallOfLove from './walloflove';
|
||||
const Home = () => {
|
||||
|
||||
|
||||
return (
|
||||
<div className="bg-gray-50">
|
||||
|
||||
<div className="text-xl flex border-b border-gray-100 p-2 md:w-10/12 mx-auto">
|
||||
<div className="flex items-center">
|
||||
<img src={logo} alt="logo" className="w-8 h-8 mx-2" />
|
||||
<h1 className="font-semibold md:text-xl text-lg font-Inter">Coverview</h1>
|
||||
</div>
|
||||
|
||||
<a href="https://github.com/rutikwankhade/CoverView" target="_blank" rel="noreferrer" className="hover:translate-x-2 duration-300 bg-gray-700 group rounded-xl md:px-4 text-white md:text-sm text-xs ml-auto mr-4 font-Inter font-semibold p-2">
|
||||
<span className="text-sm">⭐ Star on Github</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className=" mx-auto md:px-20 py-6 flex flex-col items-center">
|
||||
<h1 className="md:w-7/12 m-10 text-center md:text-5xl text-3xl font-extrabold text-gray-700 font-Anek">
|
||||
Creating cover images for your blogs is now super easy
|
||||
</h1>
|
||||
<Link to="/editor" className="hover:translate-x-2 duration-300 bg-gray-700 hover:bg-gray-800 group rounded-full px-4 md:px-8 text-white md:text-2xl text-lg mx-auto font-Inter font-semibold md:p-4 p-2">
|
||||
<span className="md:text-2xl text-lg">Open editor →</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div className=" temple flex flex-row items-center justify-center mx-auto md:w-10/12">
|
||||
|
||||
<div className="m-4 transform -translate-y-20 border animate hover:scale-105 hover:-rotate-3 rotate-6 duration-100 bg-white p-2 shadow-sm w-1/5 rounded-lg flex flex-col ">
|
||||
<img src={cover2} className="border border-gray-100 rounded mb-2" alt="cover1" />
|
||||
<p className="animate animate-pulse bg-gray-50 md:h-5 h-2 rounded mb-2"></p>
|
||||
<p className="animate animate-pulse w-8/12 bg-gray-50 md:h-5 h-2 rounded mb-2"></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="m-4 transform hover:scale-105 hover:rotate-3 -rotate-2 duration-300 bg-white p-4 shadow-sm w-1/3 rounded-lg flex flex-col ">
|
||||
<img src={cover1} className="rounded border border-gray-100 mb-2" alt="cover-2" />
|
||||
<p className="animate animate-pulse bg-gray-50 md:h-6 h-3 rounded mb-2"></p>
|
||||
<p className="animate animate-pulse w-8/12 bg-gray-50 md:h-6 h-3 rounded mb-2"></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="m-4 transform -translate-y-20 border animate hover:scale-105 hover:rotate-3 -rotate-6 duration-100 bg-white p-2 shadow-sm w-1/5 rounded-lg flex flex-col ">
|
||||
<img src={cover3} className="rounded border border-gray-100 mb-2" alt="cover3" />
|
||||
<p className="animate animate-pulse bg-gray-50 md:h-5 h-2 rounded mb-2"></p>
|
||||
<p className="animate animate-pulse w-8/12 bg-gray-50 md:odd:h-5 h-2 rounded mb-2"></p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className="md:my-32 my-10 mx-auto">
|
||||
|
||||
<div className="md:w-10/12 mx-auto flex flex-col ">
|
||||
<div className="md:w-9/12 text-center mx-auto ">
|
||||
<h2 className="text-5xl py-4 font-bold font-Anek text-gray-700">Why cover images are more important than you think?</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex md:flex-row flex-col mx-auto justify-center my-10 mx-auto">
|
||||
|
||||
<div className="m-10 p-10 bg-white rounded-xl shadow-xl shadow-gray-100 flex flex-col md:w-4/12 ">
|
||||
<div className=" my-2 bg-purple-300 h-24 w-24 p-4 flex justify-center items-center rounded-full">
|
||||
<svg className="text-white w-20 h-20" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path></svg>
|
||||
</div>
|
||||
<p className="text-2xl md:text-left text-center text-gray-700">Around <span className="font-bold">7 million</span> blog posts are published daily. And with the rise of new-age blogging tools, it will only go up.</p>
|
||||
</div>
|
||||
|
||||
<div className="m-10 p-10 bg-white rounded-xl shadow-xl shadow-gray-100 flex flex-col md:w-4/12 ">
|
||||
<div className=" my-2 bg-green-300 h-24 w-24 p-4 flex justify-center items-center rounded-full">
|
||||
<svg className="text-white w-20 h-20" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path></svg>
|
||||
</div>
|
||||
<p className="text-2xl md:text-left text-center text-gray-700">A good cover image can lead to <span className="font-bold">higher conversion rate</span> than a random stock image.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<h2 className="md:text-5xl text-3xl md:w-1/2 mx-auto mt-32 font-bold font-Anek text-center text-gray-700">With coverview, you can create cover images in <span className="text-indigo-400">seconds</span>.</h2>
|
||||
<div className="md:w-8/12 my-20 flex md:flex-row flex-col mx-auto">
|
||||
|
||||
<div className="md:w-1/3 flex flex-col mx-10">
|
||||
|
||||
<div className="text-center">
|
||||
<div className="text-xl mx-auto w-10 h-10 p-2 font-bold text-white bg-gray-700 rounded-full flex items-center justify-center">1</div>
|
||||
|
||||
<p className="text-2xl my-2 font-semibold font-Inter text-gray-600">Add title and author of your blog post</p>
|
||||
</div>
|
||||
<img src={step1} alt="preview" className="mt-2 rounded-lg shadow-sm" />
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex items-center font-bold text-3xl text-center mx-auto">--------→</div>
|
||||
|
||||
<div className="flex flex-col md:w-1/3 mx-10">
|
||||
|
||||
<div className="text-center">
|
||||
<div className="text-xl mx-auto w-10 h-10 p-2 font-bold text-white bg-gray-700 rounded-full flex items-center justify-center">2</div>
|
||||
|
||||
<p className="text-2xl my-2 font-semibold font-Inter text-gray-600">Customize with colors, fonts, icons and patterns</p>
|
||||
</div>
|
||||
<img src={step2} alt="preview" className="mt-2 rounded-lg shadow-sm" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div className="md:w-8/12 flex md:flex-row flex-col justify-center items-center mx-auto">
|
||||
|
||||
<div className="text-center md:w-1/3 m-4">
|
||||
<div className="text-xl mx-auto w-10 h-10 p-2 font-bold text-white bg-gray-700 rounded-full flex items-center justify-center">3</div>
|
||||
|
||||
<p className="text-2xl my-2 font-semibold font-Inter text-gray-600">Choose from different themes</p>
|
||||
<p className="text-xl">Unsplash integration, custom icon for personal branding and more.</p>
|
||||
</div>
|
||||
|
||||
<div className="flex md:w-8/12 hideout p-6">
|
||||
<div className="flex flex-col w-1/2 ">
|
||||
<img src={cover1} alt="preview" className=" hover:scale-105 duration-300 m-2 rounded-lg shadow-sm" />
|
||||
<img src={cover2} alt="preview" className="hover:scale-105 duration-300 m-2 rounded-lg shadow-sm" />
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex flex-col mt-4 w-1/2">
|
||||
<img src={cover3} alt="preview" className="hover:scale-105 duration-300 m-2 rounded-lg shadow-sm" />
|
||||
<img src={cover4} alt="preview" className="hover:scale-105 duration-300 m-2 rounded-lg shadow-sm" />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div className="md:w-6/12 my-20 mx-auto">
|
||||
|
||||
<div className="text-center m-4">
|
||||
|
||||
<p className="text-2xl my-2 font-semibold font-Inter text-gray-600">Supports platforms like Hashnode or Dev.to</p>
|
||||
</div>
|
||||
<div className="flex mx-auto justify-center">
|
||||
<img src={hashnodeLogo} className="w-20 m-2" alt="hashnode" />
|
||||
<img src={devLogo} className="w-20 m-2" alt="dev" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<WallOfLove />
|
||||
|
||||
<div className="md:w-8/12 mx-auto pt-24 p-4">
|
||||
<h2 className="text-6xl text-center font-Anek font-bold text-gray-700 mx-auto">Simple, quick, and easy to use</h2>
|
||||
<p className="text-2xl text-center py-4 md:w-8/12 mx-auto">So you can focus on writing your blog and never worry about those cover images.</p>
|
||||
<Link to="/editor" >
|
||||
<button className="flex mx-auto my-4 hover:translate-x-2 duration-300 bg-gray-700 rounded-full px-6 text-white text-xl font-Inter font-semibold p-4">It's Free! Try now →</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<footer className="bg-white p-10 flex md:flex-row flex-col font-Inter md:px-20 justify-center items-center">
|
||||
<div className="md:w-1/2 flex flex-col">
|
||||
<span className="text-lg">Made with 💛 by <a href="https://twitter.com/WankhadeRutik" className="font-semibold" target="_blank" rel="noreferrer">Rutik Wankhade</a></span>
|
||||
<span className="text-lg font-Nunito">checkout <a href="https://rutikwankhade.dev" target="_blank" rel="noreferrer" className="text-purple-400 hover:text-pink-400">more cool stuff</a> I built</span>
|
||||
</div>
|
||||
|
||||
<div className="md:text-lg text-sm flex flex-wrap ">
|
||||
<Link to="/faq" className="m-2 hover:font-semibold">📌 How to use</Link>
|
||||
<a href="https://github.com/rutikwankhade/CoverView" target="_blank" rel="noreferrer" className="m-2 hover:font-semibold">⭐ Star on Github</a>
|
||||
<a href="https://www.buymeacoffee.com/rutikwankhade" target="_blank" rel="noreferrer" className="m-2 hover:font-semibold">🥤 Buy me a coffee</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
@ -107,11 +107,11 @@ class RandomTheme extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="shuffle-btn border bg-white p-2 rounded cursor-pointer" onClick={this.changeTheme}>
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" className="bi bi-shuffle" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" d="M0 3.5A.5.5 0 0 1 .5 3H1c2.202 0 3.827 1.24 4.874 2.418.49.552.865 1.102 1.126 1.532.26-.43.636-.98 1.126-1.532C9.173 4.24 10.798 3 13 3v1c-1.798 0-3.173 1.01-4.126 2.082A9.624 9.624 0 0 0 7.556 8a9.624 9.624 0 0 0 1.317 1.918C9.828 10.99 11.204 12 13 12v1c-2.202 0-3.827-1.24-4.874-2.418A10.595 10.595 0 0 1 7 9.05c-.26.43-.636.98-1.126 1.532C4.827 11.76 3.202 13 1 13H.5a.5.5 0 0 1 0-1H1c1.798 0 3.173-1.01 4.126-2.082A9.624 9.624 0 0 0 6.444 8a9.624 9.624 0 0 0-1.317-1.918C4.172 5.01 2.796 4 1 4H.5a.5.5 0 0 1-.5-.5z" />
|
||||
<path d="M13 5.466V1.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384l-2.36 1.966a.25.25 0 0 1-.41-.192zm0 9v-3.932a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384l-2.36 1.966a.25.25 0 0 1-.41-.192z" />
|
||||
</svg>
|
||||
<div className="flex flex-col justify-center">
|
||||
<div className="shuffle-btn w-10 flex justify-center items-center shadow-xl shadow-gray-100 h-10 p-2 bg-indigo-400 rounded-xl cursor-pointer" onClick={this.changeTheme}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" className="text-white w-10 h-10" width="24" height="24" viewBox="0 0 24 24" ><path d="M17 17h-1.559l-9.7-10.673A1 1 0 0 0 5.001 6H2v2h2.559l4.09 4.5-4.09 4.501H2v2h3.001a1 1 0 0 0 .74-.327L10 13.987l4.259 4.686a1 1 0 0 0 .74.327H17v3l5-4-5-4v3z"></path><path d="M15.441 8H17v3l5-3.938L17 3v3h-2.001a1 1 0 0 0-.74.327l-3.368 3.707 1.48 1.346L15.441 8z"></path></svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
179
src/components/Themes/BackgroundTheme.js
Normal file
@ -0,0 +1,179 @@
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import unsplash from "../../utils/unsplashConfig";
|
||||
import { ImgContext } from '../../utils/ImgContext';
|
||||
|
||||
const BackgroundTheme = ({ config }) => {
|
||||
const { title, author, font, icon, customIcon, platform, bgColor } = config;
|
||||
|
||||
// const [image, setImage] = useState({})
|
||||
|
||||
const [imageList, setImageList] = useState([]);
|
||||
const [searchText, setSearchText] = useState('dev');
|
||||
|
||||
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
|
||||
|
||||
const searchImages = () => {
|
||||
|
||||
unsplash.search
|
||||
.getPhotos({
|
||||
query: searchText,
|
||||
page: 1,
|
||||
per_page: 30,
|
||||
// orientation:'portrait'
|
||||
|
||||
|
||||
})
|
||||
.then(response => {
|
||||
// console.log(response.response.results);
|
||||
setImageList(response.response.results)
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
unsplash.search
|
||||
.getPhotos({
|
||||
query: 'setup',
|
||||
page: 1,
|
||||
per_page: 30
|
||||
|
||||
})
|
||||
.then(response => {
|
||||
// console.log(response.response.results);
|
||||
setImageList(response.response.results)
|
||||
});
|
||||
}, [])
|
||||
|
||||
const selectImage = (image) => {
|
||||
setUnsplashImage({
|
||||
url: image.urls.regular,
|
||||
name: image.user.name,
|
||||
avatar: image.user.profile_image.small,
|
||||
profile: `${image.user.links.html}?utm_source=https://coverview.vercel.app&utm_medium=referral`,
|
||||
downloadLink: image.links.download_location
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
searchImages(searchText);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className=" bg-white rounded">
|
||||
|
||||
|
||||
<div className={` overflow-y-hidden flex flex-col rounded ${platform}`}
|
||||
style={{ backgroundColor: bgColor }}
|
||||
>
|
||||
|
||||
<div className="flex flex-row items-center bg-white justify-center ">
|
||||
|
||||
|
||||
<div className="w-full">
|
||||
|
||||
|
||||
{unsplashImage ?
|
||||
<div className='relative flex group'>
|
||||
|
||||
<div className="h-max w-full ">
|
||||
<img src={unsplashImage.url && unsplashImage.url} className=" object-cover h-full w-full " alt="preview" />
|
||||
</div>
|
||||
|
||||
|
||||
<div className=" backdrop-blur-sm h-full bg-gray-800/60 absolute top-0 right-0 left-0 ">
|
||||
<button
|
||||
onClick={() => setUnsplashImage('')}
|
||||
className="absolute top-2 right-2 cursor-pointer">
|
||||
<svg className="group-hover:inline-block hidden w-8 h-8 text-gray-800 bg-white p-2 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
|
||||
|
||||
</button>
|
||||
|
||||
<div className={`${font} px-10 pt-32 text-left rounded-xl h-full p-4 flex flex-col`}>
|
||||
<h1 className=" md:text-5xl text-center text-2xl font-bold text-white">{title}</h1>
|
||||
<div className="flex flex-col items-center py-10 ">
|
||||
|
||||
<h2 className="text-xl font-semibold text-left text-white ">{author}</h2>
|
||||
{
|
||||
customIcon ?
|
||||
<div className=" ">
|
||||
<img src={customIcon} alt="img" className="w-12 h-12 m-2 rounded-full bg-white border-2 border-white" />
|
||||
</div>
|
||||
:
|
||||
<div className="mr-2 items-center justify-center flex">
|
||||
<i className={`devicon-${icon.value}-plain text-white dev-icon text-3xl`}></i>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-4 right-4 opacity-80">
|
||||
<div className=" group-hover:flex hidden items-center">
|
||||
<span className="text-sm text-white mx-2">Photo by</span>
|
||||
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
|
||||
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
|
||||
|
||||
<span className="pr-2">{unsplashImage.name}</span>
|
||||
</a>
|
||||
|
||||
<a href="https://unsplash.com/?utm_source=https://coverview.vercel.app&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="flex flex-col p-2 bg-white items-center justify-center">
|
||||
|
||||
<div className="flex items-center w-full px-6 ">
|
||||
<div className="text-lg font-semibold text-gray-700">Click on any image to select</div>
|
||||
<form onSubmit={(e) => handleSearchSubmit(e)} className=" ml-auto mr-2 w-1/2 flex bg-gray-50 rounded-full border mb-2">
|
||||
<input type="text"
|
||||
value={searchText}
|
||||
placeholder="Search image"
|
||||
className="focus:outline-none w-full text-lg bg-gray-50 p-1 px-4 rounded-full border border-gray-50"
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
/>
|
||||
|
||||
<button type="submit" onClick={() => searchImages(searchText)}>
|
||||
<svg className="w-9 h-9 ml-auto mr-1 p-2 bg-gray-700 hover:bg-gray-800 text-white rounded-full" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div className="overflow-y-scroll overflow-x-hidden h-96 justify-center flex flex-wrap">
|
||||
{
|
||||
imageList.map(image => {
|
||||
return <img src={image.urls.regular}
|
||||
key={image.id}
|
||||
alt={image.alt_description}
|
||||
className="rounded m-2 cursor-pointer w-5/12 object-cover h-40"
|
||||
onClick={() => selectImage(image)
|
||||
}
|
||||
/>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BackgroundTheme;
|
@ -2,11 +2,11 @@ import React from 'react';
|
||||
|
||||
|
||||
const BasicTheme = ({ config }) => {
|
||||
const { title, bgColor, pattern, author, icon, font, customIcon } = config;
|
||||
const { title, bgColor, pattern, author, icon, font, customIcon,platform } = config;
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-white border">
|
||||
<div className={`cover flex text-gray-800 items-center ${pattern} `}
|
||||
<div className="p-4 bg-white ">
|
||||
<div className={`overflow-y-hidden flex text-gray-800 items-center ${pattern} ${platform} `}
|
||||
style={{ backgroundColor: bgColor }}
|
||||
>
|
||||
|
||||
@ -14,19 +14,19 @@ const BasicTheme = ({ config }) => {
|
||||
<div className={`${font} bg-white md:w-10/12 m-auto flex flex-col pt-12 rounded-xl`}>
|
||||
<div className="px-12">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-5xl font-bold text-center">{title}</h1>
|
||||
<h1 className="text-3xl md:text-5xl text-gray-800 font-bold text-center">{title}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className=" flex mx-4 mt-10 p-4 rounded-xl items-center bg-white">
|
||||
<div className=" flex mx-4 p-4 rounded-xl items-center bg-white">
|
||||
{
|
||||
customIcon ?
|
||||
<div className="w-12 h-12 ">
|
||||
<img src={customIcon} alt="img" className="rounded-full bg-white p-1 border-white" />
|
||||
</div>
|
||||
:
|
||||
<div className=" rounded-full p-6 w-32 h-32 bg-white mx-auto items-center justify-center flex">
|
||||
<i className={`devicon-${icon.value}-plain p-4 dev-icon text-7xl`}></i>
|
||||
<div className="mr-auto ml-2 items-center justify-center flex">
|
||||
<i className={`devicon-${icon.value}-plain p-4 dev-icon text-5xl`}></i>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
67
src/components/Themes/MobileMockupTheme.js
Normal file
@ -0,0 +1,67 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const MobileMockupTheme = ({ config }) => {
|
||||
const { bgColor, platform, title,font } = config;
|
||||
|
||||
const [image, setImage] = useState()
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-white">
|
||||
|
||||
|
||||
<div className={`overflow-y-hidden flex flex-row px-10 items-center justify-center rounded px-8 pt-4 ${platform}`}
|
||||
style={{ backgroundColor: bgColor }}
|
||||
>
|
||||
|
||||
|
||||
<h1 className={`${font} text-2xl w-1/2 md:text-4xl px-4 text-white font-bold text-left`}>{title}</h1>
|
||||
|
||||
<div className="w-5/12 mx-auto m-4 mt-10 group mx-auto h-full shadow-lg flex flex-col bg-white border-t-8 border-x-8 border-gray-800 rounded-t-3xl border-white">
|
||||
<div className="bg-gray-800 h-8 w-full p-2 pb-3 flex items-center rounded-t">
|
||||
|
||||
<div className="flex mx-auto items-center">
|
||||
|
||||
<div className="bg-white h-3 w-3 rounded-full mx-1"></div>
|
||||
<div className="bg-white h-2 w-20 rounded-full mx-1"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{image ?
|
||||
<div className="group relative">
|
||||
<img src={image && image} className="object-cover rounded -translate-y-1 h-full" alt="preview" />
|
||||
<button
|
||||
onClick={() => setImage('')}
|
||||
className="ml-auto mr-4 cursor-pointer">
|
||||
<svg className="group-hover:inline-block absolute top-4 right-2 bg-gray-500 hidden w-8 h-8 p-2 text-white rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
|
||||
|
||||
</button>
|
||||
</div>
|
||||
:
|
||||
<div className="flex flex-col px-4 rounded-xl py-20 bg-white items-center justify-center">
|
||||
<input type="file"
|
||||
className="text-sm flex flex-col cursor-pointer mb-2 bg-white rounded border"
|
||||
onChange={(e) => setImage(URL.createObjectURL(e.target.files[0]))}
|
||||
/>
|
||||
<span className=" text-center italic">click to upload a screenshot</span>
|
||||
</div>
|
||||
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MobileMockupTheme;
|
@ -3,19 +3,19 @@ import React from 'react';
|
||||
|
||||
const ModernTheme = ({ config }) => {
|
||||
|
||||
const { title, bgColor, pattern, author, icon, font, customIcon } = config;
|
||||
const { title, bgColor, pattern, author, icon, font, customIcon, platform } = config;
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-white border">
|
||||
<div className=" cover flex items-center">
|
||||
<div className={` h-full rounded-xl p-4 text-gray-800 flex items-center ${pattern} `}
|
||||
<div className="w-full p-4 bg-white ">
|
||||
<div className=" overflow-y-hidden w-full flex items-center">
|
||||
<div className={` h-full w-full rounded-xl p-4 text-gray-800 flex items-center ${pattern} ${platform}`}
|
||||
style={{ backgroundColor: bgColor }}
|
||||
>
|
||||
|
||||
{
|
||||
customIcon ?
|
||||
<div className="w-28 h-28 mx-auto items-center justify-center flex">
|
||||
<img src={customIcon} alt="img" className="rounded-full bg-white p-1 border-white" />
|
||||
<div className=" mx-auto items-center justify-center flex">
|
||||
<img src={customIcon} alt="img" className="w-28 h-28 rounded-full bg-white border-4 border-white" />
|
||||
</div>
|
||||
:
|
||||
<div className=" rounded-full p-6 w-32 h-32 bg-white mx-auto items-center justify-center flex">
|
||||
@ -26,7 +26,7 @@ const ModernTheme = ({ config }) => {
|
||||
|
||||
<div className="h-full w-2/3">
|
||||
<div className={`${font} bg-white px-12 justify-center text-left rounded-xl h-full p-4 flex flex-col`}>
|
||||
<h1 className="text-3xl md:text-5xl font-bold ">{title}</h1>
|
||||
<h1 className="text-3xl md:text-5xl font-bold text-gray-800">{title}</h1>
|
||||
<h2 className="text-xl mt-10 font-semibold text-left ">{author}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,41 +1,38 @@
|
||||
import React from 'react';
|
||||
const OutlineTheme = ({ config }) => {
|
||||
const { title, bgColor, pattern, author, icon, font, customIcon } = config;
|
||||
const { title, bgColor, author, icon, font, customIcon, platform } = config;
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-white border">
|
||||
<div className="p-4 bg-white ">
|
||||
|
||||
|
||||
<div className={`cover rounded flex flex-col text-gray-800 items-center border-4 border-gray-800 ${pattern} `}
|
||||
<div className={`overflow-y-hidden rounded flex flex-col text-gray-800 px-10 ${platform} `}
|
||||
style={{ backgroundColor: bgColor }}
|
||||
>
|
||||
|
||||
|
||||
<div className={`${font} bg-white rounded md:w-10/12 border-4 border-gray-800 m-auto flex flex-col py-12 px-6 `}>
|
||||
<div className="px-12">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-5xl font-bold text-center">{title}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div className={`${font} w-full border-gray-800 border-t-4 flex mt-10 p-2 px-6 items-center bg-white`}>
|
||||
<div className={`${font} rounded-2xl py-6 flex flex-col `}>
|
||||
{
|
||||
customIcon ?
|
||||
<div className="w-12 h-12 ">
|
||||
<img src={customIcon} alt="img" className="rounded-full bg-white p-1 border-white" />
|
||||
<div className=" m-6">
|
||||
<img src={customIcon} alt="img" className="rounded-full object-cover w-24 h-24 bg-white p-1 border-white" />
|
||||
</div>
|
||||
:
|
||||
<div className=" rounded-full p-6 w-32 h-32 bg-white mx-auto items-center justify-center flex">
|
||||
<i className={`devicon-${icon.value}-plain p-4 dev-icon text-7xl`}></i>
|
||||
<div className=" mr-auto ml-2 items-center justify-center flex">
|
||||
<i className={`devicon-${icon.value}-plain text-white p-4 dev-icon text-8xl`}></i>
|
||||
</div>
|
||||
}
|
||||
<h2 className="text-xl ml-auto mr-2 font-semibold">{author}</h2>
|
||||
<h1 className="text-3xl p-4 text-white md:text-5xl font-bold ">{title}</h1>
|
||||
|
||||
<div className={`${font} w-full h-16 flex mt-auto mb-0 p-2 px-6 items-center `}>
|
||||
|
||||
<h2 className="text-2xl text-white font-semibold">{author}</h2>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -1,28 +1,40 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const PreviewTheme = ({ config }) => {
|
||||
const {bgColor } = config;
|
||||
const { bgColor, platform, title, font } = config;
|
||||
|
||||
const [image, setImage] = useState()
|
||||
|
||||
return (
|
||||
<div className="p-4 bg-white border">
|
||||
<div className="p-4 bg-white">
|
||||
|
||||
|
||||
<div className={`cover flex flex-col rounded px-4 pt-4 `}
|
||||
<div className={`overflow-y-hidden flex flex-col rounded px-4 pt-4 ${platform}`}
|
||||
style={{ backgroundColor: bgColor }}
|
||||
>
|
||||
|
||||
<div className="w-10/12 mx-auto mt-auto mb-0 border-4 rounded-t-xl border-white">
|
||||
<div className="bg-gray-800 w-full p-3 flex rounded-t-xl">
|
||||
<div className="bg-red-400 h-4 w-4 rounded-full mx-2"></div>
|
||||
<div className="bg-yellow-400 h-4 w-4 rounded-full mx-2"></div>
|
||||
<div className="bg-green-400 h-4 w-4 rounded-full mx-2"></div>
|
||||
|
||||
<h1 className={`${font} text-2xl md:text-3xl p-10 text-white font-bold text-center`}>{title}</h1>
|
||||
|
||||
<div className="w-10/12 group mx-auto mt-auto mb-0 shadow-lg flex flex-col bg-white rounded-t-xl border-white">
|
||||
<div className="bg-gray-800 h-8 w-full p-2 flex items-center rounded-t-xl">
|
||||
<div className="bg-red-400 h-3 w-3 rounded-full mx-1"></div>
|
||||
<div className="bg-yellow-400 h-3 w-3 rounded-full mx-1"></div>
|
||||
<div className="bg-green-400 h-3 w-3 rounded-full mx-1"></div>
|
||||
<button
|
||||
onClick={() => setImage('')}
|
||||
className="ml-auto mr-4 cursor-pointer">
|
||||
<svg className="group-hover:inline-block hidden w-4 h-4 text-white rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
|
||||
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{image ?
|
||||
<div>
|
||||
<div className="">
|
||||
<img src={image && image} className="object-cover " alt="preview" />
|
||||
|
||||
</div>
|
||||
:
|
||||
<div className="flex flex-col p-20 py-28 bg-white items-center justify-center">
|
||||
@ -30,7 +42,7 @@ const PreviewTheme = ({ config }) => {
|
||||
className="text-xl cursor-pointer mb-2 bg-white rounded border"
|
||||
onChange={(e) => setImage(URL.createObjectURL(e.target.files[0]))}
|
||||
/>
|
||||
<span className=" text-center italic">Upload a screenshot of your app</span>
|
||||
<span className=" text-center italic">click to upload a screenshot</span>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
174
src/components/Themes/StylishTheme.js
Normal file
@ -0,0 +1,174 @@
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import unsplash from "../../utils/unsplashConfig";
|
||||
import { ImgContext } from '../../utils/ImgContext';
|
||||
|
||||
const StylishTheme = ({ config }) => {
|
||||
const { title, author, font, icon, customIcon, platform,bgColor } = config;
|
||||
|
||||
// const [image, setImage] = useState({})
|
||||
|
||||
const [imageList, setImageList] = useState([]);
|
||||
const [searchText, setSearchText] = useState('dev');
|
||||
|
||||
const { unsplashImage, setUnsplashImage } = useContext(ImgContext);
|
||||
|
||||
const searchImages = () => {
|
||||
|
||||
unsplash.search
|
||||
.getPhotos({
|
||||
query: searchText,
|
||||
page: 1,
|
||||
per_page: 30,
|
||||
// orientation:'portrait'
|
||||
|
||||
|
||||
})
|
||||
.then(response => {
|
||||
// console.log(response.response.results);
|
||||
setImageList(response.response.results)
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
unsplash.search
|
||||
.getPhotos({
|
||||
query: 'setup',
|
||||
page: 1,
|
||||
per_page: 25
|
||||
|
||||
})
|
||||
.then(response => {
|
||||
// console.log(response.response.results);
|
||||
setImageList(response.response.results)
|
||||
});
|
||||
}, [])
|
||||
|
||||
const selectImage = (image) => {
|
||||
setUnsplashImage({
|
||||
url: image.urls.regular,
|
||||
name: image.user.name,
|
||||
avatar: image.user.profile_image.small,
|
||||
profile: `${image.user.links.html}?utm_source=https://coverview.vercel.app&utm_medium=referral`,
|
||||
downloadLink: image.links.download_location
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
searchImages(searchText);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className=" bg-white rounded">
|
||||
|
||||
|
||||
<div className={` overflow-y-hidden flex flex-col rounded ${platform}`}
|
||||
style={{ backgroundColor: bgColor }}
|
||||
>
|
||||
|
||||
<div className="flex flex-row items-center bg-white justify-center m-4 ">
|
||||
|
||||
<div className="h-full w-1/2 bg-white rounded-l-xl">
|
||||
<div className={`${font} px-12 justify-center text-left rounded-xl h-full p-4 flex flex-col`}>
|
||||
<h1 className=" text-4xl font-bold text-gray-800">{title}</h1>
|
||||
<div className="flex items-center mt-10 text-left">
|
||||
{
|
||||
customIcon ?
|
||||
<div className=" ">
|
||||
<img src={customIcon} alt="img" className="w-12 h-12 mr-2 rounded-full bg-white border border-white" />
|
||||
</div>
|
||||
:
|
||||
<div className="mr-2 items-center justify-center flex">
|
||||
<i className={`devicon-${icon.value}-plain dev-icon text-3xl`}></i>
|
||||
</div>
|
||||
}
|
||||
<h2 className="text-xl font-semibold text-left ">{author}</h2>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-1/2">
|
||||
|
||||
|
||||
{unsplashImage ?
|
||||
<div className='relative flex group'>
|
||||
|
||||
<div className="h-96 w-96 ">
|
||||
|
||||
|
||||
<img src={unsplashImage.url && unsplashImage.url} className=" object-cover h-96 w-96 " alt="preview" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setUnsplashImage('')}
|
||||
className="absolute top-4 right-2 cursor-pointer">
|
||||
<svg className="group-hover:inline-block hidden w-6 h-6 text-gray-800 bg-white p-1 rounded-full z-10" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
|
||||
|
||||
</button>
|
||||
|
||||
<div className="absolute bottom-4 right-4 opacity-80">
|
||||
<div className=" group-hover:flex hidden items-center">
|
||||
<span className="text-sm text-white mx-2">Photo by</span>
|
||||
<a href={unsplashImage.profile} target="_blank" rel="noreferrer" className="cursor-pointer flex items-center bg-gray-300 rounded-full text-sm">
|
||||
<img src={unsplashImage.avatar && unsplashImage.avatar} alt={unsplashImage.name} className="h-6 w-6 rounded-full mr-2" />
|
||||
|
||||
<span className="pr-2">{unsplashImage.name}</span>
|
||||
</a>
|
||||
|
||||
<a href="https://unsplash.com/?utm_source=https://coverview.vercel.app&utm_medium=referral" className="text-sm text-white mx-2">Unsplash</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="flex flex-col p-2 bg-white items-center justify-center">
|
||||
|
||||
<form onSubmit={(e) => handleSearchSubmit(e)} className="flex bg-gray-50 rounded-full border mb-2">
|
||||
<input type="text"
|
||||
value={searchText}
|
||||
placeholder="Search image"
|
||||
className="focus:outline-none w-max text-lg bg-gray-50 p-1 px-4 rounded-full border border-gray-50"
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
/>
|
||||
|
||||
<button type="submit" onClick={() => searchImages(searchText)}>
|
||||
<svg className="w-9 h-9 p-2 bg-gray-700 hover:bg-gray-800 text-white rounded-full" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
||||
<div className="overflow-y-scroll overflow-x-hidden h-80">
|
||||
{
|
||||
imageList.map(image => {
|
||||
return <img src={image.urls.regular}
|
||||
key={image.id}
|
||||
alt={image.alt_description}
|
||||
className="rounded m-2 cursor-pointer"
|
||||
onClick={() => selectImage(image)
|
||||
}
|
||||
/>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default StylishTheme;
|
40
src/components/walloflove.js
Normal file
@ -0,0 +1,40 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
const WallOfLove = () => {
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
let script = document.createElement('script');
|
||||
script.setAttribute('type', 'text/javascript');
|
||||
script.setAttribute('src', 'https://widget.senja.io/js/iframeResizer.min.js');
|
||||
|
||||
// window.iFrameResize(
|
||||
// { log: false, checkOrigin: false },
|
||||
// '#senja-frame-902012ea');
|
||||
|
||||
let frame = document.getElementById('senja-frame-902012ea');
|
||||
frame.setAttribute('src', "https://widget.senja.io/widget/902012ea-9b49-433a-96df-5cb43fd9a648");
|
||||
document.body.appendChild(script);
|
||||
|
||||
})
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<iframe id="senja-frame-902012ea"
|
||||
title="wall of love"
|
||||
src=""
|
||||
data-src="https://widget.senja.io/widget/902012ea-9b49-433a-96df-5cb43fd9a648"
|
||||
frameBorder="0"
|
||||
scrolling="no"
|
||||
width="100%"
|
||||
height="100%"
|
||||
className="w-9/12 h-screen mx-auto"
|
||||
>
|
||||
</iframe>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default WallOfLove;
|
@ -1,3 +1,38 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities;
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap?crossorigin=anonymous');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap');
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Anek+Latin:wght@400;500;600;700&display=swap?crossorigin=anonymous');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@600;700;800&display=swap');
|
||||
|
||||
|
||||
.h-100{
|
||||
height:36rem;
|
||||
}
|
||||
|
||||
.h-99{
|
||||
height:35rem;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
/* width: 8px; */
|
||||
display: none;
|
||||
}
|
||||
|
||||
Track
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #ccccff;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #b3b3ff;
|
||||
}
|
14
src/utils/ImgContext.js
Normal file
@ -0,0 +1,14 @@
|
||||
import React, { createContext, useState } from "react";
|
||||
const ImgContext = createContext();
|
||||
|
||||
const ImgProvider = ({ children }) => {
|
||||
const [unsplashImage, setUnsplashImage] = useState();
|
||||
|
||||
return (
|
||||
<ImgContext.Provider value={{ unsplashImage, setUnsplashImage }}>
|
||||
{children}
|
||||
</ImgContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export {ImgProvider, ImgContext}
|
8
src/utils/unsplashConfig.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { createApi } from 'unsplash-js';
|
||||
|
||||
const key= process.env.REACT_APP_API_ACCESS_KEY
|
||||
const unsplash = createApi({
|
||||
accessKey: key
|
||||
});
|
||||
|
||||
export default unsplash;
|
@ -1,9 +1,20 @@
|
||||
module.exports = {
|
||||
content: [
|
||||
content: [
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
Inter: ['Inter', 'sans-serif'],
|
||||
Poppins: ['Poppins', 'sans-serif'],
|
||||
Anek: ['Anek Latin', 'sans-serif'],
|
||||
Nunito: ['Nunito', 'sans-serif']
|
||||
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
|
||||
}
|
||||
|