mirror of
https://github.com/fergalmoran/opengifame.git
synced 2025-12-22 09:38:44 +00:00
Layout kinda pimped and doots pimped
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,3 +34,4 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
.vscode
|
||||
|
||||
2
components/index.ts
Normal file
2
components/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import GifContainer from "./widgets/GifContainer";
|
||||
export { GifContainer };
|
||||
48
components/layout/Navbar.tsx
Normal file
48
components/layout/Navbar.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react'
|
||||
import Image from 'next/image';
|
||||
|
||||
const Navbar = () => {
|
||||
return (
|
||||
<nav className="bg-white border-b border-gray-200">
|
||||
<div className="px-4 mx-auto max-w-7xl sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between h-16">
|
||||
<div className="flex">
|
||||
<div className="flex items-center flex-shrink-0 mr-8">
|
||||
<Image alt="Logo" width={48} height={48}
|
||||
className="rounded-full"
|
||||
src={'/img/header-logo.gif'} />
|
||||
<h1 className='ml-4 text-2xl text-gray-700 text-bold'>Frasier Gifs</h1>
|
||||
</div>
|
||||
<div className="hidden sm:-my-px sm:ml-6 sm:flex sm:space-x-8">
|
||||
<a href="#" className="inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-900 border-b-2 border-indigo-500" aria-current="page"> Upload </a>
|
||||
<a href="#" className="inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-500 border-b-2 border-transparent hover:border-gray-300 hover:text-gray-700"> Request </a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden sm:ml-6 sm:flex sm:items-center">
|
||||
<button type="button" className="p-1 text-gray-400 bg-white rounded-full hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
<span className="sr-only">View notifications</span>
|
||||
<svg className="w-6 h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center -mr-2 sm:hidden">
|
||||
{ /* Mobile menu button */}
|
||||
<button type="button" className="inline-flex items-center justify-center p-2 text-gray-400 bg-white rounded-md hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" aria-controls="mobile-menu" aria-expanded="false">
|
||||
<span className="sr-only">Open main menu</span>
|
||||
<svg className="block w-6 h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
<svg className="hidden w-6 h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar
|
||||
21
components/layout/PageLayout.tsx
Normal file
21
components/layout/PageLayout.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react'
|
||||
import Navbar from './Navbar'
|
||||
|
||||
interface IPageLayoutProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
const PageLayout: React.FC<IPageLayoutProps> = ({ children }) => {
|
||||
return (
|
||||
<div className="min-h-full">
|
||||
<Navbar />
|
||||
<div className="px-10 py-10">
|
||||
<main>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default PageLayout
|
||||
3
components/layout/index.ts
Normal file
3
components/layout/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import PageLayout from "./PageLayout";
|
||||
|
||||
export { PageLayout };
|
||||
61
components/widgets/GifContainer.tsx
Normal file
61
components/widgets/GifContainer.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import React from 'react'
|
||||
import Image from 'next/image';
|
||||
import { HandThumbUpIcon, HandThumbDownIcon } from '@heroicons/react/24/outline';
|
||||
import { Gif } from 'models';
|
||||
|
||||
interface IGifContainerProps {
|
||||
gif: Gif;
|
||||
}
|
||||
const GifContainer: React.FC<IGifContainerProps> = ({ gif }) => {
|
||||
const _doot = async (id: string, isUp: boolean) => {
|
||||
const result = await fetch(`api/votes?gifId=${id}&isUp=${isUp ? 1 : 0}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
return (<>
|
||||
<div className="group relative h-[17.5rem] transform overflow-hidden rounded-4xl">
|
||||
<div className="absolute inset-0 bg-indigo-50" >
|
||||
<Image alt={gif.title}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
className="absolute inset-0 transition duration-300 group-hover:scale-110"
|
||||
src={`/samples/${gif.fileName}.gif`} />
|
||||
</div>
|
||||
</div>
|
||||
{/* <h3 className="mt-2 text-xl font-bold tracking-tight font-display text-slate-900">{gif.title}</h3> */}
|
||||
|
||||
<div className="flex flex-row p-2">
|
||||
<p className="flex-1 text-base tracking-tight text-slate-500">
|
||||
<span className="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded dark:bg-blue-200 dark:text-blue-800">
|
||||
Frasier
|
||||
</span>
|
||||
<span className="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded dark:bg-blue-200 dark:text-blue-800">
|
||||
Roz
|
||||
</span>
|
||||
<span className="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded dark:bg-blue-200 dark:text-blue-800">
|
||||
Martin
|
||||
</span>
|
||||
</p>
|
||||
<div className="flex items-center justify-center space-x-1" >
|
||||
<div className="flex transition duration-75 ease-in-out delay-150 hover:text-orange-700 hover:cursor-pointer">
|
||||
<span
|
||||
onClick={() => _doot(gif.id, true)}>
|
||||
<HandThumbUpIcon className="w-5" />
|
||||
</span>
|
||||
<span className="text-xs">{gif.upVotes?.toString()}</span>
|
||||
</div>
|
||||
<div className="flex transition duration-75 ease-in-out delay-150 hover:text-orange-700 hover:cursor-pointer">
|
||||
<span
|
||||
onClick={() => _doot(gif.id, false)}
|
||||
className='pl-2 '>
|
||||
<HandThumbDownIcon className="w-5" />
|
||||
</span>
|
||||
<span className="text-xs">{gif.downVotes?.toString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default GifContainer
|
||||
2
components/widgets/index.ts
Normal file
2
components/widgets/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import GifContainer from "./GifContainer";
|
||||
export { GifContainer };
|
||||
@@ -1,9 +1,10 @@
|
||||
export interface Gif {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
fileName: string;
|
||||
dateCreated: string;
|
||||
upVotes: Number;
|
||||
downVotes: Number;
|
||||
}
|
||||
export default interface Gif {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string | null;
|
||||
fileName: string;
|
||||
dateCreated: string;
|
||||
upVotes: Number;
|
||||
downVotes: Number;
|
||||
hasVoted: Boolean;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {Gif} from "./Gif";
|
||||
import type Gif from "./Gif";
|
||||
import type VoteModel from "./voteModel";
|
||||
|
||||
export type {Gif}
|
||||
export { Gif, VoteModel };
|
||||
|
||||
7
models/voteModel.ts
Normal file
7
models/voteModel.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export default interface VoteModel {
|
||||
id: String;
|
||||
isUp: boolean;
|
||||
browserId: String;
|
||||
createdAt: Date;
|
||||
gifId: String;
|
||||
}
|
||||
@@ -9,12 +9,19 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.0.11",
|
||||
"@prisma/client": "4.4.0",
|
||||
"cookie": "^0.5.0",
|
||||
"js-cookie": "^3.0.1",
|
||||
"next": "12.3.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
"react-dom": "18.2.0",
|
||||
"request-ip": "^3.3.0",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cookie": "^0.5.1",
|
||||
"@types/js-cookie": "^3.0.2",
|
||||
"@types/node": "18.7.23",
|
||||
"@types/react": "18.0.21",
|
||||
"@types/react-dom": "18.0.6",
|
||||
|
||||
@@ -1,8 +1,26 @@
|
||||
import React from 'react'
|
||||
import '../styles/globals.css'
|
||||
import type { AppProps } from 'next/app'
|
||||
import type {AppProps} from 'next/app'
|
||||
import {PageLayout} from 'components/layout'
|
||||
import {generateBrowserId} from 'utils/browser'
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
function MyApp({Component, pageProps}: AppProps) {
|
||||
React.useEffect(() => {
|
||||
const checkBrowserId = async () => {
|
||||
const storedId = localStorage.getItem('__effp')
|
||||
if (!storedId) {
|
||||
localStorage.setItem('__effp', generateBrowserId())
|
||||
}
|
||||
Cookies.set("bid", localStorage.getItem('__effp') as string)
|
||||
}
|
||||
checkBrowserId()
|
||||
.catch(console.error);
|
||||
}, [])
|
||||
return (
|
||||
<PageLayout>
|
||||
<Component {...pageProps} />
|
||||
</PageLayout>)
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
|
||||
@@ -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' })
|
||||
}
|
||||
37
pages/api/votes.ts
Normal file
37
pages/api/votes.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {PrismaClient} from "@prisma/client";
|
||||
import {getBrowserId} from "utils/browser";
|
||||
import qs from 'querystring'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const {
|
||||
query: {gifId, isUp},
|
||||
} = req;
|
||||
const prisma = new PrismaClient();
|
||||
const browserId = req.cookies.bid;
|
||||
|
||||
const exists = await prisma.votes.count({
|
||||
where: {
|
||||
gifId: gifId as string,
|
||||
browserId: browserId,
|
||||
},
|
||||
});
|
||||
|
||||
if (exists !== 0) {
|
||||
res.status(403).json({
|
||||
message: "You have already voted on this gif",
|
||||
});
|
||||
}
|
||||
const result = await prisma.votes.create({
|
||||
data: {
|
||||
isUp: isUp === "1",
|
||||
browserId: browserId as string,
|
||||
gifId: gifId as string,
|
||||
},
|
||||
});
|
||||
res.status(200).json(result);
|
||||
}
|
||||
@@ -1,24 +1,21 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import type { GetServerSideProps, NextPage } from "next";
|
||||
import { Gif } from "../models";
|
||||
import Image from "next/image";
|
||||
import {PrismaClient} from "@prisma/client";
|
||||
import type {GetServerSideProps, NextPage} from "next";
|
||||
import {Gif} from "models"
|
||||
import {GifContainer} from "components";
|
||||
import {getBrowserId} from "../utils/browser";
|
||||
|
||||
interface IHomeProps {
|
||||
gifs: Gif[]
|
||||
}
|
||||
|
||||
const Home: NextPage<IHomeProps> = ({ gifs }) => {
|
||||
const Home: NextPage<IHomeProps> = ({gifs}) => {
|
||||
return (
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-red-700 underline">
|
||||
Frasier Gifs
|
||||
</h1>
|
||||
<div className="grid grid-cols-3">
|
||||
<div className="grid grid-cols-1 xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
{gifs.map((gif: Gif) => {
|
||||
return (
|
||||
<div key={gif.id}>
|
||||
<h2>{gif.title}</h2>
|
||||
<Image alt={gif.title} width={64} height={64} src={`/samples/${gif.fileName}.gif`} />
|
||||
<div key={gif.id} className="m-2">
|
||||
<GifContainer gif={gif}/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
@@ -27,12 +24,57 @@ const Home: NextPage<IHomeProps> = ({ gifs }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
||||
export const getServerSideProps: GetServerSideProps = async ({req}) => {
|
||||
const browserId = getBrowserId(req.headers.cookie || '');
|
||||
const prisma = new PrismaClient();
|
||||
const gifs = await prisma.gif.findMany({
|
||||
take: 12, orderBy: { title: 'asc' },
|
||||
});
|
||||
|
||||
return { props: { gifs: JSON.parse(JSON.stringify(gifs)) } };
|
||||
const results = await prisma.gif.findMany({
|
||||
take: 12, orderBy: {title: 'asc'},
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
votes: {where: {isUp: true}},
|
||||
// votes: { where: { isUp: false } }, //how to achieve
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const gifs = await Promise.all(results.map(async (gif): Promise<Gif> => {
|
||||
const votes = await prisma.votes.count({
|
||||
where: {
|
||||
gifId: gif.id as string,
|
||||
browserId: browserId,
|
||||
},
|
||||
})
|
||||
const upVotes = await prisma.votes.count({
|
||||
where: {
|
||||
gifId: gif.id as string,
|
||||
browserId: browserId,
|
||||
isUp: true
|
||||
},
|
||||
})
|
||||
const downVotes = await prisma.votes.count({
|
||||
where: {
|
||||
gifId: gif.id as string,
|
||||
browserId: browserId,
|
||||
isUp: false
|
||||
},
|
||||
})
|
||||
return {
|
||||
id: gif.id,
|
||||
title: gif.title,
|
||||
description: gif.description,
|
||||
fileName: gif.fileName,
|
||||
dateCreated: gif.createdAt.toISOString(),
|
||||
upVotes: upVotes,
|
||||
downVotes: downVotes,
|
||||
hasVoted: votes !== 0
|
||||
}
|
||||
}))
|
||||
return {
|
||||
props: {
|
||||
gifs
|
||||
}
|
||||
};
|
||||
};
|
||||
export default Home;
|
||||
|
||||
24
prisma/migrations/20220928221643_add_doots/migration.sql
Normal file
24
prisma/migrations/20220928221643_add_doots/migration.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `downVotes` on the `Gif` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `upVotes` on the `Gif` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Gif" DROP COLUMN "downVotes",
|
||||
DROP COLUMN "upVotes";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Votes" (
|
||||
"id" TEXT NOT NULL,
|
||||
"isUp" BOOLEAN NOT NULL,
|
||||
"browserId" VARCHAR(1000) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"gifId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Votes_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Votes" ADD CONSTRAINT "Votes_gifId_fkey" FOREIGN KEY ("gifId") REFERENCES "Gif"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -2,7 +2,8 @@
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["filteredRelationCount"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
@@ -18,8 +19,18 @@ model Gif {
|
||||
searchTerms String? @db.VarChar(2000)
|
||||
//this is temporary, filenames should always match the GUID above
|
||||
fileName String @db.VarChar(100)
|
||||
upVotes Int @default(0)
|
||||
downVotes Int @default(0)
|
||||
|
||||
votes Votes[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Votes {
|
||||
id String @id @default(uuid())
|
||||
isUp Boolean @db.Boolean()
|
||||
browserId String @db.VarChar(1000)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
gif Gif @relation(fields: [gifId], references: [id])
|
||||
gifId String
|
||||
}
|
||||
|
||||
BIN
public/img/header-logo.gif
Normal file
BIN
public/img/header-logo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 340 KiB |
@@ -1,5 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@models/*": ["./models/*"],
|
||||
"@components/*": ["./components/*"]
|
||||
},
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
@@ -15,6 +20,6 @@
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"include": ["src", "next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
22
utils/browser.ts
Normal file
22
utils/browser.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import cookie from "cookie"
|
||||
import {ParsedUrlQuery} from "querystring";
|
||||
|
||||
export const generateBrowserId = () => {
|
||||
// always start with a letter (for DOM friendlyness)
|
||||
var idstr = String.fromCharCode(Math.floor(Math.random() * 25 + 65));
|
||||
do {
|
||||
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
|
||||
var ascicode = Math.floor(Math.random() * 42 + 48);
|
||||
if (ascicode < 58 || ascicode > 64) {
|
||||
// exclude all chars between : (58) and @ (64)
|
||||
idstr += String.fromCharCode(ascicode);
|
||||
}
|
||||
} while (idstr.length < 256);
|
||||
|
||||
return idstr;
|
||||
};
|
||||
|
||||
export const getBrowserId = (c: string) => {
|
||||
const parsed = cookie.parse(c);
|
||||
return parsed.bid;
|
||||
};
|
||||
35
yarn.lock
35
yarn.lock
@@ -32,6 +32,11 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@heroicons/react@^2.0.11":
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.11.tgz#2c6cf4c66d81142ec87c102502407d8c353558bb"
|
||||
integrity sha512-bASjOgSSaYj8HqXWsOqaBiB6ZLalE/g90WYGgZ5lPm4KCCG7wPXntY4kzHf5NrLh6UBAcnPwvbiw1Ne9GYfJtw==
|
||||
|
||||
"@humanwhocodes/config-array@^0.10.5":
|
||||
version "0.10.5"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.5.tgz#bb679745224745fff1e9a41961c1d45a49f81c04"
|
||||
@@ -183,6 +188,16 @@
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@types/cookie@^0.5.1":
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.5.1.tgz#b29aa1f91a59f35e29ff8f7cb24faf1a3a750554"
|
||||
integrity sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==
|
||||
|
||||
"@types/js-cookie@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.2.tgz#451eaeece64c6bdac8b2dde0caab23b085899e0d"
|
||||
integrity sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA==
|
||||
|
||||
"@types/json5@^0.0.29":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
@@ -501,6 +516,11 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
cookie@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
core-js-pure@^3.25.1:
|
||||
version "3.25.3"
|
||||
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.25.3.tgz#66ac5bfa5754b47fdfd14f3841c5ed21c46db608"
|
||||
@@ -1251,6 +1271,11 @@ isexe@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
|
||||
|
||||
js-cookie@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
|
||||
integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
|
||||
|
||||
js-sdsl@^4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.4.tgz#78793c90f80e8430b7d8dc94515b6c77d98a26a6"
|
||||
@@ -1731,6 +1756,11 @@ regexpp@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
|
||||
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
|
||||
|
||||
request-ip@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611"
|
||||
integrity sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==
|
||||
|
||||
resolve-from@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
@@ -2017,6 +2047,11 @@ util-deprecate@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
||||
uuid@^9.0.0:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
|
||||
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
|
||||
|
||||
which-boxed-primitive@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
|
||||
|
||||
Reference in New Issue
Block a user