├── public ├── robots.txt ├── bars.jpg ├── breakfast.jpg ├── restaurant.jpg ├── fonts │ ├── poppins-400.woff2 │ ├── poppins-500.woff2 │ └── poppins-700.woff2 ├── manifest.json └── favicon.svg ├── src ├── routes │ ├── styles.css │ ├── plugin@auth.ts │ ├── service-worker.ts │ ├── admin │ │ └── index.tsx │ ├── index.tsx │ ├── layout.tsx │ └── categories │ │ └── [categoryId] │ │ ├── admin │ │ └── index.tsx │ │ └── index.tsx ├── lib │ ├── prismaClient.ts │ └── openai.ts ├── types.ts ├── global.css ├── entry.dev.tsx ├── entry.preview.tsx ├── components │ ├── header.tsx │ ├── router-head │ │ └── router-head.tsx │ └── answers.tsx ├── entry.ssr.tsx └── root.tsx ├── .env.example ├── prisma ├── dev.db ├── migrations │ ├── migration_lock.toml │ ├── 20230502224256_initial │ │ └── migration.sql │ └── 20230502225713_initial │ │ └── migration.sql ├── schema.prisma └── seed.ts ├── postcss.config.js ├── .vscode └── extensions.json ├── tailwind.config.js ├── vite.config.ts ├── .gitignore ├── .eslintignore ├── .prettierignore ├── tsconfig.json ├── .eslintrc.cjs ├── package.json ├── README.md └── pnpm-lock.yaml /public/robots.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/routes/styles.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | GITHUB_ID= 2 | GITHUB_SECRET= 3 | AUTH_SECRET= 4 | OPENAI_API_KEY= 5 | -------------------------------------------------------------------------------- /prisma/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jherr/qwik-voting/HEAD/prisma/dev.db -------------------------------------------------------------------------------- /public/bars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jherr/qwik-voting/HEAD/public/bars.jpg -------------------------------------------------------------------------------- /public/breakfast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jherr/qwik-voting/HEAD/public/breakfast.jpg -------------------------------------------------------------------------------- /public/restaurant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jherr/qwik-voting/HEAD/public/restaurant.jpg -------------------------------------------------------------------------------- /public/fonts/poppins-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jherr/qwik-voting/HEAD/public/fonts/poppins-400.woff2 -------------------------------------------------------------------------------- /public/fonts/poppins-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jherr/qwik-voting/HEAD/public/fonts/poppins-500.woff2 -------------------------------------------------------------------------------- /public/fonts/poppins-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jherr/qwik-voting/HEAD/public/fonts/poppins-700.woff2 -------------------------------------------------------------------------------- /src/lib/prismaClient.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | export default new PrismaClient(); 4 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type VoteTally = { 2 | questionId: number; 3 | answerId: number; 4 | count: number; 5 | }; 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "unifiedjs.vscode-mdx"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [require("daisyui")], 8 | }; 9 | -------------------------------------------------------------------------------- /src/global.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Tailwind CSS imports 3 | * View the full documentation at https://tailwindcss.com 4 | */ 5 | @tailwind base; 6 | @tailwind components; 7 | @tailwind utilities; 8 | 9 | :root { 10 | background-color: rgb(40,42,54); 11 | } -------------------------------------------------------------------------------- /prisma/migrations/20230502224256_initial/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "User" ( 3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 4 | "email" TEXT NOT NULL, 5 | "name" TEXT 6 | ); 7 | 8 | -- CreateIndex 9 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); 10 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/web-manifest-combined.json", 3 | "name": "qwik-project-name", 4 | "short_name": "Welcome to Qwik", 5 | "start_url": ".", 6 | "display": "standalone", 7 | "background_color": "#fff", 8 | "description": "A Qwik project app." 9 | } 10 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import { qwikVite } from '@builder.io/qwik/optimizer'; 3 | import { qwikCity } from '@builder.io/qwik-city/vite'; 4 | import tsconfigPaths from 'vite-tsconfig-paths'; 5 | 6 | export default defineConfig(() => { 7 | return { 8 | optimizeDeps: { 9 | include: ['@auth/core'], 10 | }, 11 | plugins: [qwikCity(), qwikVite(), tsconfigPaths()], 12 | preview: { 13 | headers: { 14 | 'Cache-Control': 'public, max-age=600', 15 | }, 16 | }, 17 | }; 18 | }); 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build 2 | /dist 3 | /lib 4 | /lib-types 5 | /server 6 | 7 | .env 8 | 9 | # Development 10 | node_modules 11 | *.local 12 | 13 | # Cache 14 | .cache 15 | .mf 16 | .rollup.cache 17 | tsconfig.tsbuildinfo 18 | 19 | # Logs 20 | logs 21 | *.log 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | pnpm-debug.log* 26 | lerna-debug.log* 27 | 28 | # Editor 29 | .vscode/* 30 | !.vscode/extensions.json 31 | .idea 32 | .DS_Store 33 | *.suo 34 | *.ntvs* 35 | *.njsproj 36 | *.sln 37 | *.sw? 38 | 39 | # Yarn 40 | .yarn/* 41 | !.yarn/releases 42 | -------------------------------------------------------------------------------- /src/routes/plugin@auth.ts: -------------------------------------------------------------------------------- 1 | import { serverAuth$ } from '@builder.io/qwik-auth'; 2 | import GitHub from '@auth/core/providers/github'; 3 | import type { Provider } from '@auth/core/providers'; 4 | 5 | export const { onRequest, useAuthSession, useAuthSignin, useAuthSignout } = serverAuth$( 6 | ({ env }) => ({ 7 | secret: env.get('AUTH_SECRET'), 8 | trustHost: true, 9 | providers: [ 10 | GitHub({ 11 | clientId: env.get('GITHUB_ID')!, 12 | clientSecret: env.get('GITHUB_SECRET')!, 13 | }), 14 | ] as Provider[], 15 | }) 16 | ); 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.log 2 | **/.DS_Store 3 | *. 4 | .vscode/settings.json 5 | .history 6 | .yarn 7 | bazel-* 8 | bazel-bin 9 | bazel-out 10 | bazel-qwik 11 | bazel-testlogs 12 | dist 13 | dist-dev 14 | lib 15 | lib-types 16 | etc 17 | external 18 | node_modules 19 | temp 20 | tsc-out 21 | tsdoc-metadata.json 22 | target 23 | output 24 | rollup.config.js 25 | build 26 | .cache 27 | .vscode 28 | .rollup.cache 29 | dist 30 | tsconfig.tsbuildinfo 31 | vite.config.ts 32 | *.spec.tsx 33 | *.spec.ts 34 | .netlify 35 | pnpm-lock.yaml 36 | package-lock.json 37 | yarn.lock 38 | server 39 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.log 2 | **/.DS_Store 3 | *. 4 | .vscode/settings.json 5 | .history 6 | .yarn 7 | bazel-* 8 | bazel-bin 9 | bazel-out 10 | bazel-qwik 11 | bazel-testlogs 12 | dist 13 | dist-dev 14 | lib 15 | lib-types 16 | etc 17 | external 18 | node_modules 19 | temp 20 | tsc-out 21 | tsdoc-metadata.json 22 | target 23 | output 24 | rollup.config.js 25 | build 26 | .cache 27 | .vscode 28 | .rollup.cache 29 | dist 30 | tsconfig.tsbuildinfo 31 | vite.config.ts 32 | *.spec.tsx 33 | *.spec.ts 34 | .netlify 35 | pnpm-lock.yaml 36 | package-lock.json 37 | yarn.lock 38 | server 39 | -------------------------------------------------------------------------------- /src/entry.dev.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * WHAT IS THIS FILE? 3 | * 4 | * Development entry point using only client-side modules: 5 | * - Do not use this mode in production! 6 | * - No SSR 7 | * - No portion of the application is pre-rendered on the server. 8 | * - All of the application is running eagerly in the browser. 9 | * - More code is transferred to the browser than in SSR mode. 10 | * - Optimizer/Serialization/Deserialization code is not exercised! 11 | */ 12 | import { render, type RenderOptions } from '@builder.io/qwik'; 13 | import Root from './root'; 14 | 15 | export default function (opts: RenderOptions) { 16 | return render(document, , opts); 17 | } 18 | -------------------------------------------------------------------------------- /src/entry.preview.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * WHAT IS THIS FILE? 3 | * 4 | * It's the bundle entry point for `npm run preview`. 5 | * That is, serving your app built in production mode. 6 | * 7 | * Feel free to modify this file, but don't remove it! 8 | * 9 | * Learn more about Vite's preview command: 10 | * - https://vitejs.dev/config/preview-options.html#preview-options 11 | * 12 | */ 13 | import { createQwikCity } from '@builder.io/qwik-city/middleware/node'; 14 | import qwikCityPlan from '@qwik-city-plan'; 15 | import render from './entry.ssr'; 16 | 17 | /** 18 | * The default export is the QwikCity adapter used by Vite preview. 19 | */ 20 | export default createQwikCity({ render, qwikCityPlan }); 21 | -------------------------------------------------------------------------------- /src/routes/service-worker.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * WHAT IS THIS FILE? 3 | * 4 | * The service-worker.ts file is used to have state of the art prefetching. 5 | * https://qwik.builder.io/qwikcity/prefetching/overview/ 6 | * 7 | * Qwik uses a service worker to speed up your site and reduce latency, ie, not used in the traditional way of offline. 8 | * You can also use this file to add more functionality that runs in the service worker. 9 | */ 10 | import { setupServiceWorker } from '@builder.io/qwik-city/service-worker'; 11 | 12 | setupServiceWorker(); 13 | 14 | addEventListener('install', () => self.skipWaiting()); 15 | 16 | addEventListener('activate', () => self.clients.claim()); 17 | 18 | declare const self: ServiceWorkerGlobalScope; 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "target": "ES2017", 5 | "module": "ES2022", 6 | "lib": ["es2022", "DOM", "WebWorker", "DOM.Iterable"], 7 | "jsx": "react-jsx", 8 | "jsxImportSource": "@builder.io/qwik", 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "resolveJsonModule": true, 12 | "moduleResolution": "node", 13 | "esModuleInterop": true, 14 | "skipLibCheck": true, 15 | "incremental": true, 16 | "isolatedModules": true, 17 | "outDir": "tmp", 18 | "noEmit": true, 19 | "types": ["node", "vite/client"], 20 | "paths": { 21 | "~/*": ["./src/*"] 22 | } 23 | }, 24 | "files": ["./.eslintrc.cjs"], 25 | "include": ["src", "./*.d.ts"] 26 | } 27 | -------------------------------------------------------------------------------- /src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { component$ } from "@builder.io/qwik"; 2 | import { Form } from "@builder.io/qwik-city"; 3 | 4 | import { 5 | useAuthSession, 6 | useAuthSignin, 7 | useAuthSignout, 8 | } from "~/routes/plugin@auth"; 9 | 10 | export default component$(() => { 11 | const session = useAuthSession(); 12 | const signIn = useAuthSignin(); 13 | const signOut = useAuthSignout(); 14 | 15 | return ( 16 |
17 |
18 | {session.value?.user?.email ? ( 19 |
20 | 21 |
22 | ) : ( 23 |
24 | 25 |
26 | )} 27 |
28 | ); 29 | }); 30 | -------------------------------------------------------------------------------- /src/entry.ssr.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * WHAT IS THIS FILE? 3 | * 4 | * SSR entry point, in all cases the application is render outside the browser, this 5 | * entry point will be the common one. 6 | * 7 | * - Server (express, cloudflare...) 8 | * - npm run start 9 | * - npm run preview 10 | * - npm run build 11 | * 12 | */ 13 | import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server'; 14 | import { manifest } from '@qwik-client-manifest'; 15 | import Root from './root'; 16 | 17 | export default function (opts: RenderToStreamOptions) { 18 | return renderToStream(, { 19 | manifest, 20 | ...opts, 21 | // Use container attributes to set attributes on the html tag. 22 | containerAttributes: { 23 | lang: 'en-us', 24 | ...opts.containerAttributes, 25 | }, 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/lib/openai.ts: -------------------------------------------------------------------------------- 1 | import { Configuration, OpenAIApi } from "openai"; 2 | 3 | let openai:OpenAIApi | null = null; 4 | if (process.env.OPENAI_API_KEY) { 5 | const configuration = new Configuration({ 6 | apiKey: process.env.OPENAI_API_KEY, 7 | }); 8 | openai = new OpenAIApi(configuration); 9 | } 10 | 11 | const creteThankYouNote = async (question: string, answer: string) => { 12 | if(openai) { 13 | const completion = await openai.createCompletion({ 14 | max_tokens: 64, 15 | temperature: 0.9, 16 | model: "text-davinci-003", 17 | prompt: `Give a short snarky thank you to a person registering a vote in a poll.\nQuestion was: ${question}\nAnswer was: ${answer}`, 18 | }); 19 | return completion.data.choices[0].text?.replace(/^"/m, "").replace(/"$/m, ""); 20 | } 21 | return "Thank you for voting!" 22 | } 23 | 24 | export default creteThankYouNote; 25 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/root.tsx: -------------------------------------------------------------------------------- 1 | import { component$ } from "@builder.io/qwik"; 2 | import { 3 | QwikCityProvider, 4 | RouterOutlet, 5 | ServiceWorkerRegister, 6 | } from "@builder.io/qwik-city"; 7 | import { RouterHead } from "./components/router-head/router-head"; 8 | 9 | import "./global.css"; 10 | 11 | export default component$(() => { 12 | /** 13 | * The root of a QwikCity site always start with the component, 14 | * immediately followed by the document's and . 15 | * 16 | * Dont remove the `` and `` elements. 17 | */ 18 | 19 | return ( 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | }); 33 | -------------------------------------------------------------------------------- /src/components/router-head/router-head.tsx: -------------------------------------------------------------------------------- 1 | import { component$ } from '@builder.io/qwik'; 2 | import { useDocumentHead, useLocation } from '@builder.io/qwik-city'; 3 | 4 | /** 5 | * The RouterHead component is placed inside of the document `` element. 6 | */ 7 | export const RouterHead = component$(() => { 8 | const head = useDocumentHead(); 9 | const loc = useLocation(); 10 | 11 | return ( 12 | <> 13 | {head.title} 14 | 15 | 16 | 17 | 18 | 19 | {head.meta.map((m) => ( 20 | 21 | ))} 22 | 23 | {head.links.map((l) => ( 24 | 25 | ))} 26 | 27 | {head.styles.map((s) => ( 28 |