first commit
This commit is contained in:
commit
f74eb98414
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
75
README.md
Normal file
75
README.md
Normal file
@ -0,0 +1,75 @@
|
||||
# Nuxt Minimal Starter
|
||||
|
||||
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
|
||||
# bun
|
||||
bun install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
|
||||
# bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
|
||||
# bun
|
||||
bun run build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
|
||||
# bun
|
||||
bun run preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||
10
app.vue
Normal file
10
app.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<NuxtLoadingIndicator color="#2563eb" :height="4" />
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@import "primeicons/primeicons.css";
|
||||
</style>
|
||||
1
assets/css/main.css
Normal file
1
assets/css/main.css
Normal file
@ -0,0 +1 @@
|
||||
@import "tailwindcss";
|
||||
98
components/CardView.vue
Normal file
98
components/CardView.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<motion.img
|
||||
:src="props.card.url"
|
||||
draggable="false"
|
||||
class="h-[60cqh] max-h-[800px] w-[400px] origin-bottom rounded-lg object-cover hover:cursor-grab active:cursor-grabbing md:w-[600px]"
|
||||
:style="{
|
||||
zIndex: props.isFront ? 10 : props.z,
|
||||
gridRow: 1,
|
||||
gridColumn: 1,
|
||||
transition: '0.125s transform',
|
||||
x,
|
||||
opacity,
|
||||
rotate,
|
||||
boxShadow: isFront
|
||||
? '0 20px 25px -5px rgb(0 0 0 / 0.5), 0 8px 10px -6px rgb(0 0 0 / 0.5)'
|
||||
: undefined,
|
||||
}"
|
||||
alt="Picture of the author"
|
||||
:drag="dragValue"
|
||||
:drag-constraints="{ left: 0, right: 0 }"
|
||||
:on-drag-end="handleDragEnd"
|
||||
:animate="{
|
||||
scale: props.isFront ? 1 : 0.98,
|
||||
}"
|
||||
/>
|
||||
|
||||
<div v-if="props.isFront" class="flex justify-between">
|
||||
<!-- Pass Button -->
|
||||
<button
|
||||
class="mx-12 flex h-24 w-42 flex-col items-center justify-center rounded-xl bg-violet-500 text-4xl text-white shadow-lg transition-colors duration-150 hover:bg-violet-600 focus:ring-4 focus:ring-violet-300 focus:outline-none"
|
||||
aria-label="Pass"
|
||||
type="button"
|
||||
@click="swipeLeft"
|
||||
>
|
||||
<span class="text-base font-semibold">Pass</span>
|
||||
</button>
|
||||
|
||||
<!-- Smash Button -->
|
||||
<button
|
||||
class="mx-12 flex h-24 w-42 flex-col items-center justify-center rounded-xl bg-teal-500 text-4xl text-white shadow-lg transition-colors duration-150 hover:bg-teal-600 focus:ring-4 focus:ring-teal-300 focus:outline-none"
|
||||
aria-label="Smash"
|
||||
type="button"
|
||||
@click="swipeRight"
|
||||
>
|
||||
<span class="text-base font-semibold">Smash</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { animate, motion, useMotionValue, useTransform } from "motion-v";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
import { useCardStore } from "~/store/Card";
|
||||
import type { Card } from "~/types/Card";
|
||||
|
||||
const cardStore = useCardStore();
|
||||
|
||||
const props = defineProps({
|
||||
card: {
|
||||
type: Object as PropType<Card>,
|
||||
required: true,
|
||||
},
|
||||
isFront: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
z: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const dragValue = computed(() => (props.isFront ? "x" : false));
|
||||
|
||||
const x = useMotionValue(0);
|
||||
const opacity = useTransform(x, [-150, 0, 150], [0, 1, 0]);
|
||||
const rotateRaw = useTransform(x, [-150, 150], [-18, 18]);
|
||||
const rotate = useTransform(() => {
|
||||
const offset = props.isFront ? 0 : props.card.id % 2 ? 4 : -4;
|
||||
return `${rotateRaw.get() + offset}deg`;
|
||||
});
|
||||
|
||||
const handleDragEnd = () => {
|
||||
if (Math.abs(x.get()) > 50) {
|
||||
cardStore.removeCard(props.card.id);
|
||||
}
|
||||
};
|
||||
|
||||
async function swipeRight() {
|
||||
await animate(x, 300, { duration: 0.3 });
|
||||
cardStore.removeCard(props.card.id);
|
||||
}
|
||||
async function swipeLeft() {
|
||||
await animate(x, -300, { duration: 0.3 });
|
||||
cardStore.removeCard(props.card.id);
|
||||
}
|
||||
</script>
|
||||
4
eslint.config.mjs
Normal file
4
eslint.config.mjs
Normal file
@ -0,0 +1,4 @@
|
||||
// @ts-check
|
||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||
|
||||
export default withNuxt()
|
||||
0
middleware/auth.ts
Normal file
0
middleware/auth.ts
Normal file
38
nuxt.config.ts
Normal file
38
nuxt.config.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import Aura from "@primeuix/themes/aura";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: "2025-05-15",
|
||||
devtools: { enabled: true },
|
||||
modules: [
|
||||
"@nuxt/eslint",
|
||||
"@nuxt/image",
|
||||
"@nuxt/ui",
|
||||
"@primevue/nuxt-module",
|
||||
"motion-v/nuxt",
|
||||
"@pinia/nuxt",
|
||||
"nuxt-toast",
|
||||
],
|
||||
css: ["~/assets/css/main.css"],
|
||||
vite: { plugins: [tailwindcss()] },
|
||||
app: {
|
||||
baseURL: process.env.BASE_URL || "/",
|
||||
},
|
||||
primevue: {
|
||||
components: {
|
||||
exclude: ["Form", "FormField"],
|
||||
},
|
||||
options: {
|
||||
ripple: true,
|
||||
inputVariant: "filled",
|
||||
theme: {
|
||||
preset: Aura,
|
||||
options: {
|
||||
prefix: "p",
|
||||
darkModeSelector: "system",
|
||||
cssLayer: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
40
package.json
Normal file
40
package.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/eslint": "1.5.2",
|
||||
"@nuxt/image": "1.10.0",
|
||||
"@nuxt/ui": "3.2.0",
|
||||
"@pinia/nuxt": "0.11.1",
|
||||
"@primeuix/themes": "^1.2.1",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.0.0",
|
||||
"izitoast": "^1.4.0",
|
||||
"motion-v": "^1.5.0",
|
||||
"nuxt": "^3.17.6",
|
||||
"nuxt-toast": "1.1.4",
|
||||
"pinia": "^3.0.3",
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.3.6",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"tailwindcss-primeui": "^0.6.1",
|
||||
"typescript": "^5.6.3",
|
||||
"vue": "^3.5.17",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
|
||||
"devDependencies": {
|
||||
"@primevue/nuxt-module": "^4.3.6",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-tailwindcss": "^0.6.14"
|
||||
}
|
||||
}
|
||||
20
pages/game.vue
Normal file
20
pages/game.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div class="grid min-h-screen place-items-center">
|
||||
<CardView
|
||||
v-for="(card, index) in cardStore.cards"
|
||||
:key="card.id"
|
||||
:card="card"
|
||||
:is-front="index === cardStore.cards.length - 1"
|
||||
:z="index"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import CardView from "~/components/CardView.vue";
|
||||
import { useCardStore } from "~/store/Card";
|
||||
|
||||
const route = useRoute();
|
||||
const collection = route.query.collection;
|
||||
const cardStore = useCardStore();
|
||||
</script>
|
||||
94
pages/index.vue
Normal file
94
pages/index.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="flex min-h-screen flex-col items-center justify-center">
|
||||
<h1 class="mb-8 text-3xl font-bold">Select a collection to begin</h1>
|
||||
<ul class="w-full max-w-md space-y-4">
|
||||
<li
|
||||
v-for="collection in cardStore.collections"
|
||||
:key="collection"
|
||||
class="flex items-center justify-between rounded p-4 shadow"
|
||||
>
|
||||
<span class="text-lg font-medium">{{ collection }}</span>
|
||||
<!-- Large Play Button -->
|
||||
<Button
|
||||
icon="pi pi-play"
|
||||
rounded
|
||||
class="flex items-center justify-center bg-blue-600 text-white"
|
||||
:class="{
|
||||
'!h-32 !w-32': activeItem === collection,
|
||||
'!h-16 !w-16': activeItem !== collection,
|
||||
}"
|
||||
style="
|
||||
transition:
|
||||
width 0.3s,
|
||||
height 0.3s;
|
||||
"
|
||||
@click="play(collection)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCardStore } from "~/store/Card";
|
||||
|
||||
const cardStore = useCardStore();
|
||||
|
||||
cardStore.collections = ["Test", "Test1"];
|
||||
|
||||
cardStore.cards = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1542291026-7eec264c27ff?q=80&w=2370&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
|
||||
{
|
||||
id: 2,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1512374382149-233c42b6a83b?q=80&w=2235&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
|
||||
{
|
||||
id: 3,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1539185441755-769473a23570?q=80&w=2342&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
|
||||
{
|
||||
id: 4,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1549298916-b41d501d3772?q=80&w=2224&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
|
||||
{
|
||||
id: 5,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1516478177764-9fe5bd7e9717?q=80&w=2340&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
|
||||
{
|
||||
id: 6,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1570464197285-9949814674a7?q=80&w=2273&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
|
||||
{
|
||||
id: 7,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1578608712688-36b5be8823dc?q=80&w=2187&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
|
||||
{
|
||||
id: 8,
|
||||
name: "Pipi",
|
||||
url: "https://images.unsplash.com/photo-1505784045224-1247b2b29cf3?q=80&w=2340&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
},
|
||||
];
|
||||
|
||||
const activeItem = ref();
|
||||
|
||||
const play = (collection: string) => {
|
||||
navigateTo({ path: "game", query: { collection: collection } });
|
||||
};
|
||||
</script>
|
||||
68
pages/result.vue
Normal file
68
pages/result.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="flex min-h-screen flex-col items-center gap-10">
|
||||
<div class="flex items-start justify-center space-x-8 p-8">
|
||||
<!-- First Grid -->
|
||||
<div class="w-1/2">
|
||||
<h2 class="mb-4 text-xl font-bold">You smashed</h2>
|
||||
<div
|
||||
class="grid grid-cols-1 gap-2 lg:grid-cols-3 xl:grid-cols-5 xl:gap-4"
|
||||
>
|
||||
<div
|
||||
v-for="(img, idx) in imagesListOne"
|
||||
:key="idx"
|
||||
class="flex items-center justify-center rounded p-2 shadow"
|
||||
>
|
||||
<img
|
||||
:src="img"
|
||||
alt="Image from Smash List"
|
||||
class="h-32 w-full rounded object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Second Grid -->
|
||||
<div class="w-1/2">
|
||||
<h2 class="mb-4 text-xl font-bold">You passed</h2>
|
||||
<div
|
||||
class="grid grid-cols-1 gap-2 lg:grid-cols-3 xl:grid-cols-5 xl:gap-4"
|
||||
>
|
||||
<div
|
||||
v-for="(img, idx) in imagesListTwo"
|
||||
:key="idx"
|
||||
class="flex items-center justify-center rounded p-2 shadow"
|
||||
>
|
||||
<img
|
||||
:src="img"
|
||||
alt="Image from pass list"
|
||||
class="h-32 w-full rounded object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button label="Return" class="h-16 w-64" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const imagesListOne = [
|
||||
// Replace with your image URLs
|
||||
"https://picsum.photos/id/1011/200/200",
|
||||
"https://picsum.photos/id/1012/800/400",
|
||||
"https://picsum.photos/id/1013/200/200",
|
||||
"https://picsum.photos/id/1014/200/200",
|
||||
"https://picsum.photos/id/1015/200/200",
|
||||
"https://picsum.photos/id/1016/200/200",
|
||||
// ...more images
|
||||
];
|
||||
|
||||
const imagesListTwo = [
|
||||
"https://picsum.photos/id/1021/200/200",
|
||||
"https://picsum.photos/id/1022/200/200",
|
||||
"https://picsum.photos/id/1023/200/200",
|
||||
"https://picsum.photos/id/1024/200/200",
|
||||
"https://picsum.photos/id/1025/200/200",
|
||||
"https://picsum.photos/id/1026/200/200",
|
||||
// ...more images
|
||||
];
|
||||
</script>
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
2
public/robots.txt
Normal file
2
public/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-Agent: *
|
||||
Disallow:
|
||||
3
server/tsconfig.json
Normal file
3
server/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../.nuxt/tsconfig.server.json"
|
||||
}
|
||||
26
store/Card.ts
Normal file
26
store/Card.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { defineStore } from "pinia";
|
||||
import type { Card } from "~/types/Card";
|
||||
|
||||
export const useCardStore = defineStore("cardStore", {
|
||||
state: () => ({
|
||||
collections: [] as string[],
|
||||
cards: [] as Card[],
|
||||
}),
|
||||
actions: {
|
||||
async fetchCollections() {
|
||||
const { data: collections } =
|
||||
await useFetch<string[]>("/api/collections");
|
||||
this.collections = collections.value ?? [];
|
||||
},
|
||||
async fetchCardsByCollection(collectionName: string) {
|
||||
const response = useFetch<Card[]>(`/api/cards/${collectionName}`);
|
||||
this.cards = response.data.value ?? [];
|
||||
},
|
||||
removeCard(id: number) {
|
||||
const index = this.cards.findIndex((card) => card.id === id);
|
||||
if (index !== -1) {
|
||||
this.cards.splice(index, 1);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
import PrimeUI from 'tailwindcss-primeui';
|
||||
|
||||
export default {
|
||||
content: [],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [PrimeUI],
|
||||
}
|
||||
|
||||
4
tsconfig.json
Normal file
4
tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
5
types/Card.ts
Normal file
5
types/Card.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export type Card = {
|
||||
id: number;
|
||||
url: string;
|
||||
name: string;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user