takeover of old passkey learning repo

This commit is contained in:
Samuel Andert 2023-07-10 17:09:35 +02:00
parent 991eeacfbe
commit d8a335c001
36 changed files with 5192 additions and 142 deletions

13
.eslintignore Normal file
View File

@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

20
.eslintrc.cjs Normal file
View File

@ -0,0 +1,20 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
}
};

141
.gitignore vendored
View File

@ -1,132 +1,11 @@
# ---> Node
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
$houdini

9
.graphqlrc.yaml Normal file
View File

@ -0,0 +1,9 @@
projects:
default:
schema:
- ./schema.graphql
- ./$houdini/graphql/schema.graphql
documents:
- '**/*.gql'
- '**/*.svelte'
- ./$houdini/graphql/documents.gql

1
.npmrc Normal file
View File

@ -0,0 +1 @@
engine-strict=true

10
.prettierrc Normal file
View File

@ -0,0 +1,10 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"formatOnSave": true,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

37
CHANGELOG.md Normal file
View File

@ -0,0 +1,37 @@
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.1.3](https://github.com/shinokada/flowbite-svelte-starter/compare/v0.1.2...v0.1.3) (2023-02-18)
### Features
- dependencies update ([7ab91d0](https://github.com/shinokada/flowbite-svelte-starter/commit/7ab91d067e3004258f3dac20ffd4d505be7147dd))
- update all dependencies ([6c20ed5](https://github.com/shinokada/flowbite-svelte-starter/commit/6c20ed57b2c19189f3e41548726380d4ae9fa124))
- update svelteki to 1.5.6 ([b47978d](https://github.com/shinokada/flowbite-svelte-starter/commit/b47978d20498d30f7952da0136a17ea00a1fa305))
### Bug Fixes
- add /build to gitignore ([a11b6aa](https://github.com/shinokada/flowbite-svelte-starter/commit/a11b6aa67fd37fcc9eac5450db8780da86fcac62))
- add engines node 16.0.0 for vercel ([f113e5d](https://github.com/shinokada/flowbite-svelte-starter/commit/f113e5d93eb868021d8a3bb44ab6246d4023cceb))
- dependencies updates ([c5ecd50](https://github.com/shinokada/flowbite-svelte-starter/commit/c5ecd50064ebdfd33b280091e50a99524b541bf0))
- files update to sveltekit 1.5.6 ([05fc6f2](https://github.com/shinokada/flowbite-svelte-starter/commit/05fc6f2b2377139d61c40b20d32c17eb08e40ecf))
- files update to sveltekit 1.5.6 ([83500e1](https://github.com/shinokada/flowbite-svelte-starter/commit/83500e1188623621712cf697229b2b4d85a0fd65))
- remove /build from gitignore ([d49eb2f](https://github.com/shinokada/flowbite-svelte-starter/commit/d49eb2f0caaa632acae2c6cbb5ce6e1f9b497c20))
### [0.1.2](https://github.com/shinokada/flowbite-svelte-starter/compare/v0.1.1...v0.1.2) (2022-07-20)
### Bug Fixes
- packages and README update ([0ad4e6a](https://github.com/shinokada/flowbite-svelte-starter/commit/0ad4e6a663c610fa0950d431e4f438e444f0df02))
- update autoprefixer to 10.4.5 ([c20c74a](https://github.com/shinokada/flowbite-svelte-starter/commit/c20c74abcfae54d4b3e9068936da71961424d601))
- update dependencies and vite ([dbdaecc](https://github.com/shinokada/flowbite-svelte-starter/commit/dbdaecccae975c4c23955437b6eb07740a5b5e49))
- update Sveltekit ([1b9d814](https://github.com/shinokada/flowbite-svelte-starter/commit/1b9d814f59a6040061bd6543489fae2ccfaf645f))
### [0.1.1](https://github.com/shinokada/flowbite-svelte-starter/compare/v0.1.0...v0.1.1) (2022-05-12)
## 0.1.0 (2022-05-12)
### Features
- add svelte, sveltekit, tailwindcss, flowbite, flowbite-svelte, eslint, trypescript, playwright, prettier, svelte-heros, darkmode activated ([d754ef2](https://github.com/shinokada/flowbite-svelte-starter/commit/d754ef2c5151af366fe0a8530e6f9509daf79962))

View File

@ -1,9 +0,0 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,2 +1 @@
# learn
Hello

13
houdini.config.js Normal file
View File

@ -0,0 +1,13 @@
/// <references types="houdini-svelte">
/** @type {import('houdini').ConfigFile} */
const config = {
"watchSchema": {
"url": "https://data.andert.me/graphql"
},
"plugins": {
"houdini-svelte": {}
}
}
export default config

76
package.json Normal file
View File

@ -0,0 +1,76 @@
{
"name": "flowbite-svelte-starter",
"version": "0.1.3",
"description": "Flowbite-Svelte starter kit",
"author": {
"name": "Shinichi Okada",
"email": "connect@codewithshin.com",
"url": "https://blog.codewithshin.com"
},
"bugs": "https://github.com/shinokada/flowbite-svelte-starter/issues",
"homepage": "https://github.com/shinokada/flowbite-svelte-starter",
"license": "MIT",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "playwright test",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"test:unit": "vitest",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@playwright/test": "^1.32.1",
"@sveltejs/adapter-auto": "2.0.0",
"@sveltejs/adapter-vercel": "^2.4.1",
"@sveltejs/kit": "1.7.2",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.36.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-svelte3": "^4.0.0",
"flowbite": "^1.6.4",
"flowbite-svelte": "^0.34.2",
"houdini": "^1.1.3",
"houdini-svelte": "^1.1.3",
"postcss": "^8.4.21",
"prettier": "^2.8.7",
"prettier-plugin-svelte": "^2.10.0",
"svelte": "^3.57.0",
"svelte-check": "^2.10.3",
"svelte-heros-v2": "^0.4.2",
"tailwindcss": "^3.2.7",
"tslib": "^2.5.0",
"typescript": "~5.0.2",
"vite": "^4.2.1",
"vitest": "^0.28.5"
},
"type": "module",
"keywords": [
"svelte",
"sveltekit",
"flowbite",
"flowbite-svelte",
"tailwindcss"
],
"engines": {
"npm": ">=7.0.0",
"node": ">=16.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/shinokada/flowbite-svelte-starter.git"
},
"dependencies": {
"@directus/sdk": "^10.3.3",
"@noble/hashes": "^1.3.0",
"@pashword/pashword-lib": "^0.1.11",
"@popperjs/core": "^2.11.7",
"@teamhanko/hanko-elements": "0.2.2-alpha",
"@teamhanko/hanko-frontend-sdk": "0.2.1-alpha",
"classnames": "^2.3.2"
}
}

11
playwright.config.ts Normal file
View File

@ -0,0 +1,11 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'npm run build && npm run preview',
port: 4173
},
testDir: 'tests'
};
export default config;

3818
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

13
postcss.config.cjs Normal file
View File

@ -0,0 +1,13 @@
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer
]
};
module.exports = config;

642
schema.graphql Normal file
View File

@ -0,0 +1,642 @@
"""ISO8601 Date values"""
scalar Date
"""A Float or a String"""
scalar GraphQLStringOrFloat
"""Hashed string values"""
scalar Hash
"""
The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
"""
scalar JSON
type Mutation {
create_Projects_item(data: create_Projects_input!): Projects
create_Projects_items(data: [create_Projects_input!], filter: Projects_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [Projects!]!
create_todos_item(data: create_todos_input!): todos
create_todos_items(data: [create_todos_input!], filter: todos_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [todos!]!
delete_Projects_item(id: ID!): delete_one
delete_Projects_items(ids: [ID]!): delete_many
update_Projects_batch(data: [update_Projects_input!], filter: Projects_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [Projects!]!
update_Projects_item(data: update_Projects_input!, id: ID!): Projects
update_Projects_items(data: update_Projects_input!, filter: Projects_filter, ids: [ID]!, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [Projects!]!
}
type Projects {
date_created: Date
date_created_func: datetime_functions
date_updated: Date
date_updated_func: datetime_functions
favorite: Boolean
id: ID!
name: String
user_created: String
user_updated: String
}
type Projects_aggregated {
avg: Projects_aggregated_fields
avgDistinct: Projects_aggregated_fields
count: Projects_aggregated_count
countAll: Int
countDistinct: Projects_aggregated_count
group: JSON
max: Projects_aggregated_fields
min: Projects_aggregated_fields
sum: Projects_aggregated_fields
sumDistinct: Projects_aggregated_fields
}
type Projects_aggregated_count {
date_created: Int
date_updated: Int
favorite: Int
id: Int
name: Int
user_created: Int
user_updated: Int
}
type Projects_aggregated_fields {
id: Float
}
input Projects_filter {
_and: [Projects_filter]
_or: [Projects_filter]
date_created: date_filter_operators
date_created_func: datetime_function_filter_operators
date_updated: date_filter_operators
date_updated_func: datetime_function_filter_operators
favorite: boolean_filter_operators
id: number_filter_operators
name: string_filter_operators
user_created: string_filter_operators
user_updated: string_filter_operators
}
type Query {
Projects(filter: Projects_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [Projects!]!
Projects_aggregated(filter: Projects_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [Projects_aggregated!]!
Projects_by_id(id: ID!): Projects
apps(filter: apps_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps!]!
apps_aggregated(filter: apps_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_aggregated!]!
apps_by_id(id: ID!): apps
apps_ora_components(filter: apps_ora_components_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_ora_components!]!
apps_ora_components_aggregated(filter: apps_ora_components_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_ora_components_aggregated!]!
apps_ora_components_by_id(id: ID!): apps_ora_components
apps_todos(filter: apps_todos_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_todos!]!
apps_todos_aggregated(filter: apps_todos_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_todos_aggregated!]!
apps_todos_by_id(id: ID!): apps_todos
apps_views(filter: apps_views_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_views!]!
apps_views_aggregated(filter: apps_views_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_views_aggregated!]!
apps_views_by_id(id: ID!): apps_views
ora_components(filter: ora_components_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [ora_components!]!
ora_components_aggregated(filter: ora_components_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [ora_components_aggregated!]!
ora_components_by_id(id: ID!): ora_components
ora_components_code(filter: ora_components_code_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [ora_components_code!]!
ora_components_code_aggregated(filter: ora_components_code_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [ora_components_code_aggregated!]!
ora_components_code_by_id(id: ID!): ora_components_code
todos(filter: todos_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [todos!]!
todos_aggregated(filter: todos_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [todos_aggregated!]!
todos_by_id(id: ID!): todos
views(filter: views_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [views!]!
views_aggregated(filter: views_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [views_aggregated!]!
views_by_id(id: ID!): views
views_collections(filter: views_collections_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [views_collections!]!
views_collections_aggregated(filter: views_collections_filter, groupBy: [String], limit: Int, offset: Int, page: Int, search: String, sort: [String]): [views_collections_aggregated!]!
views_collections_by_id(id: ID!): views_collections
}
type apps {
components(filter: apps_ora_components_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_ora_components]
components_func: count_functions
date_created: Date
date_created_func: datetime_functions
date_updated: Date
date_updated_func: datetime_functions
id: ID!
image: String
name: String
sort: Int
todos(filter: apps_todos_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_todos]
todos_func: count_functions
user_created: String
user_updated: String
views(filter: apps_views_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_views]
views_func: count_functions
}
type apps_aggregated {
avg: apps_aggregated_fields
avgDistinct: apps_aggregated_fields
count: apps_aggregated_count
countAll: Int
countDistinct: apps_aggregated_count
group: JSON
max: apps_aggregated_fields
min: apps_aggregated_fields
sum: apps_aggregated_fields
sumDistinct: apps_aggregated_fields
}
type apps_aggregated_count {
components: Int
date_created: Int
date_updated: Int
id: Int
image: Int
name: Int
sort: Int
todos: Int
user_created: Int
user_updated: Int
views: Int
}
type apps_aggregated_fields {
sort: Float
}
input apps_filter {
_and: [apps_filter]
_or: [apps_filter]
components: apps_ora_components_filter
components_func: count_function_filter_operators
date_created: date_filter_operators
date_created_func: datetime_function_filter_operators
date_updated: date_filter_operators
date_updated_func: datetime_function_filter_operators
id: string_filter_operators
image: string_filter_operators
name: string_filter_operators
sort: number_filter_operators
todos: apps_todos_filter
todos_func: count_function_filter_operators
user_created: string_filter_operators
user_updated: string_filter_operators
views: apps_views_filter
views_func: count_function_filter_operators
}
type apps_ora_components {
apps_id(filter: apps_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): apps
id: ID!
ora_components_id(filter: ora_components_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): ora_components
}
type apps_ora_components_aggregated {
avg: apps_ora_components_aggregated_fields
avgDistinct: apps_ora_components_aggregated_fields
count: apps_ora_components_aggregated_count
countAll: Int
countDistinct: apps_ora_components_aggregated_count
group: JSON
max: apps_ora_components_aggregated_fields
min: apps_ora_components_aggregated_fields
sum: apps_ora_components_aggregated_fields
sumDistinct: apps_ora_components_aggregated_fields
}
type apps_ora_components_aggregated_count {
apps_id: Int
id: Int
ora_components_id: Int
}
type apps_ora_components_aggregated_fields {
id: Float
}
input apps_ora_components_filter {
_and: [apps_ora_components_filter]
_or: [apps_ora_components_filter]
apps_id: apps_filter
id: number_filter_operators
ora_components_id: ora_components_filter
}
type apps_todos {
apps_id(filter: apps_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): apps
id: ID!
todos_id(filter: todos_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): todos
}
type apps_todos_aggregated {
avg: apps_todos_aggregated_fields
avgDistinct: apps_todos_aggregated_fields
count: apps_todos_aggregated_count
countAll: Int
countDistinct: apps_todos_aggregated_count
group: JSON
max: apps_todos_aggregated_fields
min: apps_todos_aggregated_fields
sum: apps_todos_aggregated_fields
sumDistinct: apps_todos_aggregated_fields
}
type apps_todos_aggregated_count {
apps_id: Int
id: Int
todos_id: Int
}
type apps_todos_aggregated_fields {
id: Float
}
input apps_todos_filter {
_and: [apps_todos_filter]
_or: [apps_todos_filter]
apps_id: apps_filter
id: number_filter_operators
todos_id: todos_filter
}
type apps_views {
apps_id(filter: apps_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): apps
id: ID!
views_id(filter: views_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): views
}
type apps_views_aggregated {
avg: apps_views_aggregated_fields
avgDistinct: apps_views_aggregated_fields
count: apps_views_aggregated_count
countAll: Int
countDistinct: apps_views_aggregated_count
group: JSON
max: apps_views_aggregated_fields
min: apps_views_aggregated_fields
sum: apps_views_aggregated_fields
sumDistinct: apps_views_aggregated_fields
}
type apps_views_aggregated_count {
apps_id: Int
id: Int
views_id: Int
}
type apps_views_aggregated_fields {
id: Float
}
input apps_views_filter {
_and: [apps_views_filter]
_or: [apps_views_filter]
apps_id: apps_filter
id: number_filter_operators
views_id: views_filter
}
input boolean_filter_operators {
_eq: Boolean
_neq: Boolean
_nnull: Boolean
_null: Boolean
}
input count_function_filter_operators {
count: number_filter_operators
}
type count_functions {
count: Int
}
input create_Projects_input {
date_created: Date
date_updated: Date
favorite: Boolean
id: ID
name: String
user_created: create_directus_users_input
user_updated: create_directus_users_input
}
input create_directus_users_input {
avatar: String
description: String
email: String
first_name: String
last_name: String
location: String
password: Hash
role: String
title: String
}
input create_todos_input {
date_created: Date
date_updated: Date
id: ID
name: String
user_created: create_directus_users_input
user_updated: create_directus_users_input
}
input date_filter_operators {
_between: [GraphQLStringOrFloat]
_eq: String
_gt: String
_gte: String
_in: [String]
_lt: String
_lte: String
_nbetween: [GraphQLStringOrFloat]
_neq: String
_nin: [String]
_nnull: Boolean
_null: Boolean
}
input datetime_function_filter_operators {
day: number_filter_operators
hour: number_filter_operators
minute: number_filter_operators
month: number_filter_operators
second: number_filter_operators
week: number_filter_operators
weekday: number_filter_operators
year: number_filter_operators
}
type datetime_functions {
day: Int
hour: Int
minute: Int
month: Int
second: Int
week: Int
weekday: Int
year: Int
}
type delete_many {
ids: [ID]!
}
type delete_one {
id: ID!
}
input number_filter_operators {
_between: [GraphQLStringOrFloat]
_eq: GraphQLStringOrFloat
_gt: GraphQLStringOrFloat
_gte: GraphQLStringOrFloat
_in: [GraphQLStringOrFloat]
_lt: GraphQLStringOrFloat
_lte: GraphQLStringOrFloat
_nbetween: [GraphQLStringOrFloat]
_neq: GraphQLStringOrFloat
_nin: [GraphQLStringOrFloat]
_nnull: Boolean
_null: Boolean
}
type ora_components {
apps(filter: apps_ora_components_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [apps_ora_components]
apps_func: count_functions
code: String
date_created: Date
date_created_func: datetime_functions
date_updated: Date
date_updated_func: datetime_functions
id: ID!
name: String!
svelte: String
user_created: String
user_updated: String
}
type ora_components_aggregated {
count: ora_components_aggregated_count
countAll: Int
countDistinct: ora_components_aggregated_count
group: JSON
}
type ora_components_aggregated_count {
apps: Int
code: Int
date_created: Int
date_updated: Int
id: Int
name: Int
svelte: Int
user_created: Int
user_updated: Int
}
type ora_components_code {
collection: String
id: ID!
item: ora_components_code_item_union
ora_components_id(filter: ora_components_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): ora_components
}
type ora_components_code_aggregated {
avg: ora_components_code_aggregated_fields
avgDistinct: ora_components_code_aggregated_fields
count: ora_components_code_aggregated_count
countAll: Int
countDistinct: ora_components_code_aggregated_count
group: JSON
max: ora_components_code_aggregated_fields
min: ora_components_code_aggregated_fields
sum: ora_components_code_aggregated_fields
sumDistinct: ora_components_code_aggregated_fields
}
type ora_components_code_aggregated_count {
collection: Int
id: Int
item: Int
ora_components_id: Int
}
type ora_components_code_aggregated_fields {
id: Float
}
input ora_components_code_filter {
_and: [ora_components_code_filter]
_or: [ora_components_code_filter]
collection: string_filter_operators
id: number_filter_operators
item__ora_components: ora_components_filter
ora_components_id: ora_components_filter
}
union ora_components_code_item_union = ora_components
input ora_components_filter {
_and: [ora_components_filter]
_or: [ora_components_filter]
apps: apps_ora_components_filter
apps_func: count_function_filter_operators
code: string_filter_operators
date_created: date_filter_operators
date_created_func: datetime_function_filter_operators
date_updated: date_filter_operators
date_updated_func: datetime_function_filter_operators
id: string_filter_operators
name: string_filter_operators
svelte: string_filter_operators
user_created: string_filter_operators
user_updated: string_filter_operators
}
input string_filter_operators {
_contains: String
_empty: Boolean
_ends_with: String
_eq: String
_icontains: String
_in: [String]
_ncontains: String
_nempty: Boolean
_nends_with: String
_neq: String
_nin: [String]
_nnull: Boolean
_nstarts_with: String
_null: Boolean
_starts_with: String
}
type todos {
date_created: Date
date_created_func: datetime_functions
date_updated: Date
date_updated_func: datetime_functions
id: ID!
name: String
user_created: String
user_updated: String
}
type todos_aggregated {
count: todos_aggregated_count
countAll: Int
countDistinct: todos_aggregated_count
group: JSON
}
type todos_aggregated_count {
date_created: Int
date_updated: Int
id: Int
name: Int
user_created: Int
user_updated: Int
}
input todos_filter {
_and: [todos_filter]
_or: [todos_filter]
date_created: date_filter_operators
date_created_func: datetime_function_filter_operators
date_updated: date_filter_operators
date_updated_func: datetime_function_filter_operators
id: string_filter_operators
name: string_filter_operators
user_created: string_filter_operators
user_updated: string_filter_operators
}
input update_Projects_input {
date_created: Date
date_updated: Date
favorite: Boolean
id: ID
name: String
user_created: String
user_updated: String
}
type views {
date_created: Date
date_created_func: datetime_functions
date_updated: Date
date_updated_func: datetime_functions
id: ID!
name: String
user_created: String
user_updated: String
}
type views_aggregated {
count: views_aggregated_count
countAll: Int
countDistinct: views_aggregated_count
group: JSON
}
type views_aggregated_count {
date_created: Int
date_updated: Int
id: Int
name: Int
user_created: Int
user_updated: Int
}
type views_collections {
collection: String
id: ID!
item: views_collections_item_union
views_id(filter: views_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): views
}
type views_collections_aggregated {
avg: views_collections_aggregated_fields
avgDistinct: views_collections_aggregated_fields
count: views_collections_aggregated_count
countAll: Int
countDistinct: views_collections_aggregated_count
group: JSON
max: views_collections_aggregated_fields
min: views_collections_aggregated_fields
sum: views_collections_aggregated_fields
sumDistinct: views_collections_aggregated_fields
}
type views_collections_aggregated_count {
collection: Int
id: Int
item: Int
views_id: Int
}
type views_collections_aggregated_fields {
id: Float
}
input views_collections_filter {
_and: [views_collections_filter]
_or: [views_collections_filter]
collection: string_filter_operators
id: number_filter_operators
item__todos: todos_filter
views_id: views_filter
}
union views_collections_item_union = todos
input views_filter {
_and: [views_filter]
_or: [views_filter]
date_created: date_filter_operators
date_created_func: datetime_function_filter_operators
date_updated: date_filter_operators
date_updated_func: datetime_function_filter_operators
id: string_filter_operators
name: string_filter_operators
user_created: string_filter_operators
user_updated: string_filter_operators
}

4
src/app.css Normal file
View File

@ -0,0 +1,4 @@
/* Write your global styles here, in PostCSS syntax */
@tailwind base;
@tailwind components;
@tailwind utilities;

10
src/app.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/// <reference types="@sveltejs/kit" />
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare namespace App {
// interface Locals {}
// interface Platform {}
// interface Session {}
// interface Stuff {}
}

12
src/app.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover" class="bg-white dark:bg-gray-800">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

5
src/client.js Normal file
View File

@ -0,0 +1,5 @@
import { HoudiniClient } from '$houdini';
export default new HoudiniClient({
url: 'https://data.andert.me/graphql',
})

View File

@ -0,0 +1,45 @@
<script lang="ts">
import { onMount } from 'svelte';
import { register } from '@teamhanko/hanko-elements';
import { Hanko } from '@teamhanko/hanko-frontend-sdk';
import { Button } from 'flowbite-svelte';
import { goto } from '$app/navigation';
import { config } from '$lib/config.js';
const api = config.hanko;
const hanko = new Hanko(config.hanko);
let element;
let user;
let error: Error | null = null;
onMount(async () => {
register({ shadow: true }).catch((e) => (error = e));
element;
user = await hanko.user.getCurrent();
console.log('Get Credentials: ', await navigator.credentials.get());
});
const logout = () => {
hanko.user.logout();
goto('/');
};
</script>
{#if error}
<div class="error">{error?.message}</div>
{/if}
{#if user}
<div>
<div class="dark:text-white p-2">Welcome {user.email}</div>
<Button color="red" on:click={logout}>Logout</Button>
</div>
{:else}
not logged in
{/if}
<hanko-profile {api} />

View File

@ -0,0 +1,33 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { register } from '@teamhanko/hanko-elements';
import { Hanko } from '@teamhanko/hanko-frontend-sdk';
import { Button, Modal } from 'flowbite-svelte';
import { config } from '$lib/config.js';
let defaultModal = false;
const api = config.hanko;
const hanko = new Hanko(config.hanko);
let element;
let user;
let error: Error | null = null;
onMount(async () => {
register({ shadow: true }).catch((e) => (error = e));
user = await hanko.user.getCurrent();
});
</script>
{#if !user}
<Button on:click={() => (defaultModal = true)}>Login</Button>
{/if}
<Modal title="Profile" bind:open={defaultModal} autoclose>
{#if error}
<div class="error">{error?.message}</div>
{/if}
<hanko-auth bind:this={element} {api} />
</Modal>

View File

@ -0,0 +1,57 @@
<script>
import { page } from '$app/stores';
import { Sidebar, SidebarGroup, SidebarItem, SidebarWrapper } from 'flowbite-svelte';
let spanClass = 'flex-1 ml-3 whitespace-nowrap';
$: activeUrl = $page.url.pathname
</script>
<Sidebar>
<SidebarWrapper>
<SidebarGroup>
<SidebarItem label="Dashboard">
<svelte:fragment slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M10.5 6a7.5 7.5 0 107.5 7.5h-7.5V6z" /><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 10.5H21A7.5 7.5 0 0013.5 3v7.5z" /></svg>
</svelte:fragment>
</SidebarItem>
<SidebarItem label="Kanban" {spanClass}>
<svelte:fragment slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z" /></svg>
</svelte:fragment>
<svelte:fragment slot="subtext">
<span
class="inline-flex justify-center items-center px-2 ml-3 text-sm font-medium text-gray-800 bg-gray-200 rounded-full dark:bg-gray-700 dark:text-gray-300"
>Pro</span
>
</svelte:fragment>
</SidebarItem>
<SidebarItem label="Inbox" {spanClass}>
<svelte:fragment slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M9 3.75H6.912a2.25 2.25 0 00-2.15 1.588L2.35 13.177a2.25 2.25 0 00-.1.661V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18v-4.162c0-.224-.034-.447-.1-.661L19.24 5.338a2.25 2.25 0 00-2.15-1.588H15M2.25 13.5h3.86a2.25 2.25 0 012.012 1.244l.256.512a2.25 2.25 0 002.013 1.244h3.218a2.25 2.25 0 002.013-1.244l.256-.512a2.25 2.25 0 012.013-1.244h3.859M12 3v8.25m0 0l-3-3m3 3l3-3" /></svg>
</svelte:fragment>
<svelte:fragment slot="subtext">
<span
class="inline-flex justify-center items-center p-3 ml-3 w-3 h-3 text-sm font-medium text-blue-600 bg-blue-200 rounded-full dark:bg-blue-900 dark:text-blue-200"
>3</span
>
</svelte:fragment>
</SidebarItem>
<SidebarItem label="Sidebar" href='/component/sidebar' active={activeUrl === '/components/sidebar'}>
<svelte:fragment slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" /></svg>
</svelte:fragment>
</SidebarItem>
</SidebarGroup>
<SidebarGroup border>
<SidebarItem label="Sign In">
<svelte:fragment slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75" /></svg>
</svelte:fragment>
</SidebarItem>
<SidebarItem label="Sign Up">
<svelte:fragment slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12a7.5 7.5 0 0015 0m-15 0a7.5 7.5 0 1115 0m-15 0H3m16.5 0H21m-1.5 0H12m-8.457 3.077l1.41-.513m14.095-5.13l1.41-.513M5.106 17.785l1.15-.964m11.49-9.642l1.149-.964M7.501 19.795l.75-1.3m7.5-12.99l.75-1.3m-6.063 16.658l.26-1.477m2.605-14.772l.26-1.477m0 17.726l-.26-1.477M10.698 4.614l-.26-1.477M16.5 19.794l-.75-1.299M7.5 4.205L12 12m6.894 5.785l-1.149-.964M6.256 7.178l-1.15-.964m15.352 8.864l-1.41-.513M4.954 9.435l-1.41-.514M12.002 12l-3.75 6.495" /></svg>
</svelte:fragment>
</SidebarItem>
</SidebarGroup>
</SidebarWrapper>
</Sidebar>

8
src/lib/config.ts Normal file
View File

@ -0,0 +1,8 @@
let process: any;
const p = process?.env ? process.env : import.meta.env;
export const config = {
"hanko": p.VITE_HANKO_API,
"pashword": p.VITE_PASHWORD_SALT,
};

5
src/routes/+error.svelte Normal file
View File

@ -0,0 +1,5 @@
<script>
import { Button } from 'flowbite-svelte';
</script>
not found

42
src/routes/+layout.svelte Normal file
View File

@ -0,0 +1,42 @@
<script>
import '../app.css';
import { Navbar, NavBrand, NavLi, NavUl, NavHamburger } from 'flowbite-svelte';
import { DarkMode } from 'flowbite-svelte';
import { onMount } from 'svelte';
import { Hanko } from '@teamhanko/hanko-frontend-sdk';
const hanko = new Hanko(import.meta.env.VITE_HANKO_API);
let user;
onMount(async () => {
user = await hanko.user.getCurrent();
});
let darkmodebtn =
'text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-lg p-2.5 fixed right-4 top-2 z-50';
</script>
<div class="h-screen w-screen fixed">
<Navbar let:hidden let:toggle>
<NavBrand href="/">
<img
src="https://flowbite.com/docs/images/logo.svg"
class="mr-3 h-6 sm:h-9"
alt="Flowbite Logo"
/>
<span class="self-center whitespace-nowrap text-xl font-semibold dark:text-white">
Ora Earth
</span>
</NavBrand>
<NavHamburger on:click={toggle} />
<NavUl {hidden}>
<NavLi href="/" active={true}>Home</NavLi>
{#if user}
<NavLi href="/projects">Projects</NavLi>
<NavLi href="/account">Account</NavLi>
{/if}
</NavUl>
<DarkMode btnClass={darkmodebtn} />
</Navbar>
<slot />
</div>

18
src/routes/+page.svelte Normal file
View File

@ -0,0 +1,18 @@
<script>
import { Heading, P } from 'flowbite-svelte';
import Login from '$lib/components/Login.svelte';
</script>
<div class="text-center py-12">
<Heading tag="h1" class="mb-4" customSize="text-4xl font-extrabold md:text-5xl lg:text-6xl"
>We invest into your full human potential</Heading
>
<P class="mb-6 text-lg lg:text-xl sm:px-16 xl:px-48 dark:text-gray-400"
>At Ora we focus on you and where your passion evolves, to unlock long-term personal and
economic growth.</P
>
</div>
<div class="flex flex-col items-center justify-center">
<Login />
</div>

View File

@ -0,0 +1,73 @@
<script>
import Account from '$lib/components/Account.svelte';
import { Hanko } from '@teamhanko/hanko-frontend-sdk';
import { onMount } from 'svelte';
import { generatePashword } from '@pashword/pashword-lib';
import { Button } from 'flowbite-svelte';
import { config } from '$lib/config';
const hanko = new Hanko(config.hanko);
let user;
onMount(async () => {
user = await hanko.user.getCurrent();
});
async function signUpDirectusUser() {
let pashedPassword = await generatePashword(
JSON.stringify(user.webauthn_credentials[0].id + config.pashword),
32,
'https://data.andert.me',
user.email
);
// Create new directus user
const object = {
email: user.email,
password: pashedPassword,
role: 'b0f4301f-a315-4b95-8352-9016a8f95f2d'
};
const responseCreate = await fetch('https://data.andert.me/users', {
method: 'POST',
body: JSON.stringify(object),
headers: {
'Content-Type': 'application/json'
}
});
const responseText = await responseCreate.json();
console.log(responseText);
}
async function authDirectusUser() {
let pashedPassword = await generatePashword(
JSON.stringify(user.webauthn_credentials[0].id + import.meta.env.VITE_PASHWORD_SALT),
32,
'https://data.andert.me',
user.email
);
const object = {
email: user.email,
password: pashedPassword
};
const response = await fetch('https://data.andert.me/auth/login', {
method: 'POST',
body: JSON.stringify(object),
headers: {
'Content-Type': 'application/json'
}
});
const responseOutput = await response.json();
console.log(responseOutput.data.access_token);
}
</script>
<div class="h-full w-full grid overflow-scroll p-12">
<div>
<Button on:click={signUpDirectusUser}>Create Directus User</Button>
<Button color="yellow" on:click={authDirectusUser}>Authenticate</Button>
<Account />
</div>
</div>

View File

@ -0,0 +1,12 @@
query Projects($id: ID! = 7) {
Projects_by_id(id: $id) {
id
name
favorite
}
Projects {
id
name
favorite
}
}

View File

@ -0,0 +1,117 @@
<script>
import { graphql } from '$houdini';
import { goto } from '$app/navigation';
import { Star } from 'svelte-heros-v2';
import {
Card,
Avatar,
Button,
Table,
TableBody,
TableBodyCell,
TableBodyRow,
TableHead,
TableHeadCell
} from 'flowbite-svelte';
export let data;
const createProject = graphql(`
mutation CreateProject($name: String!) {
create_Projects_item(data: { name: $name }) {
id
name
favorite
}
}
`);
const toggleFavorite = graphql(`
mutation ToggleFavorite($id: ID!, $favorite: Boolean!) {
update_Projects_item(id: $id, data: { favorite: $favorite }) {
id
name
favorite
}
}
`);
const deleteProject = graphql(`
mutation DeleteProject($id: ID!) {
delete_Projects_item(id: $id) {
id
}
}
`);
$: ({ Projects } = data);
</script>
{#if $Projects.fetching}
fetching
{:else}
<div class="flex-1 p-8">
<div class="grid grid-cols-6 gap-4">
<div class="col-start-1 col-end-5">
<Button on:click={() => createProject.mutate({ name: 'Test' })}>Create New</Button>
<Table>
<TableHead>
<TableHeadCell>ID</TableHeadCell>
<TableHeadCell>Product</TableHeadCell>
<TableHeadCell>Favorite</TableHeadCell>
</TableHead>
<TableBody>
{#each $Projects.data.Projects as item}
<TableBodyRow on:click={() => goto('/projects/' + item.id)}>
<TableBodyCell>{item.id}</TableBodyCell>
<TableBodyCell>{item.name}</TableBodyCell>
<TableBodyCell>
{#if item.favorite}
<Star size="20" variation="solid" class="text-yellow-300" />
{:else}
<Star size="20" class="text-gray-300" />
{/if}</TableBodyCell
>
</TableBodyRow>
{:else}
<p>No Favorites Selected</p>
{/each}
</TableBody>
</Table>
</div>
<div class="col-end-7 col-span-2">
<Card padding="sm">
<div class="flex flex-col items-center pb-4">
<Avatar
size="lg"
src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80"
/>
<h5 class="mb-1 text-xl font-medium text-gray-900 dark:text-white">
{$Projects.data.Projects_by_id.name}
</h5>
<span class="text-sm text-gray-500 dark:text-gray-400"
>{$Projects.data.Projects_by_id.id}</span
>
{#if $Projects.data.Projects_by_id.favorite}
<Star size="50" variation="solid" class="text-yellow-300" />
{:else}
<Star size="50" class="text-gray-300" />
{/if}
<div class="flex mt-4 space-x-3 lg:mt-6">
<Button
color="yellow"
on:click={() =>
toggleFavorite.mutate({
id: $Projects.data.Projects_by_id.id,
favorite: !$Projects.data.Projects_by_id.favorite
})}>Favorite</Button
>
<Button
on:click={() => deleteProject.mutate({ id: $Projects.data.Projects_by_id.id })}
color="red"
class="dark:text-white">Delete</Button
>
</div>
</div>
</Card>
</div>
</div>
</div>
{/if}

BIN
static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

18
svelte.config.js Normal file
View File

@ -0,0 +1,18 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
adapter: adapter(),
alias: {
$houdini: './$houdini',
}
}
};
export default config;

17
tailwind.config.cjs Normal file
View File

@ -0,0 +1,17 @@
const config = {
content: [
'./src/**/*.{html,js,svelte,ts}',
'./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}',
],
theme: {
extend: {
}
},
plugins: [require('flowbite/plugin')],
darkMode: 'class'
};
module.exports = config;

6
tests/test.ts Normal file
View File

@ -0,0 +1,6 @@
import { expect, test } from '@playwright/test';
test('index page has expected h1', async ({ page }) => {
await page.goto('/');
expect(await page.textContent('h1')).toBe('Welcome to SvelteKit');
});

21
tsconfig.json Normal file
View File

@ -0,0 +1,21 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"types": [
"vite/client"
],
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"rootDirs": [
".",
"./.svelte-kit/types",
"./$houdini/types"
]
}
}

15
vite.config.js Normal file
View File

@ -0,0 +1,15 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
import houdini from 'houdini/vite'
export default defineConfig({
plugins: [houdini(), sveltekit()],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
},
resolve: {
alias: {
$houdini: './$houdini',
},
},
});