This file is a merged representation of the entire codebase, combining all repository files into a single document.
Generated by Repopack on: 2024-12-28T11:29:37.323Z
================================================================
File Summary
================================================================
Purpose:
--------
This file contains a packed representation of the entire repository's contents.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.
File Format:
------------
The content is organized as follows:
1. This summary section
2. Repository information
3. Repository structure
4. Multiple file entries, each consisting of:
a. A separator line (================)
b. The file path (File: path/to/file)
c. Another separator line
d. The full contents of the file
e. A blank line
Usage Guidelines:
-----------------
- This file should be treated as read-only. Any changes should be made to the
original repository files, not this packed version.
- When processing this file, use the file path to distinguish
between different files in the repository.
- Be aware that this file may contain sensitive information. Handle it with
the same level of security as you would the original repository.
Notes:
------
- Some files may have been excluded based on .gitignore rules and Repopack's
configuration.
- Binary files are not included in this packed representation. Please refer to
the Repository Structure section for a complete list of file paths, including
binary files.
Additional Info:
----------------
For more information about Repopack, visit: https://github.com/yamadashy/repopack
================================================================
Repository Structure
================================================================
.gitignore
.npmrc
.prettierignore
.prettierrc
components.json
eslint.config.js
jsconfig.json
messages/al.json
messages/en.json
package.json
postcss.config.js
prisma/schema.prisma
project.inlang/.gitignore
project.inlang/settings.json
README.md
src/app.css
src/app.html
src/hooks.js
src/hooks.server.js
src/lib/components/admin-navbar.svelte
src/lib/components/brand-modal.svelte
src/lib/components/FeedbackModal.svelte
src/lib/components/game-card.svelte
src/lib/components/GameFeedbackModal.svelte
src/lib/components/games/ScoreIndicator.svelte
src/lib/components/games/VictoryModal.svelte
src/lib/components/navbar.svelte
src/lib/components/screensaver.svelte
src/lib/components/ui/accordion/accordion-content.svelte
src/lib/components/ui/accordion/accordion-item.svelte
src/lib/components/ui/accordion/accordion-trigger.svelte
src/lib/components/ui/accordion/index.js
src/lib/components/ui/badge/badge.svelte
src/lib/components/ui/badge/index.js
src/lib/components/ui/button/button.svelte
src/lib/components/ui/button/index.js
src/lib/components/ui/calendar/calendar-cell.svelte
src/lib/components/ui/calendar/calendar-day.svelte
src/lib/components/ui/calendar/calendar-grid-body.svelte
src/lib/components/ui/calendar/calendar-grid-head.svelte
src/lib/components/ui/calendar/calendar-grid-row.svelte
src/lib/components/ui/calendar/calendar-grid.svelte
src/lib/components/ui/calendar/calendar-head-cell.svelte
src/lib/components/ui/calendar/calendar-header.svelte
src/lib/components/ui/calendar/calendar-heading.svelte
src/lib/components/ui/calendar/calendar-months.svelte
src/lib/components/ui/calendar/calendar-next-button.svelte
src/lib/components/ui/calendar/calendar-prev-button.svelte
src/lib/components/ui/calendar/calendar.svelte
src/lib/components/ui/calendar/index.js
src/lib/components/ui/card/card-content.svelte
src/lib/components/ui/card/card-description.svelte
src/lib/components/ui/card/card-footer.svelte
src/lib/components/ui/card/card-header.svelte
src/lib/components/ui/card/card-title.svelte
src/lib/components/ui/card/card.svelte
src/lib/components/ui/card/index.js
src/lib/components/ui/checkbox/checkbox.svelte
src/lib/components/ui/checkbox/index.js
src/lib/components/ui/date-range-picker/index.svelte
src/lib/components/ui/dialog/dialog-content.svelte
src/lib/components/ui/dialog/dialog-description.svelte
src/lib/components/ui/dialog/dialog-footer.svelte
src/lib/components/ui/dialog/dialog-header.svelte
src/lib/components/ui/dialog/dialog-overlay.svelte
src/lib/components/ui/dialog/dialog-portal.svelte
src/lib/components/ui/dialog/dialog-title.svelte
src/lib/components/ui/dialog/index.js
src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte
src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte
src/lib/components/ui/dropdown-menu/index.js
src/lib/components/ui/input/index.js
src/lib/components/ui/input/input.svelte
src/lib/components/ui/label/index.js
src/lib/components/ui/label/label.svelte
src/lib/components/ui/popover/index.js
src/lib/components/ui/popover/popover-content.svelte
src/lib/components/ui/select/index.js
src/lib/components/ui/select/select-content.svelte
src/lib/components/ui/select/select-item.svelte
src/lib/components/ui/select/select-label.svelte
src/lib/components/ui/select/select-separator.svelte
src/lib/components/ui/select/select-trigger.svelte
src/lib/components/ui/separator/index.js
src/lib/components/ui/separator/separator.svelte
src/lib/components/ui/table/index.js
src/lib/components/ui/table/table-body.svelte
src/lib/components/ui/table/table-caption.svelte
src/lib/components/ui/table/table-cell.svelte
src/lib/components/ui/table/table-footer.svelte
src/lib/components/ui/table/table-head.svelte
src/lib/components/ui/table/table-header.svelte
src/lib/components/ui/table/table-row.svelte
src/lib/components/ui/table/table.svelte
src/lib/components/ui/textarea/index.js
src/lib/components/ui/textarea/textarea.svelte
src/lib/components/ui/toggle/index.js
src/lib/components/ui/toggle/toggle.svelte
src/lib/components/ui/tooltip/index.js
src/lib/components/ui/tooltip/tooltip-content.svelte
src/lib/i18n.js
src/lib/stores/feedbackStore.js
src/lib/stores/formEditorStore.js
src/lib/stores/gameStore.js
src/lib/stores/score.js
src/lib/stores/screensaver.js
src/lib/stores/sessionStore.js
src/lib/stores/theme.js
src/lib/utils.js
src/routes/+layout.svelte
src/routes/+page.svelte
src/routes/admin/+layout.svelte
src/routes/admin/+page.svelte
src/routes/admin/feedback/+page.svelte
src/routes/admin/form-editor/+page.svelte
src/routes/admin/login/+page.svelte
src/routes/admin/users/+page.svelte
src/routes/games/+layout.svelte
src/routes/games/pairs/+page.svelte
src/routes/games/puzzle/+page.svelte
src/routes/games/race/+page.svelte
src/routes/games/trivia/+page.svelte
src/routes/leaderboard/+page.svelte
src/routes/login/+page.svelte
svelte.config.js
tailwind.config.js
vite.config.js
================================================================
Repository Files
================================================================
================
File: .gitignore
================
node_modules
# Output
.output
.vercel
.netlify
.wrangler
/.svelte-kit
/build
# OS
.DS_Store
Thumbs.db
# Env
.env
.env.*
!.env.example
!.env.test
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# Paraglide
src/lib/paraglide
# windsurf rules
.windsurfrules
================
File: .npmrc
================
engine-strict=true
================
File: .prettierignore
================
# Package Managers
package-lock.json
pnpm-lock.yaml
yarn.lock
================
File: .prettierrc
================
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"overrides": [
{
"files": "*.svelte",
"options": {
"parser": "svelte"
}
}
]
}
================
File: components.json
================
{
"$schema": "https://shadcn-svelte.com/schema.json",
"style": "new-york",
"tailwind": {
"config": "tailwind.config.js",
"css": "src\\app.css",
"baseColor": "slate"
},
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils"
},
"typescript": false
}
================
File: eslint.config.js
================
import prettier from 'eslint-config-prettier';
import js from '@eslint/js';
import { includeIgnoreFile } from '@eslint/compat';
import svelte from 'eslint-plugin-svelte';
import globals from 'globals';
import { fileURLToPath } from 'node:url';
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
/** @type {import('eslint').Linter.Config[]} */
export default [
includeIgnoreFile(gitignorePath),
js.configs.recommended,
...svelte.configs['flat/recommended'],
prettier,
...svelte.configs['flat/prettier'],
{
languageOptions: {
globals: {
...globals.browser,
...globals.node
}
}
}
];
================
File: jsconfig.json
================
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}
================
File: messages/al.json
================
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"hello_world": "Hello, {name} from al!"
}
================
File: messages/en.json
================
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"hello_world": "Hello, {name} from en!"
}
================
File: package.json
================
{
"name": "poalai",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"format": "prettier --write .",
"lint": "prettier --check . && eslint ."
},
"devDependencies": {
"@eslint/compat": "^1.2.3",
"@internationalized/date": "^3.6.0",
"@prisma/client": "^6.1.0",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.9.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"autoprefixer": "^10.4.20",
"bits-ui": "^0.21.16",
"clsx": "^2.1.1",
"eslint": "^9.7.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0",
"globals": "^15.0.0",
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.6",
"prettier-plugin-tailwindcss": "^0.6.5",
"prisma": "^6.1.0",
"svelte": "^5.0.0",
"tailwind-merge": "^2.5.5",
"tailwind-variants": "^0.3.0",
"tailwindcss": "^3.4.9",
"vite": "^6.0.0"
},
"dependencies": {
"@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.1",
"@inlang/paraglide-sveltekit": "^0.11.1",
"@radix-ui/colors": "^3.0.0",
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
"bcrypt": "^5.1.1",
"better-sqlite3": "^11.7.0",
"canvas-confetti": "^1.9.3",
"date-fns": "^4.1.0",
"lucide-svelte": "^0.469.0",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7",
"svelte-dnd-action": "^0.9.53",
"svelte-fa": "^4.0.3",
"svelte-radix": "^2.0.1",
"xlsx": "^0.18.5",
"zod": "^3.24.1"
}
}
================
File: postcss.config.js
================
export default {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};
================
File: prisma/schema.prisma
================
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("./dev.sqlite")
}
================
File: project.inlang/.gitignore
================
cache
================
File: project.inlang/settings.json
================
{
"$schema": "https://inlang.com/schema/project-settings",
"modules": [
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-valid-js-identifier@1/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@2/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@0/dist/index.js"
],
"plugin.inlang.messageFormat": {
"pathPattern": "./messages/{languageTag}.json"
},
"sourceLanguageTag": "en",
"languageTags": ["en", "al"]
}
================
File: README.md
================
# sv
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npx sv create
# create a new project in my-app
npx sv create my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
================
File: src/app.css
================
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 40 33% 98%;
--foreground: 20 14.3% 4.1%;
--card: 40 30% 96%;
--card-foreground: 20 14.3% 4.1%;
--popover: 40 33% 98%;
--popover-foreground: 20 14.3% 4.1%;
--primary: 24 9.8% 10%;
--primary-foreground: 40 33% 98%;
--secondary: 40 30% 96%;
--secondary-foreground: 24 9.8% 10%;
--muted: 40 30% 96%;
--muted-foreground: 25 5.3% 44.7%;
--accent: 40 30% 96%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 40 33% 98%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 5%; /* Slightly lighter black */
--foreground: 210 40% 98%;
--card: 0 0% 15%; /* Slightly lighter black */
--card-foreground: 210 40% 98%;
--popover: 0 0% 15%; /* Slightly lighter black */
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground transition-colors duration-300;
overflow:hidden
}
.light body {
@apply bg-[#FAF8F3];
}
.dark body {
@apply bg-[#131313];
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Better mobile tap targets */
@media (max-width: 640px) {
button, a {
@apply min-h-[44px] min-w-[44px];
}
}
}
/* Custom styles */
.game-card {
@apply relative overflow-hidden rounded-lg transition-all duration-300;
aspect-ratio: 3/4;
background: linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0.8));
}
.game-card:hover {
transform: scale(1.02);
}
.game-card::before {
content: '';
@apply absolute inset-0 bg-black/40 transition-opacity duration-300;
}
.game-card:hover::before {
@apply opacity-20;
}
.game-card img {
@apply absolute inset-0 w-full h-full object-cover transition-transform duration-300;
}
.game-card:hover img {
transform: scale(1.1);
}
.game-card-content {
@apply absolute inset-x-0 bottom-0 p-4 text-white text-center;
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
}
/* Custom animations */
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
/* Card hover effects */
.card-hover {
@apply transition-all duration-300 hover:shadow-lg hover:-translate-y-1;
}
/* Game grid responsive layout */
.game-grid {
@apply grid gap-6;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
/* Responsive table */
.responsive-table {
@apply w-full overflow-x-auto;
}
/* Custom scrollbar */
@media (min-width: 640px) {
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
@apply bg-muted;
}
::-webkit-scrollbar-thumb {
@apply bg-primary/50 rounded-full;
}
::-webkit-scrollbar-thumb:hover {
@apply bg-primary;
}
}
================
File: src/app.html
================
%sveltekit.head%
%sveltekit.body%
================
File: src/hooks.js
================
import { i18n } from '$lib/i18n';
export const reroute = i18n.reroute();
================
File: src/hooks.server.js
================
import { i18n } from '$lib/i18n';
const handleParaglide = i18n.handle();
export const handle = handleParaglide;
================
File: src/lib/components/admin-navbar.svelte
================
{#if !isLoginPage}
Panel Administratori
{#each navItems as item}
goto(item.href)}
>
{@html item.icon}
{item.title}
{#if $page.url.pathname === item.href}
{/if}
{/each}
Dil
{/if}
================
File: src/lib/components/brand-modal.svelte
================
{#if show}
Shto Markë të Re
{#if error}
{error}
{/if}
ID i Markës
Emri i Markës
Logo e Markës
{#if previewUrl}
{
previewUrl = '';
if (fileInput) fileInput.value = '';
}}
>
{:else}
{#if isUploading}
Duke ngarkuar...
{:else}
Kliko për të ngarkuar logon
{/if}
{/if}
Anulo
Shto
{/if}
================
File: src/lib/components/FeedbackModal.svelte
================
{#if show}
!inGameMode && (show = false)}>
Formulari i Feedback-ut
{#if !inGameMode}
show = false}
>
{/if}
{/if}
================
File: src/lib/components/game-card.svelte
================
e.key === 'Enter' && handleClick()}>
{title}
================
File: src/lib/components/GameFeedbackModal.svelte
================
{#if show && $feedbackStore.currentRound % 2 === 1 && !showThankYou}
Feedback
Ju lutemi të jepni përgjigjet tuaja në këtë form.
{#each currentQuestions as question (question.id)}
{#if question.type === 'department'}
{question.text}
saveAnswer(question.id, 'sales')}
>
Shitje
saveAnswer(question.id, 'service')}
>
Servis
{:else if question.type === 'brand'}
{question.text}
{#each brands as brand}
saveAnswer(question.id, brand.id)}
>
{/each}
{:else if question.type === 'rating'}
{question.text}
{#each Array(5) as _, i}
saveAnswer(question.id, i + 1)}
>
i ? fasStar : farStar}
class={answers[question.id] > i ? "text-orange-500" : "text-zinc-600"}
/>
{/each}
{:else}
{question.text}
{#if question.required}
*
{/if}
saveAnswer(question.id, e.target.value, false)}
placeholder={question.required ? "Shkruani përgjigjen tuaj këtu..." : "Opsionale - Shkruani përgjigjen tuaj këtu..."}
rows="3"
class="w-full resize-none"
on:keydown={(e) => {
if (e.key === 'Enter' && e.target.value.trim()) {
saveAnswer(question.id, e.target.value);
handleSubmit();
}
}}
/>
{/if}
{/each}
{:else if show && showThankYou}
Faleminderit!
E vlerësojmë shumë përgjigjen tuaj!
{/if}
================
File: src/lib/components/games/ScoreIndicator.svelte
================
{isPositive ? '+' : '-'}{Math.abs(points)}
================
File: src/lib/components/games/VictoryModal.svelte
================
{#if show}
Congratulations!
{#each stats as stat}
{stat.label}
{stat.value}
{#if stat.bonus}
Bonus: {stat.bonus}
{/if}
{/each}
Llogaritja e pikëve
{#each bonuses as bonus}
{bonus.label}
{bonus.value} pikë
{/each}
Pikët totale
{totalScore} pikë
Homepage
Luaj përsëri
{/if}
================
File: src/lib/components/navbar.svelte
================
{#if isMobileMenuOpen}
{/if}
================
File: src/lib/components/screensaver.svelte
================
{#if active}
{#each Array(12) as _, i}
{/each}
{hours}
:
{minutes}
Tap to play
{#each Array(30) as _, i}
{/each}
{/if}
================
File: src/lib/components/ui/accordion/accordion-content.svelte
================
================
File: src/lib/components/ui/accordion/accordion-item.svelte
================
================
File: src/lib/components/ui/accordion/accordion-trigger.svelte
================
svg]:rotate-180",
className
)}
{...$$restProps}
on:click
>
================
File: src/lib/components/ui/accordion/index.js
================
import { Accordion as AccordionPrimitive } from "bits-ui";
import Content from "./accordion-content.svelte";
import Item from "./accordion-item.svelte";
import Trigger from "./accordion-trigger.svelte";
const Root = AccordionPrimitive.Root;
export {
Root,
Content,
Item,
Trigger,
//
Root as Accordion,
Content as AccordionContent,
Item as AccordionItem,
Trigger as AccordionTrigger,
};
================
File: src/lib/components/ui/badge/badge.svelte
================
================
File: src/lib/components/ui/badge/index.js
================
import { tv } from "tailwind-variants";
export { default as Badge } from "./badge.svelte";
export const badgeVariants = tv({
base: "focus:ring-ring inline-flex select-none items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2",
variants: {
variant: {
default:
"bg-primary text-primary-foreground hover:bg-primary/80 border-transparent shadow",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/80 border-transparent shadow",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
});
================
File: src/lib/components/ui/button/button.svelte
================
================
File: src/lib/components/ui/button/index.js
================
import { tv } from "tailwind-variants";
import Root from "./button.svelte";
const buttonVariants = tv({
base: "focus-visible:ring-ring inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50",
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90 shadow",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm",
outline:
"border-input bg-background hover:bg-accent hover:text-accent-foreground border shadow-sm",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-sm",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
});
export {
Root,
//
Root as Button,
buttonVariants,
};
================
File: src/lib/components/ui/calendar/calendar-cell.svelte
================
================
File: src/lib/components/ui/calendar/calendar-day.svelte
================
{date.day}
================
File: src/lib/components/ui/calendar/calendar-grid-body.svelte
================
================
File: src/lib/components/ui/calendar/calendar-grid-head.svelte
================
================
File: src/lib/components/ui/calendar/calendar-grid-row.svelte
================
================
File: src/lib/components/ui/calendar/calendar-grid.svelte
================
================
File: src/lib/components/ui/calendar/calendar-head-cell.svelte
================
================
File: src/lib/components/ui/calendar/calendar-header.svelte
================
================
File: src/lib/components/ui/calendar/calendar-heading.svelte
================
{headingValue}
================
File: src/lib/components/ui/calendar/calendar-months.svelte
================
================
File: src/lib/components/ui/calendar/calendar-next-button.svelte
================
================
File: src/lib/components/ui/calendar/calendar-prev-button.svelte
================
================
File: src/lib/components/ui/calendar/calendar.svelte
================
{#each months as month}
{#each weekdays as weekday}
{weekday.slice(0, 2)}
{/each}
{#each month.weeks as weekDates}
{#each weekDates as date}
{/each}
{/each}
{/each}
================
File: src/lib/components/ui/calendar/index.js
================
import Root from "./calendar.svelte";
import Cell from "./calendar-cell.svelte";
import Day from "./calendar-day.svelte";
import Grid from "./calendar-grid.svelte";
import Header from "./calendar-header.svelte";
import Months from "./calendar-months.svelte";
import GridRow from "./calendar-grid-row.svelte";
import Heading from "./calendar-heading.svelte";
import GridBody from "./calendar-grid-body.svelte";
import GridHead from "./calendar-grid-head.svelte";
import HeadCell from "./calendar-head-cell.svelte";
import NextButton from "./calendar-next-button.svelte";
import PrevButton from "./calendar-prev-button.svelte";
export {
Day,
Cell,
Grid,
Header,
Months,
GridRow,
Heading,
GridBody,
GridHead,
HeadCell,
NextButton,
PrevButton,
//
Root as Calendar,
};
================
File: src/lib/components/ui/card/card-content.svelte
================
================
File: src/lib/components/ui/card/card-description.svelte
================
================
File: src/lib/components/ui/card/card-footer.svelte
================
================
File: src/lib/components/ui/card/card-header.svelte
================
================
File: src/lib/components/ui/card/card-title.svelte
================
================
File: src/lib/components/ui/card/card.svelte
================
================
File: src/lib/components/ui/card/index.js
================
import Root from "./card.svelte";
import Content from "./card-content.svelte";
import Description from "./card-description.svelte";
import Footer from "./card-footer.svelte";
import Header from "./card-header.svelte";
import Title from "./card-title.svelte";
export {
Root,
Content,
Description,
Footer,
Header,
Title,
//
Root as Card,
Content as CardContent,
Description as CardDescription,
Footer as CardFooter,
Header as CardHeader,
Title as CardTitle,
};
================
File: src/lib/components/ui/checkbox/checkbox.svelte
================
{#if isIndeterminate}
{:else}
{/if}
================
File: src/lib/components/ui/checkbox/index.js
================
import Root from "./checkbox.svelte";
export {
Root,
//
Root as Checkbox,
};
================
File: src/lib/components/ui/date-range-picker/index.svelte
================
{formattedDate}
{#if value?.from}
{/if}
{#each presets as preset}
selectPreset(preset)}
>
{preset.label}
{/each}
{#if selectedRange.from && !selectedRange.to}
Zgjidhni datën e fundit
{:else}
Zgjidhni datën e fillimit
{/if}
================
File: src/lib/components/ui/dialog/dialog-content.svelte
================
Close
================
File: src/lib/components/ui/dialog/dialog-description.svelte
================
================
File: src/lib/components/ui/dialog/dialog-footer.svelte
================
================
File: src/lib/components/ui/dialog/dialog-header.svelte
================
================
File: src/lib/components/ui/dialog/dialog-overlay.svelte
================
================
File: src/lib/components/ui/dialog/dialog-portal.svelte
================
================
File: src/lib/components/ui/dialog/dialog-title.svelte
================
================
File: src/lib/components/ui/dialog/index.js
================
import { Dialog as DialogPrimitive } from "bits-ui";
import Title from "./dialog-title.svelte";
import Portal from "./dialog-portal.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
import Description from "./dialog-description.svelte";
const Root = DialogPrimitive.Root;
const Trigger = DialogPrimitive.Trigger;
const Close = DialogPrimitive.Close;
export {
Root,
Title,
Portal,
Footer,
Header,
Trigger,
Overlay,
Content,
Description,
Close,
//
Root as Dialog,
Title as DialogTitle,
Portal as DialogPortal,
Footer as DialogFooter,
Header as DialogHeader,
Trigger as DialogTrigger,
Overlay as DialogOverlay,
Content as DialogContent,
Description as DialogDescription,
Close as DialogClose,
};
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte
================
================
File: src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte
================
================
File: src/lib/components/ui/dropdown-menu/index.js
================
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import Item from "./dropdown-menu-item.svelte";
import Label from "./dropdown-menu-label.svelte";
import Content from "./dropdown-menu-content.svelte";
import Shortcut from "./dropdown-menu-shortcut.svelte";
import RadioItem from "./dropdown-menu-radio-item.svelte";
import Separator from "./dropdown-menu-separator.svelte";
import RadioGroup from "./dropdown-menu-radio-group.svelte";
import SubContent from "./dropdown-menu-sub-content.svelte";
import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
const Trigger = DropdownMenuPrimitive.Trigger;
const Group = DropdownMenuPrimitive.Group;
export {
Sub,
Root,
Item,
Label,
Group,
Trigger,
Content,
Shortcut,
Separator,
RadioItem,
SubContent,
SubTrigger,
RadioGroup,
CheckboxItem,
//
Root as DropdownMenu,
Sub as DropdownMenuSub,
Item as DropdownMenuItem,
Label as DropdownMenuLabel,
Group as DropdownMenuGroup,
Content as DropdownMenuContent,
Trigger as DropdownMenuTrigger,
Shortcut as DropdownMenuShortcut,
RadioItem as DropdownMenuRadioItem,
Separator as DropdownMenuSeparator,
RadioGroup as DropdownMenuRadioGroup,
SubContent as DropdownMenuSubContent,
SubTrigger as DropdownMenuSubTrigger,
CheckboxItem as DropdownMenuCheckboxItem,
};
================
File: src/lib/components/ui/input/index.js
================
import Root from "./input.svelte";
export {
Root,
//
Root as Input,
};
================
File: src/lib/components/ui/input/input.svelte
================
================
File: src/lib/components/ui/label/index.js
================
import Root from "./label.svelte";
export {
Root,
//
Root as Label,
};
================
File: src/lib/components/ui/label/label.svelte
================
================
File: src/lib/components/ui/popover/index.js
================
import { Popover as PopoverPrimitive } from "bits-ui";
import Content from "./popover-content.svelte";
const Root = PopoverPrimitive.Root;
const Trigger = PopoverPrimitive.Trigger;
const Close = PopoverPrimitive.Close;
export {
Root,
Content,
Trigger,
Close,
//
Root as Popover,
Content as PopoverContent,
Trigger as PopoverTrigger,
Close as PopoverClose,
};
================
File: src/lib/components/ui/popover/popover-content.svelte
================
================
File: src/lib/components/ui/select/index.js
================
import { Select as SelectPrimitive } from "bits-ui";
import Label from "./select-label.svelte";
import Item from "./select-item.svelte";
import Content from "./select-content.svelte";
import Trigger from "./select-trigger.svelte";
import Separator from "./select-separator.svelte";
const Root = SelectPrimitive.Root;
const Group = SelectPrimitive.Group;
const Input = SelectPrimitive.Input;
const Value = SelectPrimitive.Value;
export {
Root,
Item,
Group,
Input,
Label,
Value,
Content,
Trigger,
Separator,
//
Root as Select,
Item as SelectItem,
Group as SelectGroup,
Input as SelectInput,
Label as SelectLabel,
Value as SelectValue,
Content as SelectContent,
Trigger as SelectTrigger,
Separator as SelectSeparator,
};
================
File: src/lib/components/ui/select/select-content.svelte
================
================
File: src/lib/components/ui/select/select-item.svelte
================
{label || value}
================
File: src/lib/components/ui/select/select-label.svelte
================
================
File: src/lib/components/ui/select/select-separator.svelte
================
================
File: src/lib/components/ui/select/select-trigger.svelte
================
span]:text-muted-foreground flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...$$restProps}
>
================
File: src/lib/components/ui/separator/index.js
================
import Root from "./separator.svelte";
export {
Root,
//
Root as Separator,
};
================
File: src/lib/components/ui/separator/separator.svelte
================
================
File: src/lib/components/ui/table/index.js
================
import Root from "./table.svelte";
import Body from "./table-body.svelte";
import Caption from "./table-caption.svelte";
import Cell from "./table-cell.svelte";
import Footer from "./table-footer.svelte";
import Head from "./table-head.svelte";
import Header from "./table-header.svelte";
import Row from "./table-row.svelte";
export {
Root,
Body,
Caption,
Cell,
Footer,
Head,
Header,
Row,
//
Root as Table,
Body as TableBody,
Caption as TableCaption,
Cell as TableCell,
Footer as TableFooter,
Head as TableHead,
Header as TableHeader,
Row as TableRow,
};
================
File: src/lib/components/ui/table/table-body.svelte
================
================
File: src/lib/components/ui/table/table-caption.svelte
================
================
File: src/lib/components/ui/table/table-cell.svelte
================
[role=checkbox]]:translate-y-[2px]",
className
)}
{...$$restProps}
on:click
on:keydown
>
================
File: src/lib/components/ui/table/table-footer.svelte
================
================
File: src/lib/components/ui/table/table-head.svelte
================
[role=checkbox]]:translate-y-[2px]",
className
)}
{...$$restProps}
>
================
File: src/lib/components/ui/table/table-header.svelte
================
================
File: src/lib/components/ui/table/table-row.svelte
================
================
File: src/lib/components/ui/table/table.svelte
================
================
File: src/lib/components/ui/textarea/index.js
================
import Root from "./textarea.svelte";
export {
Root,
//
Root as Textarea,
};
================
File: src/lib/components/ui/textarea/textarea.svelte
================
================
File: src/lib/components/ui/toggle/index.js
================
import { tv } from "tailwind-variants";
import Root from "./toggle.svelte";
export const toggleVariants = tv({
base: "hover:bg-muted hover:text-muted-foreground focus-visible:ring-ring data-[state=on]:bg-accent data-[state=on]:text-accent-foreground inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50",
variants: {
variant: {
default: "bg-transparent",
outline:
"border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-sm",
},
size: {
default: "h-9 px-3",
sm: "h-8 px-2",
lg: "h-10 px-3",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
});
export {
Root,
//
Root as Toggle,
};
================
File: src/lib/components/ui/toggle/toggle.svelte
================
================
File: src/lib/components/ui/tooltip/index.js
================
import { Tooltip as TooltipPrimitive } from "bits-ui";
import Content from "./tooltip-content.svelte";
const Root = TooltipPrimitive.Root;
const Trigger = TooltipPrimitive.Trigger;
export {
Root,
Trigger,
Content,
//
Root as Tooltip,
Content as TooltipContent,
Trigger as TooltipTrigger,
};
================
File: src/lib/components/ui/tooltip/tooltip-content.svelte
================
================
File: src/lib/i18n.js
================
import * as runtime from '$lib/paraglide/runtime';
import { createI18n } from '@inlang/paraglide-sveltekit';
export const i18n = createI18n(runtime);
================
File: src/lib/stores/feedbackStore.js
================
import { writable } from 'svelte/store';
import { browser } from '$app/environment';
const STORAGE_KEY = 'feedback-store';
const defaultState = {
department: '',
brand: '',
currentStep: 1,
questionIndex: 0,
totalQuestions: [],
completedQuestions: {},
lastFeedbackDate: null,
roundsPlayed: 0,
isComplete: false,
progress: 0,
currentRoundStarted: false,
currentRound: 1,
answers: {}
};
const initialState = {
roundsPlayed: 0,
isComplete: false,
progress: 0,
currentRoundStarted: false,
currentRound: 1,
answers: {},
feedbackShownForRounds: {}, // Track which rounds we've shown feedback for
lastFeedbackDate: null // Track when feedback was last shown
};
const createFeedbackStore = () => {
// Load initial state from localStorage if available
const storedState = browser && localStorage.getItem(STORAGE_KEY);
const initialStateWithStorage = storedState ? JSON.parse(storedState) : initialState;
const { subscribe, set, update } = writable({ ...defaultState, ...initialStateWithStorage });
return {
subscribe,
updateState: (newState) => update(state => {
const updatedState = { ...state, ...newState };
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedState));
}
return updatedState;
}),
startNewRound: () => {
update(state => {
const updatedState = {
...state,
currentRoundStarted: true
};
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedState));
}
return updatedState;
});
},
completeRound: () => {
update(state => {
const updatedState = {
...state,
roundsPlayed: state.roundsPlayed + 1,
currentRoundStarted: false,
currentRound: state.currentRound + 1,
lastFeedbackDate: new Date().toISOString() // Update last feedback date
};
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedState));
}
return updatedState;
});
},
completeQuestion: (question, answer) => {
update(state => {
const newCompletedQuestions = { ...state.completedQuestions, [question]: answer };
const totalAnswered = Object.keys(newCompletedQuestions).length;
const totalQuestions = state.totalQuestions.length + 2; // +2 for department and brand
const progress = Math.round((totalAnswered / totalQuestions) * 100);
const updatedState = {
...state,
completedQuestions: newCompletedQuestions,
progress,
questionIndex: state.questionIndex + (question === 'department' || question === 'brand' ? 0 : 1),
isComplete: totalAnswered === totalQuestions,
answers: { ...state.answers, [question]: answer }
};
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedState));
}
return updatedState;
});
},
setTotalQuestions: (questions) => {
update(state => {
const updatedState = { ...state, totalQuestions: questions };
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(updatedState));
}
return updatedState;
});
},
reset: () => {
const newState = { ...defaultState, ...initialState };
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(newState));
}
set(newState);
},
shouldShowFeedback: () => {
let shouldShow = false;
update(state => {
if (!state.lastFeedbackDate) {
shouldShow = true;
return state;
}
const lastDate = new Date(state.lastFeedbackDate);
const today = new Date();
// Check if it's a different day
shouldShow = lastDate.getDate() !== today.getDate() ||
lastDate.getMonth() !== today.getMonth() ||
lastDate.getFullYear() !== today.getFullYear();
return state;
});
return shouldShow;
},
getCurrentQuestions: () => {
let currentQuestions = [];
update(state => {
if (state.totalQuestions.length > 0) {
const startIdx = state.questionIndex;
const endIdx = Math.min(startIdx + 2, state.totalQuestions.length);
currentQuestions = state.totalQuestions
.slice(startIdx, endIdx)
.filter(q => !state.completedQuestions[q]);
}
return state;
});
return currentQuestions;
},
getProgress: () => {
let progress = 0;
update(state => {
const totalAnswered = Object.keys(state.completedQuestions).length;
const totalQuestions = state.totalQuestions.length + 2; // +2 for department and brand
progress = Math.round((totalAnswered / totalQuestions) * 100);
return state;
});
return progress;
},
getCurrentRound: () => {
let currentState;
subscribe(store => {
currentState = store;
})();
return currentState.currentRound;
},
setRound: (round) => update(store => {
store.currentRound = round;
console.log('🔄 Feedback Store: Round set to', store.currentRound);
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(store));
}
return store;
}),
saveAnswer: (questionId, answer) => update(store => {
store.answers[questionId] = answer;
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(store));
}
return store;
}),
incrementRound: () => {
update(state => {
const newState = {
...state,
currentRound: state.currentRound + 1,
roundsPlayed: state.roundsPlayed + 1
};
console.log('🔄 Feedback Store: Incrementing round', {
oldRound: state.currentRound,
newRound: newState.currentRound
});
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(newState));
}
return newState;
});
},
markFeedbackShown: (round) => {
update(state => {
const newState = {
...state,
feedbackShownForRounds: {
...state.feedbackShownForRounds,
[round]: true
}
};
console.log('📝 Feedback Store: Marked feedback shown for round', round);
if (browser) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(newState));
}
return newState;
});
},
isFeedbackShown: (round) => {
let currentState;
subscribe(store => {
currentState = store;
})();
return !!currentState.feedbackShownForRounds[round];
},
};
};
export const feedbackStore = createFeedbackStore();
================
File: src/lib/stores/formEditorStore.js
================
import { writable } from 'svelte/store';
const initialForms = {
sales: {
questions: [
{ id: 1, type: 'rating', text: 'Si e vlerësoni eksperiencën e blerjes?', order: 0 },
{ id: 2, type: 'rating', text: 'A ishte stafi i dobishëm?', order: 1 },
{ id: 3, type: 'rating', text: 'Sa i kënaqur jeni me çmimin?', order: 2 },
{ id: 4, type: 'rating', text: 'A do ta rekomandonit tek të tjerët?', order: 3 }
],
brands: [
{ id: 'volkswagen', name: 'Volkswagen', image: '/images/brands/volkswagen.png' },
{ id: 'audi', name: 'Audi', image: '/images/brands/audi.png' },
{ id: 'seat', name: 'Seat', image: '/images/brands/seat.png' },
{ id: 'skoda', name: 'Skoda', image: '/images/brands/skoda.png' }
]
},
service: {
questions: [
{ id: 1, type: 'rating', text: 'Sa i kënaqur jeni me shërbimin?', order: 0 },
{ id: 2, type: 'rating', text: 'A u zgjidh problemi juaj?', order: 1 },
{ id: 3, type: 'comment', text: 'Çfarë mund të përmirësojmë?', order: 2 },
{ id: 4, type: 'rating', text: 'A do ta rekomandonit shërbimin tonë?', order: 3 }
],
brands: [
{ id: 'volkswagen', name: 'Volkswagen', image: '/images/brands/volkswagen.png' },
{ id: 'audi', name: 'Audi', image: '/images/brands/audi.png' },
{ id: 'seat', name: 'Seat', image: '/images/brands/seat.png' },
{ id: 'skoda', name: 'Skoda', image: '/images/brands/skoda.png' }
]
}
};
function createFormEditorStore() {
const { subscribe, set, update } = writable({
currentDepartment: 'sales',
forms: initialForms,
history: []
});
return {
subscribe,
setDepartment: (department) => update(state => ({ ...state, currentDepartment: department })),
addQuestion: (question) => update(state => {
const currentQuestions = state.forms[state.currentDepartment].questions;
const newQuestion = {
...question,
id: Math.max(...currentQuestions.map(q => q.id), 0) + 1,
order: currentQuestions.length
};
return {
...state,
forms: {
...state.forms,
[state.currentDepartment]: {
...state.forms[state.currentDepartment],
questions: [...currentQuestions, newQuestion]
}
}
};
}),
updateQuestion: (questionId, updates) => update(state => {
const questions = state.forms[state.currentDepartment].questions.map(q =>
q.id === questionId ? { ...q, ...updates } : q
);
return {
...state,
forms: {
...state.forms,
[state.currentDepartment]: {
...state.forms[state.currentDepartment],
questions
}
}
};
}),
removeQuestion: (questionId) => update(state => {
const questions = state.forms[state.currentDepartment].questions
.filter(q => q.id !== questionId)
.map((q, index) => ({ ...q, order: index }));
return {
...state,
forms: {
...state.forms,
[state.currentDepartment]: {
...state.forms[state.currentDepartment],
questions
}
}
};
}),
reorderQuestions: (questions) => update(state => ({
...state,
forms: {
...state.forms,
[state.currentDepartment]: {
...state.forms[state.currentDepartment],
questions
}
}
})),
addBrand: (brand) => update(state => {
const brands = state.forms[state.currentDepartment].brands;
return {
...state,
forms: {
...state.forms,
[state.currentDepartment]: {
...state.forms[state.currentDepartment],
brands: [...brands, brand]
}
}
};
}),
removeBrand: (brandId) => update(state => {
const brands = state.forms[state.currentDepartment].brands
.filter(b => b.id !== brandId);
return {
...state,
forms: {
...state.forms,
[state.currentDepartment]: {
...state.forms[state.currentDepartment],
brands
}
}
};
}),
saveForm: () => update(state => {
const currentForm = state.forms[state.currentDepartment];
return {
...state,
history: [
...state.history,
{
department: state.currentDepartment,
timestamp: new Date().toISOString(),
questions: [...currentForm.questions],
brands: [...currentForm.brands]
}
]
};
}),
reset: () => set({ currentDepartment: 'sales', forms: initialForms, history: [] })
};
}
export const formEditorStore = createFormEditorStore();
================
File: src/lib/stores/gameStore.js
================
import { writable } from 'svelte/store';
function createGameStore() {
const { subscribe, set, update } = writable({
username: '',
totalScore: 0,
gameHistory: [],
stats: {
gamesPlayed: 0,
bestScores: {
puzzle: 0,
race: 0,
pairs: 0,
trivia: 0
},
lastPlayed: null,
playStreak: 0
}
});
function updatePlayStreak(store) {
const now = new Date();
const lastPlayed = store.stats.lastPlayed ? new Date(store.stats.lastPlayed) : null;
if (!lastPlayed) {
return 1;
}
const daysSinceLastPlay = Math.floor((now - lastPlayed) / (1000 * 60 * 60 * 24));
if (daysSinceLastPlay === 1) {
return store.stats.playStreak + 1;
} else if (daysSinceLastPlay > 1) {
return 1;
}
return store.stats.playStreak;
}
return {
subscribe,
setUsername: (username) => {
const savedData = localStorage.getItem(`gameData_${username}`);
if (savedData) {
set(JSON.parse(savedData));
} else {
update(store => ({
...store,
username,
totalScore: 0,
gameHistory: [],
stats: {
gamesPlayed: 0,
bestScores: {
puzzle: 0,
race: 0,
pairs: 0,
trivia: 0
},
lastPlayed: null,
playStreak: 0
}
}));
}
},
addScore: (game, score) => {
update(store => {
const now = new Date().toISOString();
const newGameHistory = [...store.gameHistory, {
game,
score,
timestamp: now
}];
const newStats = {
...store.stats,
gamesPlayed: store.stats.gamesPlayed + 1,
bestScores: {
...store.stats.bestScores,
[game]: Math.max(store.stats.bestScores[game], score)
},
lastPlayed: now,
playStreak: updatePlayStreak(store)
};
const newTotalScore = store.totalScore + score;
const newStore = {
...store,
totalScore: newTotalScore,
gameHistory: newGameHistory,
stats: newStats
};
// Save to localStorage
localStorage.setItem(`gameData_${store.username}`, JSON.stringify(newStore));
return newStore;
});
},
getStats: () => {
let stats;
update(store => {
stats = store.stats;
return store;
});
return stats;
},
getGameHistory: () => {
let history;
update(store => {
history = store.gameHistory;
return store;
});
return history;
}
};
}
export const gameStore = createGameStore();
================
File: src/lib/stores/score.js
================
import { writable } from 'svelte/store';
// Initialize the score from localStorage or default to 0
const storedScore = typeof localStorage !== 'undefined' ? localStorage.getItem('totalScore') : '0';
const initialScore = parseInt(storedScore) || 0;
// Create the score store
const score = writable(initialScore);
// Subscribe to changes and update localStorage
if (typeof window !== 'undefined') {
score.subscribe(value => {
localStorage.setItem('totalScore', value.toString());
});
}
// Helper function to add points
function addPoints(points) {
score.update(current => Math.max(0, current + points));
}
export { score, addPoints };
================
File: src/lib/stores/screensaver.js
================
import { writable } from 'svelte/store';
const INACTIVITY_TIMEOUT = 180000; // 3 minutes in milliseconds
function createScreensaverStore() {
const { subscribe, set } = writable(false);
let timer;
function resetTimer() {
if (timer) clearTimeout(timer);
set(false);
timer = setTimeout(() => set(true), INACTIVITY_TIMEOUT);
}
function initialize() {
// Reset timer on various user interactions
const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'];
events.forEach(event => {
window.addEventListener(event, resetTimer, { passive: true });
});
// Initial timer setup
resetTimer();
// Cleanup function
return () => {
if (timer) clearTimeout(timer);
events.forEach(event => {
window.removeEventListener(event, resetTimer);
});
};
}
return {
subscribe,
initialize,
reset: resetTimer
};
}
export const screensaver = createScreensaverStore();
================
File: src/lib/stores/sessionStore.js
================
import { writable } from 'svelte/store';
import { goto } from '$app/navigation';
function createSessionStore() {
const { subscribe, set, update } = writable({
isAuthenticated: false,
user: null
});
return {
subscribe,
login: (username) => {
localStorage.setItem('username', username);
set({
isAuthenticated: true,
user: { username }
});
},
logout: () => {
localStorage.removeItem('username');
set({
isAuthenticated: false,
user: null
});
goto('/login');
},
checkAuth: () => {
const username = localStorage.getItem('username');
if (username) {
set({
isAuthenticated: true,
user: { username }
});
return true;
}
return false;
}
};
}
export const session = createSessionStore();
================
File: src/lib/stores/theme.js
================
// theme.js
// Example: Exporting a default theme object
import { writable } from 'svelte/store';
// Create a proper Svelte store for theme
function createThemeStore() {
// Get initial theme from localStorage or default to 'light'
const storedTheme = typeof localStorage !== 'undefined' ? localStorage.getItem('theme') : 'light';
const initialTheme = storedTheme || 'light';
const { subscribe, set, update } = writable(initialTheme);
return {
subscribe,
set: (value) => {
if (typeof localStorage !== 'undefined') {
localStorage.setItem('theme', value);
}
set(value);
},
toggle: () => update(theme => {
const newTheme = theme === 'light' ? 'dark' : 'light';
if (typeof localStorage !== 'undefined') {
localStorage.setItem('theme', newTheme);
}
return newTheme;
})
};
}
export const theme = createThemeStore();
// You can expand this file with more theme-related logic or data as needed.
================
File: src/lib/utils.js
================
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { cubicOut } from "svelte/easing";
export function cn(...inputs) {
return twMerge(clsx(inputs));
}
export const flyAndScale = (
node,
params = { y: -8, x: 0, start: 0.95, duration: 150 }
) => {
const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform;
const scaleConversion = (valueA, scaleA, scaleB) => {
const [minA, maxA] = scaleA;
const [minB, maxB] = scaleB;
const percentage = (valueA - minA) / (maxA - minA);
const valueB = percentage * (maxB - minB) + minB;
return valueB;
};
const styleToString = (style) => {
return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined) return str;
return str + `${key}:${style[key]};`;
}, "");
};
return {
duration: params.duration ?? 200,
delay: 0,
css: (t) => {
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
return styleToString({
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
opacity: t
});
},
easing: cubicOut
};
};
================
File: src/routes/+layout.svelte
================
{#if mounted}
{#if showNav && !isAdmin}
{/if}
{/if}
================
File: src/routes/+page.svelte
================
LET'S PLAY, {username.toUpperCase()}!
{#each games as game, i}
{/each}
showFeedbackModal = true}
>
Na ndihmoni të përmirësohemi
================
File: src/routes/admin/+layout.svelte
================
================
File: src/routes/admin/+page.svelte
================
Mirë se vini në Panelin e Adminit
Zgjidhni një nga opsionet e mëposhtme për të menaxhuar sistemin.
{#each adminCards as card}
goto(card.href)}
>
{card.title}
{card.description}
{#if card.stats}
{card.stats.label}
{card.stats.value}
{/if}
{/each}
================
File: src/routes/admin/feedback/+page.svelte
================
Tabela e Feedback-ut
History
Form History
Shkarkoni versionet e mëparshme dhe ndryshimet e bëra në formën e feedback-it
{#each mockFormVersionsHistory as version}
{version.editor}
{version.department}
{formatDate(version.date)}
{#each version.changes as change}
{/each}
loadFormVersion(version)}
>
Download Excel
{/each}
Export
Filters
{#if selectedDepartment !== 'all' || searchQuery || selectedBrands.length > 0 || selectedIpAddresses.length > 0 || selectedRatings.length > 0}
{
selectedDepartment = 'all';
searchQuery = '';
selectedBrands = [];
selectedIpAddresses = [];
selectedRatings = [];
}}
>
Pastro Filtrat
{/if}
Marka
{#each brands as brand}
{
if (selectedBrands.includes(brand)) {
selectedBrands = selectedBrands.filter(b => b !== brand);
} else {
selectedBrands = [...selectedBrands, brand];
}
}}
>
{brand}
{/each}
IP
{#each ipAddresses as ip}
{
if (selectedIpAddresses.includes(ip)) {
selectedIpAddresses = selectedIpAddresses.filter(i => i !== ip);
} else {
selectedIpAddresses = [...selectedIpAddresses, ip];
}
}}
>
{ip}
{/each}
Rating
{#each [1, 2, 3, 4, 5] as rating}
{
if (selectedRatings.includes(rating)) {
selectedRatings = selectedRatings.filter(r => r !== rating);
} else {
selectedRatings = [...selectedRatings, rating];
}
}}
>
{ratingLabels[rating].text}
{/each}
Departamenti
selectedDepartment = 'all'}
>
All
selectedDepartment = 'Shitje'}
>
Shitje
selectedDepartment = 'Servis'}
>
Servis
Data
Emri
Departamenti
Brendi
IP
{#each mockQuestions[selectedDepartment === 'Shitje' ? 'sales' : 'service'] as question, i}
Q{i + 1}
{question}
{/each}
{#each filteredResponses as response (response.id)}
{formatDate(response.date)}
{response.name}
{response.department}
{response.brand}
{response.ip}
{#each response.responses as answer, i}
{#if typeof answer === 'number'}
{ratingLabels[answer].text}
{:else}
{answer}
{/if}
{/each}
{/each}
================
File: src/routes/admin/form-editor/+page.svelte
================
formEditorStore.setDepartment('sales')}
>
ShitjeModifiko pyetjet e formit te shitjes
formEditorStore.setDepartment('service')}
>
ServisModifiko pyetjet e formit te servisit
Zgjidhni markë
{#each brands as brand}
formEditorStore.removeBrand(brand.id)}
>
{/each}
showBrandModal = true}
>
Shto Markë
Vlerësoni eksperiencën tuaj
{#each questions as question (question.id)}
{question.text}
Tipi: {question.type === 'rating' ? 'Vlerësim' : 'Koment'}
removeQuestion(question.id)}
>
{/each}
newQuestion = { text: "", type: "rating" }}
>
Shto Pyetje të Re
Ruaj Ndryshimet
showBrandModal = false}
/>
{#if newQuestion.text !== undefined}
Shto Pyetje të Re
newQuestion = { text: undefined, type: "rating" }}
>
Tipi i Pyetjes
newQuestion.type = 'rating'}
>
VlerësimVlerësim me yje
Teksti i Pyetjes
newQuestion = { text: undefined, type: "rating" }}
>
Anulo
Shto
{/if}
================
File: src/routes/admin/login/+page.svelte
================
Admin Login
Enter your credentials to access the admin panel
Protected area. Unauthorized access is prohibited.
================
File: src/routes/admin/users/+page.svelte
================
Admin Management
Add Admin
Add New Admin User
Create a new admin user with specific roles and privileges.
Name
Email
Role
Super Admin
Normal Admin
Privileges
{#each Object.entries(newUser.privileges) as [privilege, value]}
{privilegeLabels[privilege]}
{/each}
showAddDialog = false}
>
Cancel
Add User
{#each adminUsers as user (user.id)}
{user.role === 'super' ? 'Super Admin' : 'Normal Admin'}
Privileges
{#each Object.entries(user.privileges) as [privilege, value]}
{privilegeLabels[privilege]}
{/each}
editUser(user)}
>
Edit User
confirmDelete(user)}
>
Delete
{/each}
{#if editingUser}
Edit Admin User
Modify user details and privileges.
Name
Email
Role
Super Admin
Normal Admin
Privileges
{#each Object.entries(editingUser.privileges) as [privilege, value]}
{privilegeLabels[privilege]}
{/each}
showEditDialog = false}
>
Cancel
Save Changes
{/if}
{#if userToDelete}
Delete Admin User
Are you sure you want to delete this admin user? This action cannot be undone.
{userToDelete.name}
{userToDelete.email}
{
showDeleteDialog = false;
userToDelete = null;
}}
>
Cancel
Delete User
{/if}
================
File: src/routes/games/+layout.svelte
================
================
File: src/routes/games/pairs/+page.svelte
================
{#each scoreIndicators as indicator (indicator.id)}
{#if indicator.text}
{indicator.text}
{:else}
✕
{/if}
{/each}
{#each cards as card, index}
handleCardClick(index, e)}
>
{/each}
{#if showVictoryModal}
window.location.href = "/"}
gameTitle="Pick the Pairs"
/>
{/if}
================
File: src/routes/games/puzzle/+page.svelte
================
{#each carImages as image}
selectImage(image)}
>
{/each}
{#if selectedImage && !gameStarted}
Gati për të filluar?
(Klikoni dy pjesë për t'i ndërruar vëndin)
Nis lojën
{:else if gameStarted}
{#each pieces as piece (piece.id)}
{@const pos = piece.currentPos}
{@const x = Math.floor(pos % difficulty)}
{@const y = Math.floor(pos / difficulty)}
handlePieceClick(piece)}
animate:flip={{
duration: 400,
easing: cubicOut,
delay: 0
}}
style="
--piece-image: url({selectedImage});
--total-size: {difficulty * 100}% {difficulty * 100}%;
--piece-position: {-x * 100}% {-y * 100}%;
"
>
{/each}
{/if}
{#if showDifficultyMenu}
showDifficultyMenu = false}
>
Zgjidhni vështirësinë
{#each [3, 4, 5] as level}
{
setDifficulty(level);
showDifficultyMenu = false;
}}
>
{#if difficulty === level}
Zgjedhur
{/if}
{/each}
{/if}
{#if showCompletionOverlay}
{/if}
{#if showModal}
window.location.href = "/"}
onPlayAgain={handlePlayAgain}
gameTitle="Piece the Puzzle"
/>
{/if}
{#if showFeedback}
{/if}
================
File: src/routes/games/race/+page.svelte
================
{Math.floor(timer / 60)}:{(timer % 60).toString().padStart(2, '0')}
{Math.floor(distance)}m
{#if !isGameStarted}
Race the Road
Shpejto përmes trafikut dhe shiko sa larg mund të arrish.
{ startGame(); }}
class="bg-orange-500 text-white hover:bg-orange-600"
>
Nis lojën
{/if}
{#if showGameOverModal}
{/if}
{#if showFeedback}
{/if}
{#if isGameStarted && !isGameOver}
handleSteeringClick('left')}
>
handleSteeringClick('right')}
>
{/if}
================
File: src/routes/games/trivia/+page.svelte
================
{#if !gameStarted}
Testoni njohuritë tuaja për makinat
Përgjigjuni pyetjeve. Sa më shpejt përgjigjeni, aq më shumë pikë fitoni!
Fillo quizin
{:else}
Pyetja {currentQuestion + 1} nga {questions.length}
{questions[currentQuestion].question}
{#each questions[currentQuestion].answers as answer, i}
handleAnswer(i)}
disabled={selectedAnswer !== null}
>
{#if selectedAnswer !== null}
{#if i === questions[currentQuestion].correct}
{:else if selectedAnswer === i}
{/if}
{/if}
{answer}
{/each}
{/if}
{#if showFeedback}
{/if}
{#if showModal}
{/if}
================
File: src/routes/leaderboard/+page.svelte
================
Tabela e Pikëve
Shikoni lojtarët më të mirë dhe arritjet e tyre
timeFilter = 'all'}
>
Gjithë koha
timeFilter = 'today'}
>
Sot
timeFilter = 'week'}
>
Java
timeFilter = 'month'}
>
Muaji
{#if leaderboardData.length === 0}
Nuk ka të dhëna për këtë periudhë
{:else}
Pozicioni
Lojtari
Pikët
Lojëra
{#each leaderboardData as player, index}
{getMedalIcon(index)}
#{index + 1}
{player.username}
{player.totalScore.toLocaleString()}
{player.gamesPlayed}
{/each}
{/if}
================
File: src/routes/login/+page.svelte
================
Si quheni?
{#if isLoading}
Duke u kyçur...
{:else}
Dakord
{/if}
{#if errorMessage}
{errorMessage}
{/if}
================
File: svelte.config.js
================
import adapter from '@sveltejs/adapter-auto';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter()
}
};
export default config;
================
File: tailwind.config.js
================
/** @type {import('tailwindcss').Config} */
export default {
darkMode: ["class"],
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
},
},
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
require('@tailwindcss/container-queries'),
],
}
================
File: vite.config.js
================
import { paraglide } from '@inlang/paraglide-sveltekit/vite';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit(),
paraglide({
project: './project.inlang',
outdir: './src/lib/paraglide'
})
]
});