attempts at voting before running into cache issues
This commit is contained in:
		
							parent
							
								
									900b70da77
								
							
						
					
					
						commit
						c626998952
					
				@ -6,23 +6,22 @@ import resolvers from './resolvers'
 | 
			
		||||
import typeDefs from './typeDefs'
 | 
			
		||||
import models from './models'
 | 
			
		||||
 | 
			
		||||
const client = new ApolloClient({
 | 
			
		||||
  ssrMode: true,
 | 
			
		||||
  // Instead of "createHttpLink" use SchemaLink here
 | 
			
		||||
  link: new SchemaLink({
 | 
			
		||||
    schema: mergeSchemas({
 | 
			
		||||
      schemas: typeDefs,
 | 
			
		||||
      resolvers: resolvers
 | 
			
		||||
    }),
 | 
			
		||||
    context: async ({ req }) => {
 | 
			
		||||
      const session = await getSession({ req })
 | 
			
		||||
      return {
 | 
			
		||||
export default async function serverSideClient (req) {
 | 
			
		||||
  const session = await getSession({ req })
 | 
			
		||||
  console.log(session)
 | 
			
		||||
  return new ApolloClient({
 | 
			
		||||
    ssrMode: true,
 | 
			
		||||
    // Instead of "createHttpLink" use SchemaLink here
 | 
			
		||||
    link: new SchemaLink({
 | 
			
		||||
      schema: mergeSchemas({
 | 
			
		||||
        schemas: typeDefs,
 | 
			
		||||
        resolvers: resolvers
 | 
			
		||||
      }),
 | 
			
		||||
      context: {
 | 
			
		||||
        models,
 | 
			
		||||
        me: session ? session.user : null
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }),
 | 
			
		||||
  cache: new InMemoryCache()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default client
 | 
			
		||||
    }),
 | 
			
		||||
    cache: new InMemoryCache()
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,64 +1,5 @@
 | 
			
		||||
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 {
 | 
			
		||||
  Query: {
 | 
			
		||||
    items: async (parent, args, { models }) => {
 | 
			
		||||
@ -142,6 +83,29 @@ export default {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      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}`
 | 
			
		||||
      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!
 | 
			
		||||
    createDiscussion(title: String!, text: String): Item!
 | 
			
		||||
    createComment(text: String!, parentId: ID!): Item!
 | 
			
		||||
    vote(sats: Int): Int!
 | 
			
		||||
    vote(id: ID!, sats: Int): Int!
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  type Item {
 | 
			
		||||
@ -28,6 +28,7 @@ export default gql`
 | 
			
		||||
    user: User!
 | 
			
		||||
    depth: Int!
 | 
			
		||||
    sats: Int!
 | 
			
		||||
    meSats: Int!
 | 
			
		||||
    ncomments: Int!
 | 
			
		||||
    comments: [Item!]!
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ export default function Comment ({ item, children, replyOpen, includeParent, cac
 | 
			
		||||
      <div />
 | 
			
		||||
      <div>
 | 
			
		||||
        <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.other}>
 | 
			
		||||
              <Link href={`/${item.user.name}`} passHref>
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ export default function Header () {
 | 
			
		||||
        <>
 | 
			
		||||
          <Nav.Item>
 | 
			
		||||
            <Link href={'/' + session.user.name} passHref>
 | 
			
		||||
              <Nav.Link className='text-reset'>@{session.user.name}</Nav.Link>
 | 
			
		||||
              <Nav.Link>@{session.user.name}</Nav.Link>
 | 
			
		||||
            </Link>
 | 
			
		||||
          </Nav.Item>
 | 
			
		||||
          <Nav.Item>
 | 
			
		||||
@ -51,6 +51,9 @@ export default function Header () {
 | 
			
		||||
                <Nav.Link>post</Nav.Link>
 | 
			
		||||
              </Link>
 | 
			
		||||
            </Nav.Item>
 | 
			
		||||
            <Nav.Item>
 | 
			
		||||
              <Nav.Link href='https://bitcoinerjobs.co' target='_blank'>jobs</Nav.Link>
 | 
			
		||||
            </Nav.Item>
 | 
			
		||||
          </Nav>
 | 
			
		||||
          <Nav className='ml-auto align-items-center' activeKey={router.asPath.split('?')[0]}>
 | 
			
		||||
            <Corner />
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ export default function Item ({ item, rank, children }) {
 | 
			
		||||
          </div>)
 | 
			
		||||
        : <div />}
 | 
			
		||||
      <div className={styles.item}>
 | 
			
		||||
        <UpVote />
 | 
			
		||||
        <UpVote itemId={item.id} meSats={item.meSats} />
 | 
			
		||||
        <div className={styles.hunk}>
 | 
			
		||||
          <div className={`${styles.main} flex-wrap flex-md-nowrap`}>
 | 
			
		||||
            <Link href={`/items/${item.id}`} passHref>
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ export default function Reply ({ parentId, onSuccess, cacheId }) {
 | 
			
		||||
        cache.modify({
 | 
			
		||||
          id: cacheId || `Item:${parentId}`,
 | 
			
		||||
          fields: {
 | 
			
		||||
            comments (existingCommentRefs = [], { readField }) {
 | 
			
		||||
            comments (existingCommentRefs = []) {
 | 
			
		||||
              const newCommentRef = cache.writeFragment({
 | 
			
		||||
                data: createComment,
 | 
			
		||||
                fragment: COMMENTS,
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,55 @@
 | 
			
		||||
import { LightningConsumer } from './lightning'
 | 
			
		||||
import UpArrow from '../svgs/lightning-arrow.svg'
 | 
			
		||||
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 (
 | 
			
		||||
    <LightningConsumer>
 | 
			
		||||
      {({ strike }) =>
 | 
			
		||||
        <UpArrow
 | 
			
		||||
          width={24}
 | 
			
		||||
          height={24}
 | 
			
		||||
          className={`${styles.upvote} ${className || ''}`}
 | 
			
		||||
          onClick={strike}
 | 
			
		||||
          className={
 | 
			
		||||
            `${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>
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
@ -8,3 +8,13 @@
 | 
			
		||||
    fill: darkgray;
 | 
			
		||||
    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
 | 
			
		||||
    }
 | 
			
		||||
    sats
 | 
			
		||||
    meSats
 | 
			
		||||
    ncomments
 | 
			
		||||
  }
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@ export const ITEM_FIELDS = gql`
 | 
			
		||||
      name
 | 
			
		||||
    }
 | 
			
		||||
    sats
 | 
			
		||||
    meSats
 | 
			
		||||
    ncomments
 | 
			
		||||
  }`
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,8 @@ import { gql } from '@apollo/client'
 | 
			
		||||
import ApolloClient from '../api/client'
 | 
			
		||||
import UserHeader from '../components/user-header'
 | 
			
		||||
 | 
			
		||||
export async function getServerSideProps ({ params }) {
 | 
			
		||||
  const { error, data: { user } } = await ApolloClient.query({
 | 
			
		||||
export async function getServerSideProps ({ req, params }) {
 | 
			
		||||
  const { error, data: { user } } = await (await ApolloClient(req)).query({
 | 
			
		||||
    query:
 | 
			
		||||
      gql`{
 | 
			
		||||
        user(name: "${params.username}") {
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
import gql from 'graphql-tag'
 | 
			
		||||
import Item from '../../components/item'
 | 
			
		||||
import Layout from '../../components/layout'
 | 
			
		||||
import ApolloClient from '../../api/client'
 | 
			
		||||
@ -7,23 +6,18 @@ import Comment from '../../components/comment'
 | 
			
		||||
import Text from '../../components/text'
 | 
			
		||||
import Comments from '../../components/comments'
 | 
			
		||||
import { COMMENTS } from '../../fragments/comments'
 | 
			
		||||
import { ITEM_FIELDS } from '../../fragments/items'
 | 
			
		||||
import { gql } from '@apollo/client'
 | 
			
		||||
 | 
			
		||||
export async function getServerSideProps ({ params }) {
 | 
			
		||||
  const { error, data: { item } } = await ApolloClient.query({
 | 
			
		||||
export async function getServerSideProps ({ req, params }) {
 | 
			
		||||
  const { error, data: { item } } = await (await ApolloClient(req)).query({
 | 
			
		||||
    query:
 | 
			
		||||
      gql`{
 | 
			
		||||
      gql`
 | 
			
		||||
      ${ITEM_FIELDS}
 | 
			
		||||
      {
 | 
			
		||||
        item(id: ${params.id}) {
 | 
			
		||||
          id
 | 
			
		||||
          createdAt
 | 
			
		||||
          title
 | 
			
		||||
          url
 | 
			
		||||
          ...ItemFields
 | 
			
		||||
          text
 | 
			
		||||
          parentId
 | 
			
		||||
          user {
 | 
			
		||||
            name
 | 
			
		||||
          }
 | 
			
		||||
          sats
 | 
			
		||||
          ncomments
 | 
			
		||||
        }
 | 
			
		||||
      }`
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ export default function login ({ providers, csrfToken, error }) {
 | 
			
		||||
 | 
			
		||||
            return (
 | 
			
		||||
              <Button
 | 
			
		||||
                className={`d-block mt-2 ${styles.providerButton}`}
 | 
			
		||||
                className={`mt-2 ${styles.providerButton}`}
 | 
			
		||||
                key={provider.name}
 | 
			
		||||
                variant={variant}
 | 
			
		||||
                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())
 | 
			
		||||
  createdAt DateTime @default(now()) @map(name: "created_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])
 | 
			
		||||
  itemId    Int
 | 
			
		||||
  user      User     @relation(fields: [userId], references: [id])
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ $theme-colors: (
 | 
			
		||||
  "info" : #007cbe,
 | 
			
		||||
  "success" : #5c8001,
 | 
			
		||||
  "twitter" : #1da1f2,
 | 
			
		||||
  "boost" : #7A0CE9,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
$body-bg: #fafafa;
 | 
			
		||||
@ -50,6 +51,14 @@ $container-max-widths: (
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.alert-dismissible .close {
 | 
			
		||||
  font-weight: 300;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.nav-item {
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-control:focus {
 | 
			
		||||
  border-color: #fada5e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,8 @@
 | 
			
		||||
.login .providerButton {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user