[website] Added blog support

[website]  Fixed Navbar & made responsive
This commit is contained in:
Kingkor Roy Tirtho 2022-07-18 15:14:18 +06:00
parent 68e9dfe9b3
commit 0e10ddfa54
11 changed files with 682 additions and 27 deletions

View File

@ -0,0 +1,138 @@
import { Link, Flex, Box, chakra, Image, Button, Text } from "@chakra-ui/react";
import { BlogPost } from "pages/blog";
import { FC } from "react";
import NavLink from "next/link";
const ArticleCard: FC<BlogPost> = ({
metadata: {
author,
author_avatar_url,
cover_image,
tags,
title,
summary,
date,
},
slug,
}) => {
return (
<Box
mx="auto"
rounded="lg"
shadow="md"
bg="white"
_dark={{
bg: "gray.800",
}}
maxW="2xl"
>
<Image
roundedTop="lg"
w="full"
h={64}
fit="cover"
src={cover_image}
alt="Article"
/>
<Box p={6}>
<Box>
{tags.map((tag, i) => {
return (
<chakra.span
key={i}
px={3}
py={1}
mx="1"
bg="gray.600"
color="gray.100"
fontSize="sm"
fontWeight="700"
rounded="md"
>
{tag}
</chakra.span>
);
})}
<NavLink href={`/blog/${slug}`} passHref>
<Link
display="block"
color="gray.800"
_dark={{
color: "white",
}}
fontWeight="bold"
fontSize="2xl"
mt={2}
_hover={{
color: "gray.600",
textDecor: "underline",
}}
>
{title}
</Link>
</NavLink>
<chakra.p
mt={2}
fontSize="sm"
color="gray.600"
_dark={{
color: "gray.400",
}}
>
{summary}
</chakra.p>
</Box>
<Box mt={4}>
<Flex
alignItems="center"
justify="space-between"
flexDirection={{ base: "column", md: "row" }}
>
<Flex alignItems="center">
<Image
h={10}
fit="cover"
rounded="full"
src={author_avatar_url}
alt="Avatar"
/>
<Text
mx={2}
fontWeight="bold"
color="gray.700"
_dark={{
color: "gray.200",
}}
>
{author}
</Text>
<chakra.span
mx={1}
fontSize="sm"
color="gray.600"
_dark={{
color: "gray.300",
}}
>
{date}
</chakra.span>
</Flex>
<NavLink href={`/blog/${slug}`} passHref>
<Button
_hover={{ textDecor: "none" }}
colorScheme="purple"
as={Link}
>
Read the Full Article
</Button>
</NavLink>
</Flex>
</Box>
</Box>
</Box>
);
};
export default ArticleCard;

View File

@ -10,26 +10,60 @@ import {
} from "@chakra-ui/react";
import { Platform, usePlatform } from "hooks/usePlatform";
import React from "react";
import { FaCaretDown } from "react-icons/fa";
import {
FaApple,
FaCaretDown,
FaUbuntu,
FaLinux,
FaWindows,
FaAndroid,
} from "react-icons/fa";
const baseURL = "https://github.com/KRTirtho/spotube/releases/latest/download/";
const DownloadLinks = Object.freeze({
[Platform.linux]: [
{ name: "deb", url: baseURL + "Spotube-linux-x86_64.deb" },
{ name: "tar", url: baseURL + "Spotube-linux-x86_64.tar.xz" },
{ name: "AppImage", url: baseURL + "Spotube-linux-x86_64.AppImage" },
{
name: "deb",
url: baseURL + "Spotube-linux-x86_64.deb",
icon: <FaUbuntu />,
},
{
name: "tar",
url: baseURL + "Spotube-linux-x86_64.tar.xz",
icon: <FaLinux />,
},
{
name: "AppImage",
url: baseURL + "Spotube-linux-x86_64.AppImage",
icon: <FaLinux />,
},
],
[Platform.android]: [
{
name: "apk",
url: baseURL + "Spotube-android-all-arch.apk",
icon: <FaAndroid />,
},
],
[Platform.mac]: [
{
name: "dmg",
url: baseURL + "Spotube-macos-x86_64.dmg",
icon: <FaApple />,
},
],
[Platform.mac]: [{ name: "dmg", url: baseURL + "Spotube-macos-x86_64.dmg" }],
[Platform.windows]: [
{ name: "exe", url: baseURL + "Spotube-windows-x86_64-setup.exe" },
{ name: "nupkg", url: baseURL + "Spotube-windows-x86_64.nupkg " },
{
name: "exe",
url: baseURL + "Spotube-windows-x86_64-setup.exe",
icon: <FaWindows />,
},
{
name: "nupkg",
url: baseURL + "Spotube-windows-x86_64.nupkg ",
icon: <FaWindows />,
},
],
});
@ -55,7 +89,7 @@ const DownloadButton = () => {
href={currentPlatform.url}
_hover={{ textDecoration: "none" }}
>
Download for {platform} (.{currentPlatform.name}) Binary
Download for {platform} (.{currentPlatform.name})
</Button>
<MenuButton
aria-label="Show More Downloads"
@ -65,9 +99,9 @@ const DownloadButton = () => {
/>
</ButtonGroup>
<MenuList>
{allPlatforms.map(({ name, url }) => {
{allPlatforms.map(({ name, url, icon }) => {
return (
<MenuItem key={url} as={Anchor} href={url}>
<MenuItem key={url} as={Anchor} href={url} icon={icon}>
{name}
</MenuItem>
);

View File

@ -1,17 +1,29 @@
import {
Box,
Button,
ButtonGroup,
chakra,
CloseButton,
Flex,
Heading,
HStack,
IconButton,
Link,
useColorMode,
useColorModeValue,
useDisclosure,
VisuallyHidden,
VStack,
} from "@chakra-ui/react";
import NavLink from "next/link";
import { GoLightBulb } from "react-icons/go";
import { FiSun } from "react-icons/fi";
import { FiGithub, FiSun } from "react-icons/fi";
import Image from "next/image";
import React from "react";
import { AiOutlineMenu } from "react-icons/ai";
import { BsHeartFill } from "react-icons/bs";
const Navbar = () => {
const ExNavbar = () => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<HStack justifyContent="space-between" as="nav" w="full">
@ -34,6 +46,11 @@ const Navbar = () => {
Downloads
</Button>
</NavLink>
<NavLink href="/blog" passHref>
<Button as="a" variant="ghost" colorScheme="gray">
Blog
</Button>
</NavLink>
<NavLink href="/about" passHref>
<Button as="a" variant="ghost" colorScheme="gray">
About
@ -53,4 +70,185 @@ const Navbar = () => {
);
};
const Navbar = () => {
const bg = useColorModeValue("white", "gray.800");
const mobileNav = useDisclosure();
return (
<React.Fragment>
<chakra.header
bg={bg}
w="full"
px={{
base: 1,
sm: 3,
}}
py={2}
shadow="md"
>
<Flex alignItems="center" justifyContent="space-between" mx="auto">
<Flex align="center">
<NavLink href="/">
<Image
src="/spotube-logo.svg"
alt="Logo"
height="45"
width="45"
layout="fixed"
/>
</NavLink>
<VisuallyHidden>Spotube</VisuallyHidden>
<NavLink href="/" passHref>
<Heading p="2" as="a" size="lg" mr="2">
Spotube
</Heading>
</NavLink>
</Flex>
<HStack display="flex" alignItems="center" spacing={1}>
<HStack
spacing={1}
mr={1}
color="brand.500"
display={{
base: "none",
md: "inline-flex",
}}
>
<NavLink href="/other-downloads" passHref>
<Button as="a" colorScheme="gray" variant="ghost">
Downloads
</Button>
</NavLink>
<NavLink href="/blog" passHref>
<Button as="a" variant="ghost" colorScheme="gray">
Blog
</Button>
</NavLink>
<NavLink href="/about" passHref>
<Button as="a" variant="ghost" colorScheme="gray">
About
</Button>
</NavLink>
<Button
as={Link}
href="https://github.com/KRTirtho/spotube"
bgColor="black"
color="white"
target="_blank"
_hover={{
textDecor: "none",
bgColor: "blackAlpha.800",
}}
_active={{
bgColor: "blackAlpha.700",
}}
rightIcon={<FiGithub />}
>
Give us a on
</Button>
</HStack>
<Button
size={{
base: "sm",
md: "sm",
lg: "md",
}}
as={Link}
href="https://opencollective.com/spotube"
bgColor="pink.100"
color="pink.500"
_hover={{
bgColor: "pink.200",
textDecor: "none",
}}
_active={{
bgColor: "pink.100",
}}
rightIcon={<BsHeartFill />}
target="_blank"
>
Donate/Sponsor us
</Button>
<Box
display={{
base: "inline-flex",
md: "none",
}}
>
<IconButton
display={{
base: "flex",
md: "none",
}}
aria-label="Open menu"
fontSize="20px"
color="gray.800"
_dark={{
color: "inherit",
}}
variant="ghost"
icon={<AiOutlineMenu />}
onClick={mobileNav.onOpen}
/>
<VStack
pos="absolute"
top={0}
left={0}
right={0}
display={mobileNav.isOpen ? "flex" : "none"}
flexDirection="column"
p={2}
pb={4}
m={2}
bg={bg}
spacing={3}
rounded="sm"
shadow="sm"
>
<CloseButton
aria-label="Close menu"
onClick={mobileNav.onClose}
/>
<NavLink href="/other-downloads" passHref>
<Button w="full" as="a" colorScheme="gray" variant="ghost">
Downloads
</Button>
</NavLink>
<NavLink href="/blog" passHref>
<Button w="full" as="a" variant="ghost" colorScheme="gray">
Blog
</Button>
</NavLink>
<NavLink href="/about" passHref>
<Button w="full" as="a" variant="ghost" colorScheme="gray">
About
</Button>
</NavLink>
<Button
as={Link}
href="https://github.com/KRTirtho/spotube"
bgColor="black"
color="white"
target="_blank"
w="full"
_hover={{
textDecor: "none",
bgColor: "blackAlpha.800",
}}
_active={{
bgColor: "blackAlpha.700",
}}
rightIcon={<FiGithub />}
>
Give us a on
</Button>
</VStack>
</Box>
</HStack>
</Flex>
</chakra.header>
</React.Fragment>
);
};
export default Navbar;

View File

@ -1,6 +1,16 @@
import { Link as Anchor, Heading, Text, chakra } from "@chakra-ui/react";
import {
Link as Anchor,
Heading,
Text,
chakra,
Code,
HStack,
Divider,
Box,
} from "@chakra-ui/react";
import { Options } from "react-markdown";
export const MarkdownComponentDefs = {
export const MarkdownComponentDefs: Options["components"] = {
a: (props: any) => <Anchor {...props} color="blue.500" />,
h1: (props: any) => <Heading {...props} size="xl" mt="5" mb="1.5" />,
h2: (props: any) => <Heading {...props} size="lg" mt="5" mb="1.5" />,
@ -10,4 +20,24 @@ export const MarkdownComponentDefs = {
h6: (props: any) => <Heading {...props} size="xs" />,
p: (props: any) => <Text {...props} />,
li: (props: any) => <chakra.li {...props} ml="4" />,
code: (props) => (
<Code
{...props}
p={!props.inline ? 5 : 0}
overflow="scroll"
colorScheme="gray"
maxW="full"
/>
),
blockquote: (props) => {
return (
<HStack bgColor="blackAlpha.300" py="3" px="2">
<Box borderLeft="2px solid gray" pl="2">
<Text as="span" fontSize="sm">
{props.children}
</Text>
</Box>
</HStack>
);
},
};

View File

@ -18,6 +18,7 @@
"@octokit/rest": "^19.0.3",
"@types/progress": "^2.0.5",
"framer-motion": "^6",
"gray-matter": "^4.0.3",
"next": "12.2.2",
"nextjs-progressbar": "^0.0.14",
"react": "18.2.0",
@ -32,6 +33,7 @@
"@types/node": "18.0.5",
"@types/react": "18.0.15",
"@types/react-dom": "18.0.6",
"@types/react-syntax-highlighter": "^15.5.3",
"eslint": "8.20.0",
"eslint-config-next": "12.2.2",
"eslint-config-prettier": "^8.5.0",

View File

@ -1,13 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

View File

@ -0,0 +1,105 @@
import fs from "fs";
import path from "path";
import { GetStaticPaths, GetStaticProps, NextPage } from "next";
import ReactMarkdown from "react-markdown";
import matter from "gray-matter";
import { BlogMetadata } from ".";
import gfm from "remark-gfm";
import gemoji from "remark-gemoji";
import { MarkdownComponentDefs } from "misc/MarkdownComponentDefs";
import {
Box,
chakra,
Flex,
Heading,
Image,
Text,
VStack,
} from "@chakra-ui/react";
interface Props {
metadata: BlogMetadata;
content: string;
}
const BlogPost: NextPage<Props> = ({
content,
metadata: { author, author_avatar_url, cover_image, date, tags, title },
}) => {
return (
<VStack>
<Box w="full" maxH="xl" overflow="hidden" mb="5">
<Image fit="cover" src={cover_image} alt={title} />
</Box>
<VStack align="flex-start" py="5" px="10" w="full">
<Flex alignItems="center">
<Image
h="12"
fit="cover"
rounded="full"
src={author_avatar_url}
alt="Avatar"
/>
<VStack spacing="0">
<Text
mx={2}
fontWeight="bold"
color="gray.700"
_dark={{
color: "gray.200",
}}
>
{author}
</Text>
<chakra.span
mx={1}
fontSize="sm"
color="gray.600"
_dark={{
color: "gray.300",
}}
>
{date}
</chakra.span>
</VStack>
</Flex>
<Heading>{title}</Heading>
<ReactMarkdown
components={MarkdownComponentDefs}
remarkPlugins={[gfm, gemoji]}
>
{content}
</ReactMarkdown>
</VStack>
</VStack>
);
};
export default BlogPost;
export const getStaticPaths: GetStaticPaths = async () => {
const paths = fs.readdirSync("posts").map((file) => {
return {
params: {
slug: file.replace(".md", ""),
},
};
});
return {
paths,
fallback: false,
};
};
export const getStaticProps: GetStaticProps<Props> = async (ctx) => {
const { content, data } = matter(
fs.readFileSync(path.join("posts", `${ctx.params?.slug}.md`), "utf-8")
);
return {
props: {
content,
metadata: data as BlogMetadata,
},
};
};

View File

@ -0,0 +1,62 @@
import fs from "fs";
import path from "path";
import { GetStaticProps, NextPage } from "next";
import matter from "gray-matter";
import ArticleCard from "components/ArticleCard";
import { VStack } from "@chakra-ui/react";
export interface BlogMetadata {
title: string;
cover_image: string;
author: string;
date: string;
author_avatar_url: string;
tags: string[];
summary: string;
}
export interface BlogPost {
slug: string;
metadata: BlogMetadata;
}
interface Props {
posts: BlogPost[];
}
const Blog: NextPage<Props> = ({ posts }) => {
return (
<VStack mx="5" my="5" spacing="7">
{posts.map((post) => {
return (
<ArticleCard
key={post.slug}
metadata={post.metadata}
slug={post.slug}
/>
);
})}
</VStack>
);
};
export default Blog;
export const getStaticProps: GetStaticProps<Props> = async () => {
const posts = fs.readdirSync("posts").map((file) => {
return {
slug: file.replace(".md", ""),
metadata: matter(fs.readFileSync(path.join("posts", file)))
.data as BlogMetadata,
};
});
return {
props: {
posts: posts.sort(
// @ts-ignore
(a, b) => new Date(b.metadata.date) - new Date(a.metadata.date)
),
},
};
};

View File

@ -12,10 +12,12 @@ specifiers:
'@types/progress': ^2.0.5
'@types/react': 18.0.15
'@types/react-dom': 18.0.6
'@types/react-syntax-highlighter': ^15.5.3
eslint: 8.20.0
eslint-config-next: 12.2.2
eslint-config-prettier: ^8.5.0
framer-motion: ^6
gray-matter: ^4.0.3
next: 12.2.2
nextjs-progressbar: ^0.0.14
react: 18.2.0
@ -37,6 +39,7 @@ dependencies:
'@octokit/rest': 19.0.3
'@types/progress': 2.0.5
framer-motion: 6.5.1_biqbaboplfbrettd7655fr4n2y
gray-matter: 4.0.3
next: 12.2.2_beenoklgwfttvph5dgxj7na7aq
nextjs-progressbar: 0.0.14_next@12.2.2+react@18.2.0
react: 18.2.0
@ -51,6 +54,7 @@ devDependencies:
'@types/node': 18.0.5
'@types/react': 18.0.15
'@types/react-dom': 18.0.6
'@types/react-syntax-highlighter': 15.5.3
eslint: 8.20.0
eslint-config-next: 12.2.2_he2ccbldppg44uulnyq4rwocfa
eslint-config-prettier: 8.5.0_eslint@8.20.0
@ -1662,6 +1666,12 @@ packages:
'@types/react': 18.0.15
dev: true
/@types/react-syntax-highlighter/15.5.3:
resolution: {integrity: sha512-N5bgZxolo+wFuYnx4nOvIQO2P0E+KYHt3dDwb8ydUvZ96QN8Lpq60ReT+0W0JmXKZjp4udkYkIDYt9GIygBY1Q==}
dependencies:
'@types/react': 18.0.15
dev: true
/@types/react/18.0.15:
resolution: {integrity: sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==}
dependencies:
@ -1784,6 +1794,12 @@ packages:
color-convert: 2.0.1
dev: true
/argparse/1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
sprintf-js: 1.0.3
dev: false
/argparse/2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
@ -2441,6 +2457,12 @@ packages:
eslint-visitor-keys: 3.3.0
dev: true
/esprima/4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/esquery/1.4.0:
resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==}
engines: {node: '>=0.10'}
@ -2465,6 +2487,13 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/extend-shallow/2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
dependencies:
is-extendable: 0.1.1
dev: false
/extend/3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
dev: false
@ -2687,6 +2716,16 @@ packages:
slash: 3.0.0
dev: true
/gray-matter/4.0.3:
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
engines: {node: '>=6.0'}
dependencies:
js-yaml: 3.14.1
kind-of: 6.0.3
section-matter: 1.0.0
strip-bom-string: 1.0.0
dev: false
/has-bigints/1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
dev: true
@ -2826,6 +2865,11 @@ packages:
has-tostringtag: 1.0.0
dev: true
/is-extendable/0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
dev: false
/is-extglob/2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@ -2906,6 +2950,14 @@ packages:
/js-tokens/4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
/js-yaml/3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
dependencies:
argparse: 1.0.10
esprima: 4.0.1
dev: false
/js-yaml/4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@ -2952,6 +3004,11 @@ packages:
object.assign: 4.1.2
dev: true
/kind-of/6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
dev: false
/kleur/4.1.5:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
@ -3955,6 +4012,14 @@ packages:
loose-envify: 1.4.0
dev: false
/section-matter/1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
dependencies:
extend-shallow: 2.0.1
kind-of: 6.0.3
dev: false
/semver/6.3.0:
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
hasBin: true
@ -4006,6 +4071,10 @@ packages:
resolution: {integrity: sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==}
dev: false
/sprintf-js/1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: false
/string.prototype.matchall/4.0.7:
resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==}
dependencies:
@ -4042,6 +4111,11 @@ packages:
ansi-regex: 5.0.1
dev: true
/strip-bom-string/1.0.0:
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
engines: {node: '>=0.10.0'}
dev: false
/strip-bom/3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}

View File

@ -0,0 +1,11 @@
---
title: Getting Started With Spotube
cover_image: https://github.com/KRTirtho/spotube/raw/master/assets/spotube-screenshot.jpg
date: "July 16, 2022"
author: Kingkor Roy Tirtho
author_avatar_url: https://avatars.githubusercontent.com/u/61944859?v=4
tags:
- getting-started
- spotube
summary: You installed Spotube, don't know what to do now? Then don't worry we Gotchu covered here. We'll guide you through the basics of using Spotube & how you can use it to enrich your daily life with music.
---

View File

@ -0,0 +1,14 @@
---
title: Improve Search Accuracy
cover_image: https://github.com/KRTirtho/spotube/raw/master/assets/spotube_banner.png
date: "July 18, 2022"
author: Kingkor Roy Tirtho
author_avatar_url: https://avatars.githubusercontent.com/u/61944859?v=4
tags:
- spotify
- music
- spotube
summary: Spotube has matches Spotify Song counterparts in YouTube. So there's a lot chance that sometimes you'll get the wrong song. This is where we'll help you improve the accuracy of your search for specific songs
---
# Improve Search Accuracy