├── .eslintrc.json
├── .gitignore
├── LICENSE.md
├── README.md
├── components
├── Layout.js
├── ReusableStyles.js
├── Seo.js
├── WebLinks.js
└── icons
│ └── index.js
├── data
├── BioData.js
└── LinksData.js
├── next-seo.config.js
├── next.config.js
├── package.json
├── pages
├── _app.js
├── _document.js
├── api
│ └── hello.js
└── index.js
├── public
├── 3dicons.png
├── avatar.png
├── behance.svg
├── bg.png
├── bmc.png
├── designletter.png
├── doc.png
├── dribbble.svg
├── facebook.svg
├── favicon.ico
├── figma.svg
├── foundation.svg
├── g-bg.svg
├── github-fill.svg
├── github.svg
├── gumroad.png
├── hive.svg
├── illlustrations.png
├── insta.svg
├── ios.svg
├── linkedin.svg
├── mastodon.svg
├── medium.svg
├── moon.svg
├── new-up.svg
├── newproduct.png
├── noflash.js
├── opensea.svg
├── pinterest.svg
├── post.svg
├── preview.jpg
├── product-hunt.svg
├── rarible.svg
├── realvjy-gradient.svg
├── realvjy.svg
├── showtime.svg
├── tiktok.svg
├── title.svg
├── twitter.svg
├── use.png
├── vercel.svg
├── vijay-verma.svg
├── vjy.png
├── web.svg
└── youtube.svg
├── styles
├── GlobalStyle.js
├── global.css
└── theme.config.js
└── yarn.lock
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 |
21 | # debug
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | # local env files
27 | .env.local
28 | .env.development.local
29 | .env.test.local
30 | .env.production.local
31 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 vijay verma (realvjy)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nxt Lnk
2 |
3 | **Custom bio links for creatives who love coding. Made this first to use for my own weblinks vjy.me/lnk**
4 |
5 | A perfect custom alternative for linktree, bio and other shortner platform. Check live version here [nxtlnk.xyz](https://nxtlnk.xyz)
6 |
7 | Pull requests are always welcome. In case you want inspiration or new features on what to add, check out the issues for feature requests.
8 |
9 | Coffee fuels coding ☕️
10 |
11 |
12 |
13 | **Table of Contents**
14 |
15 |
16 | - [Usage](#usage)
17 | - [Quick Start](#quick-start)
18 | - [Manual Setup](#manual-setup)
19 | - [Getting Started](#getting-started)
20 | - [Images](#images)
21 | - [Update Bio](#update-bio)
22 | - [Add/Update](#update-bio)
23 | - [Enable/Disable](#update-bio)
24 | - [Featured Banner](#update-bio)
25 | - [Update Links](#update-links)
26 | - [Enable/Disable](#update-links)
27 | - [Add/Update](#update-links)
28 | - [Frontend](#frontend)
29 | - [SEO](#seo)
30 | - [Google Analytics](#google-analytics)
31 | - [Custom Domain](#custom-domain)
32 | - [Favicon](#favicon)
33 | - [Contributors](#contributors)
34 |
35 |
36 | ## Usage
37 | `nxt-lnk` template used to create your custom bio link and self-host on Vercel or Netlify using your own domain. Need little understanding of code :) ☕
38 |
39 | Usually, you don't need to worry a lot about coding if you're just updating information in `BioData.js` and `LinkData.js`. To deep dive know more [Next.js](https://nextjs.org/docs) and [React](https://reactjs.org/docs/getting-started.html) official documentaion.
40 |
41 | For customization used [styled components](https://styled-components.com/). If you want to customize styling you can [learn more here](https://styled-components.com/docs).
42 |
43 | **Template auto support dark-mode depending on system cofig.**
44 |
45 | ## Quick Start
46 | [](https://vercel.com/import/git?s=https://github.com/realvjy/nxt-lnk) [](https://app.netlify.com/start/deploy?repository=https://github.com/realvjy/nxt-lnk)
47 |
48 |
49 | ## Manual Setup
50 | Run the following command to create a new project with this template:
51 | ```bash
52 | yarn create next-app your-app-name -e https://github.com/realvjy/nxt-lnk
53 | # or
54 | npx create-next-app your-app-name -e https://github.com/realvjy/nxt-lnk
55 | ```
56 |
57 | ## Getting Started
58 |
59 | Use any editor to work on editing. I use [vscode](https://code.visualstudio.com/)
60 |
61 | First, run the development server:
62 | ```bash
63 | npm run dev
64 | # or
65 | yarn dev
66 | ```
67 |
68 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
69 |
70 | **Important files to edit or update info**
71 | `data/BioData.js` All basic info update here
72 | `data/LinksData.js` Contain all the links
73 | `Components/WebLinks.js` UI and stylesheet
74 | `Components/icons/index.js` Contain all SVG icon compo
75 |
76 | You can start editing the page by modifying `data/BioData.js` and `data/LinksData.js`. The page auto-updates as you edit the file.
77 |
78 |
79 |
80 | ## Images
81 | All images stored inside `public` folder of the project.
82 |
83 | ## Update Bio
84 | **Example from** `BioData.js` :
85 | ```jsx
86 | const bioData = [
87 | {
88 | name: 'vijay verma',
89 | username: '@realvjy',
90 | url: 'https://vjy.me',
91 | titleImg: true,
92 | avatar: '/avatar.png',
93 | nftAvatar: true,
94 | description: 'A short description/bio about you goes here',
95 | subdesc: 'This is secondary description. If you do not need, you can remove it',
96 | newProductUrl: 'https://vjy.me/lnk',
97 | newProduct: true,
98 | },
99 | ];
100 |
101 | export default bioData;
102 | ```
103 | **Avatar**
104 | Just replace `avatar.png`. 200x200px will be good.
105 |
106 | **Hex/NFT avatar view**
107 | `nftAvatar: true` enable hex shape on avatar image.
108 | `nftAvatar: false` made it in oval shape.
109 |
110 | **Title**
111 | By default `titleImg: true` and it look for `title.svg`. Replace svg with logo **logo**. Make sure to use `title.svg ` name.
112 |
113 | **Featured banner**
114 | `newProductUrl` and `newProduct` used for getting featured banner. You can replace the image `newproduct.png` with any design you like.
115 |
116 | `newProduct: true` show banner. Default is `true` make it false to hide.
117 |
118 |
119 | ## Update Links
120 | **Example from** `LinksData.js` :
121 | ```jsx
122 | const webLinks = [
123 | // All social profile
124 | {
125 | title: 'Twitter',
126 | url: 'https://twitter.com/realvjy',
127 | type: 'social',
128 | icon: '/twitter.svg',
129 | on: true
130 | },
131 | ...
132 | ...
133 |
134 | {
135 | title: 'Instagram',
136 | url: 'https://instagram.com/realvjy',
137 | type: 'social',
138 | icon: '/insta.svg',
139 | on: true
140 | }
141 | ];
142 | export default webLinks;
143 | ```
144 | **Enable/Disable Social Media**
145 | Find `type: social` and change `on:true|false`
146 |
147 | | Title | on (default) |
148 | | --------- | -------- |
149 | | `Twitter` | `true` |
150 | | `Instagram` | `true` |
151 | | `Dribbble` | `false` |
152 | | `Medium` | `false` |
153 | | `Github` | `true` |
154 | | `Youtube` | `false` |
155 | | `Behance` | `true` |
156 | | `Figma` | `true` |
157 | | `Linkedin` | `false` |
158 | | `Mastodon` | `false` |
159 | | `Hive Social` | `false` |
160 | | `Post.news` | `false` |
161 |
162 | Setting `on: true` show the social icon.
163 | The social media icons are arranged in a single row at the top of the page below description. If you want to use as list, chagne type to `type: 'other'`
164 |
165 | **Add new Social Media link**
166 | create a new block by copying this
167 | ```jsx
168 | {
169 | title: 'Social Name',
170 | url: 'https://link.com/whateverurl',
171 | type: 'social',
172 | icon: '/newiconname.svg',
173 | on: true
174 | }
175 | ```
176 | Update all info and make sure to add a `newiconname.svg` file in [public](#images) folder.
177 | Then you have to add new section to frontend `components/WebLinks.js`
178 |
179 | ## Frontend
180 | All frontend customization done inside `components/WebLinks.js`. If you wante to update and add new section just look this file and update according to your need.
181 |
182 | **Update section**
183 |
184 | Look for Section codes. Like if you want to change `install` type to `featured` Update the `type: 'featured'` in `LinkData.js` then update all `install` related code in `WebLinks.js` to `featured`
185 |
186 | ```js
187 | // Collect all links filter by type - social, project, nft and other etc=
188 | // get data for install section
189 | const install = allLinks.filter((el) => {
190 | return el.type === "install" && el.on
191 | });
192 |
193 | ...
194 | ...
195 |
196 | {/* Featured Section */ }
197 |
198 |
{install[0].type}
199 | {
200 | install.map((i) => {
201 | return (
202 |
203 |
204 | {i.title}
205 |
206 |
207 | )
208 | })
209 | }
210 |
211 | {/* End Featured Section */ }
212 | ```
213 | **Add New section**
214 |
215 | Add new section with specific `type` in `Linkdata.js`. Then copy `LinkSection` Code to create new section in `WebLinks.js` file. Make sure to create get data of that section as well.
216 |
217 | ## SEO
218 | Already added `next-seo`. All you have to do is `update next-seo.config.js` file. Make sure to add direct link of `preview.jpg`file, like - `https://vjy.me/preview.jpg`.
219 |
220 | ## Google Analytics
221 | In Vercel, you can set this by going to your project, then Settings and finally [Environments Variables](https://vercel.com/docs/concepts/projects/environment-variables). To get GA 4 code `G-ZXX0000XXX` follow [these steps ](https://support.google.com/analytics/answer/9304153?hl=en)
222 |
223 |
224 |
225 |
226 | ## Custom Domain
227 | By default vercel give you a subdomain with your project name like - [nxtlnk.vercel.app](https:nxtlnk.vercel.app). But you can add own domain.
228 |
229 | Vercel/Netlify give you option to add any domain to the deployed project like [vjy.me/lnk](https://vjy.me/lnk) or [nxtlnk.xyz](https://nxtlnk.xyz). All you have to do is follow official [Vercel documentaion](https://vercel.com/docs/concepts/projects/domains/add-a-domain) or [Netlify Documentaion](https://www.netlify.com/blog/2021/12/20/how-to-add-custom-domains-to-netlify-sites/)
230 |
231 | ## Favicon
232 | Create a `favicon.ico` file and place inside `public` folder. I use [favicon.io](https://favicon.io/favicon-converter/)
233 |
234 | ## Contributors
235 | Created by [realvjy](https://twitter.com/realvjy). You are always welcome to share your feedback on twitter or any social media platform.
236 |
237 | If you want to contribute. Just create a pull request.
238 |
--------------------------------------------------------------------------------
/components/Layout.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 | import ReactDOM from 'react-dom';
3 |
4 |
5 |
6 | export default function Layout({ children }) {
7 | return (
8 |
9 | {children}
10 |
11 | )
12 | }
13 |
14 | const Main = styled.main`
15 | min-height: 100vh;
16 | background: url('/bg.png') no-repeat;
17 | background-size: 100%;
18 | background-position: -50vh 10%;
19 | background-attachment: fixed;
20 | @media screen and (max-width: ${({ theme }) => theme.deviceSize.tablet}) {
21 | background-size: 250%;
22 | background-position: -50vh 30vh;
23 | }
24 | `;
25 |
--------------------------------------------------------------------------------
/components/ReusableStyles.js:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import styled from "styled-components";
3 |
4 | export const Container = styled.div`
5 | position: relative;
6 | align-items: center;
7 | justify-content: center;
8 | width: 650px;
9 | margin: 0 auto;
10 | @media screen and (max-width: ${({ theme }) => theme.deviceSize.tablet}) {
11 | width: 100%;
12 | }
13 | `;
14 |
15 | export const Wrapper = styled.div`
16 | display: flex;
17 | flex-direction: column;
18 | `;
19 |
20 |
21 | export const Button = styled.button`
22 | `
23 |
24 | export const LinkButton = styled.a`
25 | display: flex;
26 | align-items: center;
27 | color: var(--white);
28 | text-decoration: none;
29 | color: inherit;
30 | cursor: pointer;
31 | outline: none;
32 | line-height: 20px;
33 | p{
34 | line-height: 24px;
35 | font-size: 20px;
36 | font-weight: 700;
37 | text-transform: uppercase;
38 | font-style: normal;
39 | border-top-left-radius: 16px;
40 | border-bottom-left-radius: 16px;
41 | background: var(--lfg-sky-200);
42 | border: 2px solid var(--lfg-sky-200);
43 | }
44 | div{
45 | line-height: 0;
46 | border-top-right-radius: 16px;
47 | border-bottom-right-radius: 16px;
48 | border: 2px solid var(--lfg-sky-200);
49 | background: var(--lfg-sky-300);
50 | }
51 | `
52 |
53 | export const Tag = styled.div`
54 | font-size: 16px;
55 | font-weight: 700;
56 | line-height: 20px;
57 | padding: 4px 12px;
58 | border-radius: 14px;
59 | display: inline-flex;
60 | border: 1px solid var(--black);
61 |
62 | &.red{
63 | background: var(--red);
64 | }
65 | &.blue{
66 | background: var(--blue);
67 | }
68 | &.yellow{
69 | background: var(--yellow);
70 | }
71 | `
72 |
73 | export const StyledLink = styled.a`
74 | line-height: normal;
75 | cursor: pointer;
76 | color: ${({ theme }) => theme.text.primary};
77 | `
78 |
79 | export const IssueGrid = styled.div`
80 | display: grid;
81 | grid-template-columns: repeat(2, 1fr);
82 | grid-gap: 40px;
83 | cursor: pointer;
84 | @media screen and (max-width: ${({ theme }) => theme.deviceSize.tablet}) {
85 | grid-template-columns: repeat(1, 1fr);
86 | padding: 20px;
87 | }
88 | `
89 |
90 | export const ButtonLink = styled.a`
91 | font-size: 24px;
92 | display: inline-flex;
93 | line-height: normal;
94 | padding: 16px 32px;
95 | border-style: none;
96 | outline: none;
97 | cursor: pointer;
98 | border-radius: 36px;
99 | background: rgb(228, 232, 236);
100 | background: linear-gradient(262.31deg, #06F1F8 1.86%, #2F8FFF 27.73%, #FF3382 68.97%, #FFBD6F 99.88%);
101 | transition: all .3s;
102 | position: relative;
103 |
104 |
105 | `
--------------------------------------------------------------------------------
/components/Seo.js:
--------------------------------------------------------------------------------
1 | import { NextSeo } from 'next-seo';
2 | import seoData from '../next-seo.config';
3 |
4 | export default function Seo({ page }) {
5 | const { title, excerpt, slug, coverImage } = page;
6 | return (
7 | <>
8 |
58 | >
59 | );
60 | }
--------------------------------------------------------------------------------
/components/WebLinks.js:
--------------------------------------------------------------------------------
1 | // Weblinks Page Sections
2 | // created by @realvjy
3 | // date: 29 Jul, 2022
4 |
5 | import Image from "next/image";
6 | import styled from "styled-components";
7 | import { Button, ButtonLink, Container, StyledLink } from "./ReusableStyles";
8 | import Link from "next/link";
9 | import { ChevronRightIcon, HexIcon, HomeIcon, TwitterIcon, NewUp, OvalIcon } from './icons';
10 | import allLinks from "../data/LinksData";
11 | import bioData from "../data/BioData";
12 |
13 |
14 |
15 | const Links = () => {
16 |
17 | // all user info from bioData
18 | const name = bioData[0].name;
19 | const url = bioData[0].url;
20 | const username = bioData[0].username;
21 | const titleImg = bioData[0].titleImg;
22 | const avatarImg = bioData[0].avatar;
23 | const description = bioData[0].description;
24 | const descShow = bioData[0].descShow;
25 | const subdesc = bioData[0].subdesc;
26 | const subdescShow = bioData[0].subdescShow;
27 | const footerText = bioData[0].footerText;
28 | const author = bioData[0].author;
29 | const authorURL = bioData[0].authorURL;
30 | const titleImage = "/title.svg";
31 |
32 | // Check what class to use oval or hex for avatar
33 | const avatarShape = bioData[0].nftAvatar ? `nft-clipped` : `oval-clipped`
34 |
35 |
36 | // Description and subdescription goes here
37 | const descriptionText = descShow ? description : `Write your own fall back text if description not in BioData.js or remove me/leave blank`
38 | const subdescText = subdescShow ? subdesc : `Write your own if you want or just remove me/leave blank`
39 |
40 |
41 | const newProduct = bioData[0].newProduct; // checking for newProduct flag true false
42 | const newProductUrl = bioData[0].newProductUrl; // get product url if available
43 |
44 |
45 |
46 | // Collect all links filter by type - social, project, nft and other etc=
47 | // get data for social section
48 | const social = allLinks.filter((el) => {
49 | return el.type === "social" && el.on
50 | });
51 |
52 | // Get data for install section
53 | const install = allLinks.filter((el) => {
54 | return el.type === "install" && el.on
55 | });
56 |
57 | // Get data for nfts
58 | const nfts = allLinks.filter((el) => {
59 | return el.type === "nft" && el.on
60 | });
61 |
62 | // Get data for other section
63 | const others = allLinks.filter((el) => {
64 | return el.type === "other" && el.on
65 | });
66 |
67 | return (
68 |
69 |
70 |
71 |
72 |
73 |
74 | {/* Avatar svg hex or oval if nftAvatar=true will convert to hex */}
75 |
76 |
77 |
78 |
79 |
83 |
84 |
85 |
86 | {/* Using titleimg flag to use image as title or text */}
87 | {titleImg ?
88 | :
89 |
{name}
90 | }
91 | {/* if your remove username from data it will not appear */}
92 | {
93 | username ?