attempts at voting before running into cache issues
This commit is contained in:
parent
900b70da77
commit
c626998952
@ -6,7 +6,10 @@ import resolvers from './resolvers'
|
|||||||
import typeDefs from './typeDefs'
|
import typeDefs from './typeDefs'
|
||||||
import models from './models'
|
import models from './models'
|
||||||
|
|
||||||
const client = new ApolloClient({
|
export default async function serverSideClient (req) {
|
||||||
|
const session = await getSession({ req })
|
||||||
|
console.log(session)
|
||||||
|
return new ApolloClient({
|
||||||
ssrMode: true,
|
ssrMode: true,
|
||||||
// Instead of "createHttpLink" use SchemaLink here
|
// Instead of "createHttpLink" use SchemaLink here
|
||||||
link: new SchemaLink({
|
link: new SchemaLink({
|
||||||
@ -14,15 +17,11 @@ const client = new ApolloClient({
|
|||||||
schemas: typeDefs,
|
schemas: typeDefs,
|
||||||
resolvers: resolvers
|
resolvers: resolvers
|
||||||
}),
|
}),
|
||||||
context: async ({ req }) => {
|
context: {
|
||||||
const session = await getSession({ req })
|
|
||||||
return {
|
|
||||||
models,
|
models,
|
||||||
me: session ? session.user : null
|
me: session ? session.user : null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
cache: new InMemoryCache()
|
cache: new InMemoryCache()
|
||||||
})
|
})
|
||||||
|
}
|
||||||
export default client
|
|
||||||
|
@ -1,64 +1,5 @@
|
|||||||
import { UserInputError, AuthenticationError } from 'apollo-server-micro'
|
import { UserInputError, AuthenticationError } from 'apollo-server-micro'
|
||||||
|
|
||||||
const createItem = async (parent, { title, text, url, parentId }, { me, models }) => {
|
|
||||||
if (!me) {
|
|
||||||
throw new AuthenticationError('You must be logged in')
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
title,
|
|
||||||
url,
|
|
||||||
text,
|
|
||||||
user: {
|
|
||||||
connect: {
|
|
||||||
name: me.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentId) {
|
|
||||||
data.parent = {
|
|
||||||
connect: {
|
|
||||||
id: parseInt(parentId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const item = await models.item.create({ data })
|
|
||||||
item.comments = []
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
function nestComments (flat, parentId) {
|
|
||||||
const result = []
|
|
||||||
let added = 0
|
|
||||||
for (let i = 0; i < flat.length;) {
|
|
||||||
if (!flat[i].comments) flat[i].comments = []
|
|
||||||
if (Number(flat[i].parentId) === Number(parentId)) {
|
|
||||||
result.push(flat[i])
|
|
||||||
added++
|
|
||||||
i++
|
|
||||||
} else if (result.length > 0) {
|
|
||||||
const item = result[result.length - 1]
|
|
||||||
const [nested, newAdded] = nestComments(flat.slice(i), item.id)
|
|
||||||
if (newAdded === 0) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
item.comments.push(...nested)
|
|
||||||
i += newAdded
|
|
||||||
added += newAdded
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [result, added]
|
|
||||||
}
|
|
||||||
|
|
||||||
// we have to do our own query because ltree is unsupported
|
|
||||||
const SELECT =
|
|
||||||
`SELECT id, created_at as "createdAt", updated_at as "updatedAt", title,
|
|
||||||
text, url, "userId", "parentId", ltree2text("path") AS "path"`
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Query: {
|
Query: {
|
||||||
items: async (parent, args, { models }) => {
|
items: async (parent, args, { models }) => {
|
||||||
@ -142,6 +83,29 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return await createItem(parent, { text, parentId }, { me, models })
|
return await createItem(parent, { text, parentId }, { me, models })
|
||||||
|
},
|
||||||
|
vote: async (parent, { id, sats = 1 }, { me, models }) => {
|
||||||
|
// need to make sure we are logged in
|
||||||
|
if (!me) {
|
||||||
|
throw new AuthenticationError('You must be logged in')
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
sats,
|
||||||
|
item: {
|
||||||
|
connect: {
|
||||||
|
id: parseInt(id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
connect: {
|
||||||
|
name: me.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await models.vote.create({ data })
|
||||||
|
return sats
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -155,6 +119,96 @@ export default {
|
|||||||
WHERE path <@ text2ltree(${item.path}) AND id != ${item.id}`
|
WHERE path <@ text2ltree(${item.path}) AND id != ${item.id}`
|
||||||
return count
|
return count
|
||||||
},
|
},
|
||||||
sats: () => 0
|
sats: async (item, args, { models }) => {
|
||||||
|
const { sum: { sats } } = await models.vote.aggregate({
|
||||||
|
sum: {
|
||||||
|
sats: true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
itemId: item.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return sats
|
||||||
|
},
|
||||||
|
meSats: async (item, args, { me, models }) => {
|
||||||
|
if (!me) return 0
|
||||||
|
|
||||||
|
const { sum: { sats } } = await models.vote.aggregate({
|
||||||
|
sum: {
|
||||||
|
sats: true
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
itemId: item.id,
|
||||||
|
userId: me.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return sats
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createItem = async (parent, { title, text, url, parentId }, { me, models }) => {
|
||||||
|
if (!me) {
|
||||||
|
throw new AuthenticationError('You must be logged in')
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
text,
|
||||||
|
item: {
|
||||||
|
connect: {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
connect: {
|
||||||
|
name: me.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentId) {
|
||||||
|
data.parent = {
|
||||||
|
connect: {
|
||||||
|
id: parseInt(parentId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = await models.item.create({ data })
|
||||||
|
item.comments = []
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
function nestComments (flat, parentId) {
|
||||||
|
const result = []
|
||||||
|
let added = 0
|
||||||
|
for (let i = 0; i < flat.length;) {
|
||||||
|
if (!flat[i].comments) flat[i].comments = []
|
||||||
|
if (Number(flat[i].parentId) === Number(parentId)) {
|
||||||
|
result.push(flat[i])
|
||||||
|
added++
|
||||||
|
i++
|
||||||
|
} else if (result.length > 0) {
|
||||||
|
const item = result[result.length - 1]
|
||||||
|
const [nested, newAdded] = nestComments(flat.slice(i), item.id)
|
||||||
|
if (newAdded === 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
item.comments.push(...nested)
|
||||||
|
i += newAdded
|
||||||
|
added += newAdded
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [result, added]
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have to do our own query because ltree is unsupported
|
||||||
|
const SELECT =
|
||||||
|
`SELECT id, created_at as "createdAt", updated_at as "updatedAt", title,
|
||||||
|
text, url, "userId", "parentId", ltree2text("path") AS "path"`
|
||||||
|
@ -15,7 +15,7 @@ export default gql`
|
|||||||
createLink(title: String!, url: String): Item!
|
createLink(title: String!, url: String): Item!
|
||||||
createDiscussion(title: String!, text: String): Item!
|
createDiscussion(title: String!, text: String): Item!
|
||||||
createComment(text: String!, parentId: ID!): Item!
|
createComment(text: String!, parentId: ID!): Item!
|
||||||
vote(sats: Int): Int!
|
vote(id: ID!, sats: Int): Int!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Item {
|
type Item {
|
||||||
@ -28,6 +28,7 @@ export default gql`
|
|||||||
user: User!
|
user: User!
|
||||||
depth: Int!
|
depth: Int!
|
||||||
sats: Int!
|
sats: Int!
|
||||||
|
meSats: Int!
|
||||||
ncomments: Int!
|
ncomments: Int!
|
||||||
comments: [Item!]!
|
comments: [Item!]!
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ export default function Comment ({ item, children, replyOpen, includeParent, cac
|
|||||||
<div />
|
<div />
|
||||||
<div>
|
<div>
|
||||||
<div className={`${itemStyles.item} ${styles.item}`}>
|
<div className={`${itemStyles.item} ${styles.item}`}>
|
||||||
<UpVote className={styles.upvote} />
|
<UpVote itemId={item.id} meSats={item.meSats} className={styles.upvote} />
|
||||||
<div className={itemStyles.hunk}>
|
<div className={itemStyles.hunk}>
|
||||||
<div className={itemStyles.other}>
|
<div className={itemStyles.other}>
|
||||||
<Link href={`/${item.user.name}`} passHref>
|
<Link href={`/${item.user.name}`} passHref>
|
||||||
|
@ -20,7 +20,7 @@ export default function Header () {
|
|||||||
<>
|
<>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Link href={'/' + session.user.name} passHref>
|
<Link href={'/' + session.user.name} passHref>
|
||||||
<Nav.Link className='text-reset'>@{session.user.name}</Nav.Link>
|
<Nav.Link>@{session.user.name}</Nav.Link>
|
||||||
</Link>
|
</Link>
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
@ -51,6 +51,9 @@ export default function Header () {
|
|||||||
<Nav.Link>post</Nav.Link>
|
<Nav.Link>post</Nav.Link>
|
||||||
</Link>
|
</Link>
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
|
<Nav.Item>
|
||||||
|
<Nav.Link href='https://bitcoinerjobs.co' target='_blank'>jobs</Nav.Link>
|
||||||
|
</Nav.Item>
|
||||||
</Nav>
|
</Nav>
|
||||||
<Nav className='ml-auto align-items-center' activeKey={router.asPath.split('?')[0]}>
|
<Nav className='ml-auto align-items-center' activeKey={router.asPath.split('?')[0]}>
|
||||||
<Corner />
|
<Corner />
|
||||||
|
@ -13,7 +13,7 @@ export default function Item ({ item, rank, children }) {
|
|||||||
</div>)
|
</div>)
|
||||||
: <div />}
|
: <div />}
|
||||||
<div className={styles.item}>
|
<div className={styles.item}>
|
||||||
<UpVote />
|
<UpVote itemId={item.id} meSats={item.meSats} />
|
||||||
<div className={styles.hunk}>
|
<div className={styles.hunk}>
|
||||||
<div className={`${styles.main} flex-wrap flex-md-nowrap`}>
|
<div className={`${styles.main} flex-wrap flex-md-nowrap`}>
|
||||||
<Link href={`/items/${item.id}`} passHref>
|
<Link href={`/items/${item.id}`} passHref>
|
||||||
|
@ -24,7 +24,7 @@ export default function Reply ({ parentId, onSuccess, cacheId }) {
|
|||||||
cache.modify({
|
cache.modify({
|
||||||
id: cacheId || `Item:${parentId}`,
|
id: cacheId || `Item:${parentId}`,
|
||||||
fields: {
|
fields: {
|
||||||
comments (existingCommentRefs = [], { readField }) {
|
comments (existingCommentRefs = []) {
|
||||||
const newCommentRef = cache.writeFragment({
|
const newCommentRef = cache.writeFragment({
|
||||||
data: createComment,
|
data: createComment,
|
||||||
fragment: COMMENTS,
|
fragment: COMMENTS,
|
||||||
|
@ -1,16 +1,55 @@
|
|||||||
import { LightningConsumer } from './lightning'
|
import { LightningConsumer } from './lightning'
|
||||||
import UpArrow from '../svgs/lightning-arrow.svg'
|
import UpArrow from '../svgs/lightning-arrow.svg'
|
||||||
import styles from './upvote.module.css'
|
import styles from './upvote.module.css'
|
||||||
|
import { gql, useMutation } from '@apollo/client'
|
||||||
|
|
||||||
|
export default function UpVote ({ itemId, meSats, className, item }) {
|
||||||
|
const [vote] = useMutation(
|
||||||
|
gql`
|
||||||
|
mutation vote($id: ID!, $sats: Int!) {
|
||||||
|
vote(id: $id, sats: $sats)
|
||||||
|
}`, {
|
||||||
|
update (cache, { data: { vote } }) {
|
||||||
|
if (item) {
|
||||||
|
item.sats += vote
|
||||||
|
item.meSats += vote
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cache.modify({
|
||||||
|
id: `Item:${itemId}`,
|
||||||
|
fields: {
|
||||||
|
sats (existingSats = 0) {
|
||||||
|
return existingSats + vote
|
||||||
|
},
|
||||||
|
meSats (existingMeSats = 0) {
|
||||||
|
return existingMeSats + vote
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export default function UpVote ({ className }) {
|
|
||||||
return (
|
return (
|
||||||
<LightningConsumer>
|
<LightningConsumer>
|
||||||
{({ strike }) =>
|
{({ strike }) =>
|
||||||
<UpArrow
|
<UpArrow
|
||||||
width={24}
|
width={24}
|
||||||
height={24}
|
height={24}
|
||||||
className={`${styles.upvote} ${className || ''}`}
|
className={
|
||||||
onClick={strike}
|
`${styles.upvote}
|
||||||
|
${className || ''}
|
||||||
|
${meSats ? (meSats > 1 ? styles.stimi : styles.voted) : ''}`
|
||||||
|
}
|
||||||
|
onClick={async () => {
|
||||||
|
if (!itemId) return
|
||||||
|
const { error } = await vote({ variables: { id: itemId, sats: 1 } })
|
||||||
|
if (error) {
|
||||||
|
throw new Error({ message: error.toString() })
|
||||||
|
}
|
||||||
|
|
||||||
|
strike()
|
||||||
|
}}
|
||||||
/>}
|
/>}
|
||||||
</LightningConsumer>
|
</LightningConsumer>
|
||||||
)
|
)
|
||||||
|
@ -8,3 +8,13 @@
|
|||||||
fill: darkgray;
|
fill: darkgray;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.upvote.voted {
|
||||||
|
fill: #F6911D;
|
||||||
|
filter: drop-shadow(0 0 7px #F6911D);
|
||||||
|
}
|
||||||
|
|
||||||
|
.upvote.stimi {
|
||||||
|
fill: #993DF5;
|
||||||
|
filter: drop-shadow(0 0 7px #C28BF9);
|
||||||
|
}
|
@ -10,6 +10,7 @@ export const COMMENT_FIELDS = gql`
|
|||||||
name
|
name
|
||||||
}
|
}
|
||||||
sats
|
sats
|
||||||
|
meSats
|
||||||
ncomments
|
ncomments
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -11,6 +11,7 @@ export const ITEM_FIELDS = gql`
|
|||||||
name
|
name
|
||||||
}
|
}
|
||||||
sats
|
sats
|
||||||
|
meSats
|
||||||
ncomments
|
ncomments
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import { gql } from '@apollo/client'
|
|||||||
import ApolloClient from '../api/client'
|
import ApolloClient from '../api/client'
|
||||||
import UserHeader from '../components/user-header'
|
import UserHeader from '../components/user-header'
|
||||||
|
|
||||||
export async function getServerSideProps ({ params }) {
|
export async function getServerSideProps ({ req, params }) {
|
||||||
const { error, data: { user } } = await ApolloClient.query({
|
const { error, data: { user } } = await (await ApolloClient(req)).query({
|
||||||
query:
|
query:
|
||||||
gql`{
|
gql`{
|
||||||
user(name: "${params.username}") {
|
user(name: "${params.username}") {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import gql from 'graphql-tag'
|
|
||||||
import Item from '../../components/item'
|
import Item from '../../components/item'
|
||||||
import Layout from '../../components/layout'
|
import Layout from '../../components/layout'
|
||||||
import ApolloClient from '../../api/client'
|
import ApolloClient from '../../api/client'
|
||||||
@ -7,23 +6,18 @@ import Comment from '../../components/comment'
|
|||||||
import Text from '../../components/text'
|
import Text from '../../components/text'
|
||||||
import Comments from '../../components/comments'
|
import Comments from '../../components/comments'
|
||||||
import { COMMENTS } from '../../fragments/comments'
|
import { COMMENTS } from '../../fragments/comments'
|
||||||
|
import { ITEM_FIELDS } from '../../fragments/items'
|
||||||
|
import { gql } from '@apollo/client'
|
||||||
|
|
||||||
export async function getServerSideProps ({ params }) {
|
export async function getServerSideProps ({ req, params }) {
|
||||||
const { error, data: { item } } = await ApolloClient.query({
|
const { error, data: { item } } = await (await ApolloClient(req)).query({
|
||||||
query:
|
query:
|
||||||
gql`{
|
gql`
|
||||||
|
${ITEM_FIELDS}
|
||||||
|
{
|
||||||
item(id: ${params.id}) {
|
item(id: ${params.id}) {
|
||||||
id
|
...ItemFields
|
||||||
createdAt
|
|
||||||
title
|
|
||||||
url
|
|
||||||
text
|
text
|
||||||
parentId
|
|
||||||
user {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
sats
|
|
||||||
ncomments
|
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
})
|
})
|
||||||
|
@ -66,7 +66,7 @@ export default function login ({ providers, csrfToken, error }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={`d-block mt-2 ${styles.providerButton}`}
|
className={`mt-2 ${styles.providerButton}`}
|
||||||
key={provider.name}
|
key={provider.name}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
onClick={() => signIn(provider.id)}
|
onClick={() => signIn(provider.id)}
|
||||||
|
26
prisma/migrations/20210426184717_vote/migration.sql
Normal file
26
prisma/migrations/20210426184717_vote/migration.sql
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "item_gist_path_index";
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Vote" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||||
|
"sats" INTEGER NOT NULL,
|
||||||
|
"itemId" INTEGER NOT NULL,
|
||||||
|
"userId" INTEGER NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Vote.itemId_index" ON "Vote"("itemId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Vote.userId_index" ON "Vote"("userId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Vote" ADD FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Vote" ADD FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
3
prisma/migrations/20210426193558_stimi/migration.sql
Normal file
3
prisma/migrations/20210426193558_stimi/migration.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Vote" ADD COLUMN "stimi" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
ALTER COLUMN "sats" SET DEFAULT 1;
|
@ -55,7 +55,8 @@ model Vote {
|
|||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
createdAt DateTime @default(now()) @map(name: "created_at")
|
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||||
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
||||||
sats Int
|
sats Int @default(1)
|
||||||
|
stimi Boolean @default(false)
|
||||||
item Item @relation(fields: [itemId], references: [id])
|
item Item @relation(fields: [itemId], references: [id])
|
||||||
itemId Int
|
itemId Int
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
@ -5,6 +5,7 @@ $theme-colors: (
|
|||||||
"info" : #007cbe,
|
"info" : #007cbe,
|
||||||
"success" : #5c8001,
|
"success" : #5c8001,
|
||||||
"twitter" : #1da1f2,
|
"twitter" : #1da1f2,
|
||||||
|
"boost" : #7A0CE9,
|
||||||
);
|
);
|
||||||
|
|
||||||
$body-bg: #fafafa;
|
$body-bg: #fafafa;
|
||||||
@ -50,6 +51,14 @@ $container-max-widths: (
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-dismissible .close {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.form-control:focus {
|
.form-control:focus {
|
||||||
border-color: #fada5e;
|
border-color: #fada5e;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
.login .providerButton {
|
.login .providerButton {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user