我如何在短短 2 小时内创建出一个极简的 Linktree 式页面。
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
计划
我看到很多人使用 Linktree 和类似的网站来创建社交链接页面,但我需要的是一个非常简洁干净的页面,所以我决定自己制作社交链接页面!
注:我已尽力解释整个过程,但我还是个博客新手,所以如果有些地方看起来很奇怪,请不要介意,也请告诉我哪些地方可以改进,我很乐意听取您的意见。
设计
设计思路很清晰:一个小头像、名字、个人简介以及所有社交链接,都以图标形式呈现,并带有炫酷的悬停效果。为了方便日后自定义,我知道必须创建一个配置文件,其中包含所有颜色、图标列表、名字、个人简介和头像链接。它看起来是这样的:
// config.js
export const config = {
avatar: 'https://avatars.githubusercontent.com/u/68690233',
bgColor: '#18181b',
textColor: '#d4d4d8',
iconColor: '#d4d4d8',
name: 'ashish',
description: 'solo developer by day, overthinker by night.',
links: [
{
slug: 'github',
type: 'url',
link: 'https://github.com/asheeeshh/'
},
{
slug: 'discord',
type: 'hover',
text: 'asheeshh#7727'
},
...
]
}
请注意我如何使用type: 'hover'Discord 图标来将其与其他图标区分开来,继续阅读以了解原因。
技术栈
由于只是一个单页应用,我决定使用 NextJS,因为我目前对它非常熟悉。以下是我使用的所有框架和库:
- NextJS
- 顺风
- React-Tooltip
- React-Hot-Toast
- 简易图标
创建应用程序
首先,我使用我喜爱的命令快速启动了下一个项目create-next-app,在项目中初始化了Tailwind CSS,并安装了我需要的所有其他库。
下一步是创建我需要的所有组件,即Avatar.jsx、Icon.jsx和IconBar.jsx。
成分
Avatar.jsx- 应用中的头像组件。Icon.jsx- 单个图标组件。IconBar.jsx- 应用程序中的水平图标栏组件。
现在,我们来讨论一下这些文件的内容。
这是我的文件代码Avatar.jsx。它是一个带有 Tailwind 类的 Next Image 组件。
// Avatar.jsx
import Image from 'next/image'
export default function Avatar() {
return (
<Image src="https://avatars.githubusercontent.com/u/68690233" alt="Avatar" width={100} height={100} className="rounded-full"/>
)
}
图标方面,我使用的是 Simple-Icons,因为他们有很多品牌图标,这正是我需要的。首先,我创建了一个文件GetIcon.js,使用别名(slug)获取 SVG 图标。它看起来大概是这样的。
// GetIcon.js
import SimpleIcons from 'simple-icons';
export default function GetIcon(slug) {
const icon = SimpleIcons.Get(slug).svg
return icon;
}
如您所见,它返回的<svg></svg>是图标的标签字符串。下一步是将该字符串转换为 JSX 组件,这正是我的Icon.jsx组件的功能。
// Icon.jsx
import GetIcon from "../libs/GetIcon";
import { config } from "../config";
export default function Icon(props) {
return (
<div dangerouslySetInnerHTML={{__html: `${GetIcon(props.icon)}`}} className="w-[30px] h-[30px] hover:scale-[1.15] duration-300 ease-in-out" style={{fill: `${config.iconColor}`}}></div>
)
}
你可以看到我使用配置来设置图标颜色。它接收图标别名作为 props,并将其传递给GetIcon()返回 svg 字符串的函数,该函数随后使用 jsx 组件将 svg 转换为 jsx 组件。dangereouslySetInnerHTML
最后一个组件IconBar.jsx会将所有图标水平堆叠起来,并将它们作为 jsx 组件返回。
// IconBar.jsx
import Icon from "./Icon";
import { config } from "../config";
import ReactTooltip from 'react-tooltip';
import { useEffect, useState } from "react";
import toast, { Toaster } from 'react-hot-toast';
export default function IconBar() {
const [isMounted, setIsMounted] = useState(false)
useEffect(() => {
setIsMounted(true)
}, [])
const handleClick = (e) => {
navigator.clipboard.writeText(e.target.closest('[data-tip]').dataset.tip)
toast.success("Copied to clipboard!", {
duration: 2000,
})
}
const icons = config.links.map(
(icon) => {
if (icon.type == "url") {
return (
<div className="text-center items-center cursor-pointer" key={icon.slug}>
<a href={icon.link} target="_blank" rel="noopener noreferrer" >
<Icon icon={icon.slug} />
</a>
</div>
);
} else if (icon.type == "hover") {
return (
<div className="text-center items-center cursor-pointer" key={icon.slug}>
<a data-tip={icon.text} key={icon.slug} onClick={handleClick}>
<Icon icon={icon.slug} />
</a>
{isMounted && <ReactTooltip place="top" type="dark" effect="float"/>}
</div>
)
} else {
return;
}
}
)
return (
<div className="flex flex-wrap w-full h-full gap-5 justify-center items-top">
<Toaster
toastOptions={{
style: {
background: `${config.textColor}`
}
}}
/>
{icons}
</div>
)
}
config.js我正在将文件中的数组映射icons到<div></div>组件,最终这些组件会被用到返回的 div 元素中。另外,由于 Discord 没有 URL,但有一个标签,所以我用它来为 Discord 图标创建工具提示。这就是我上面提到的React-Tooltip添加 Discord 图标的原因。type: 'hover'
为了显示 Discord 标签已被复制的通知,我使用了该React-Hot-Toast库。
组装部件
最后一步是将文件中的所有组件组装起来,index.js完成应用程序的开发。成品如下:
// index.js
import Avatar from "../components/Avatar"
import IconBar from "../components/IconBar"
import { config } from "../config"
import Head from "next/head"
export default function Home() {
return (
<div className="flex flex-col justify-center items-center w-screen h-screen p-6" style={{backgroundColor: `${config.bgColor}`}}>
<Head>
<title>{config.name}</title>
<meta name="description" content={config.description} />
<link rel="icon" href={(process.env.NEXT_PUBLIC_CLOUDIMG_TOKEN) ? `https://${process.env.NEXT_PUBLIC_CLOUDIMG_TOKEN}.cloudimg.io/${config.avatar}?radius=500` : `${config.avatar}`} />
</Head>
<div className="flex flex-col justify-center align-center w-full lg:w-1/2 md:w-1/3 h-[80%] lg:h-1/2 md:h-1/2 items-center">
<div className="w-full h-full flex flex-col justify-center items-center">
<Avatar />
<h1 className="text-center text-xl font-[600] mt-3" style={{color: `${config.textColor}`}}>{config.name}</h1>
<h1 className="text-[${config.textColor}] text-center text-md font-normal mt-5" style={{color: `${config.textColor}`}}>{config.description}</h1>
<div className="w-full h-1/4 mt-5 lg:mt-3 md:mt-3">
<IconBar />
</div>
</div>
</div>
</div>
)
}
组装完成后,使用 Tailwind 进行一些样式设置,App 的外观如下:
部署应用程序
我使用 Vercel 来部署应用程序,因为它与 NextJS 的兼容性最佳,并且我还为其添加了一个自定义子域名。目前,该网站已上线,网址为https://ayyy.vercel.app/和https://ayyy.asheeshh.ninja/。
结论
这就是制作这款应用的整个过程,大约花了2个小时,我现在已经把它用作我的社交链接页面了。
您可以随意使用它来创建自己的页面,源代码以 MIT 许可证发布在此处。
感谢阅读 <3
文章来源:https://dev.to/asheeshh/how-i-created-a-minimal-linktree-like-page-for-me-in-just-2-hours-ncp
