Convert backend/web from submodule to regular directory
@@ -0,0 +1,28 @@
|
||||
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-*
|
||||
# SQLite
|
||||
*.db
|
||||
*.db.wal
|
||||
|
||||
.fontello
|
||||
@@ -0,0 +1 @@
|
||||
engine-strict=true
|
||||
@@ -0,0 +1,9 @@
|
||||
# Package Managers
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
bun.lock
|
||||
bun.lockb
|
||||
|
||||
# Miscellaneous
|
||||
/static/
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"svelte.svelte-vscode",
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"bradlc.vscode-tailwindcss"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.css": "tailwindcss"
|
||||
},
|
||||
"svelte/no-navigation-without-resolve": [
|
||||
"error",
|
||||
{
|
||||
"ignoreGoto": false,
|
||||
"ignoreLinks": false,
|
||||
"ignorePushState": false,
|
||||
"ignoreReplaceState": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
FONT_DIR ?= ./static/assets/fontello
|
||||
FONTELLO_HOST ?= https://fontello.com
|
||||
|
||||
|
||||
fontopen:
|
||||
@if test ! `which curl` ; then \
|
||||
echo 'Install curl first.' >&2 ; \
|
||||
exit 128 ; \
|
||||
fi
|
||||
curl --silent --show-error --fail --output .fontello \
|
||||
--form "config=@${FONT_DIR}/config.json" \
|
||||
${FONTELLO_HOST}
|
||||
xdg-open ${FONTELLO_HOST}/`cat .fontello`
|
||||
|
||||
fontsave:
|
||||
@if test ! `which unzip` ; then \
|
||||
echo 'Install unzip first.' >&2 ; \
|
||||
exit 128 ; \
|
||||
fi
|
||||
@if test ! -e .fontello ; then \
|
||||
echo 'Run `make fontopen` first.' >&2 ; \
|
||||
exit 128 ; \
|
||||
fi
|
||||
rm -rf .fontello.src .fontello.zip
|
||||
curl --silent --show-error --fail --output .fontello.zip \
|
||||
${FONTELLO_HOST}/`cat .fontello`/get
|
||||
unzip .fontello.zip -d .fontello.src
|
||||
rm -rf ${FONT_DIR}
|
||||
mv `find ./.fontello.src -maxdepth 1 -name 'fontello-*'` ${FONT_DIR}
|
||||
rm -rf .fontello.src .fontello.zip
|
||||
@@ -0,0 +1,42 @@
|
||||
# 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!
|
||||
|
||||
```sh
|
||||
# create a new project
|
||||
npx sv create my-app
|
||||
```
|
||||
|
||||
To recreate this project with the same configuration:
|
||||
|
||||
```sh
|
||||
# recreate this project
|
||||
npx sv@0.17.0 create --template minimal --types ts --add prettier eslint tailwindcss="plugins:typography,forms" better-auth="demo:password,github" drizzle="database:sqlite+sqlite:turso" --no-install ./
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
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.
|
||||
@@ -0,0 +1,382 @@
|
||||
{
|
||||
"auditReportVersion": 2,
|
||||
"vulnerabilities": {
|
||||
"@chevrotain/cst-dts-gen": {
|
||||
"name": "@chevrotain/cst-dts-gen",
|
||||
"severity": "moderate",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
"@chevrotain/gast",
|
||||
"lodash"
|
||||
],
|
||||
"effects": [
|
||||
"chevrotain"
|
||||
],
|
||||
"range": "10.0.0 - 10.5.0",
|
||||
"nodes": [
|
||||
"node_modules/@chevrotain/cst-dts-gen"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "auth",
|
||||
"version": "1.2.3",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"@chevrotain/gast": {
|
||||
"name": "@chevrotain/gast",
|
||||
"severity": "moderate",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
"lodash"
|
||||
],
|
||||
"effects": [
|
||||
"@chevrotain/cst-dts-gen",
|
||||
"chevrotain"
|
||||
],
|
||||
"range": "<=10.5.0",
|
||||
"nodes": [
|
||||
"node_modules/@chevrotain/gast"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "auth",
|
||||
"version": "1.2.3",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"@esbuild-kit/core-utils": {
|
||||
"name": "@esbuild-kit/core-utils",
|
||||
"severity": "moderate",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
"esbuild"
|
||||
],
|
||||
"effects": [
|
||||
"@esbuild-kit/esm-loader"
|
||||
],
|
||||
"range": "*",
|
||||
"nodes": [
|
||||
"node_modules/@esbuild-kit/core-utils"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "drizzle-kit",
|
||||
"version": "0.18.1",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"@esbuild-kit/esm-loader": {
|
||||
"name": "@esbuild-kit/esm-loader",
|
||||
"severity": "moderate",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
"@esbuild-kit/core-utils"
|
||||
],
|
||||
"effects": [
|
||||
"drizzle-kit"
|
||||
],
|
||||
"range": "*",
|
||||
"nodes": [
|
||||
"node_modules/@esbuild-kit/esm-loader"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "drizzle-kit",
|
||||
"version": "0.18.1",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"@mrleebo/prisma-ast": {
|
||||
"name": "@mrleebo/prisma-ast",
|
||||
"severity": "moderate",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
"chevrotain"
|
||||
],
|
||||
"effects": [
|
||||
"auth"
|
||||
],
|
||||
"range": "0.4.2 - 0.13.1",
|
||||
"nodes": [
|
||||
"node_modules/@mrleebo/prisma-ast"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "auth",
|
||||
"version": "1.2.3",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"@sveltejs/adapter-auto": {
|
||||
"name": "@sveltejs/adapter-auto",
|
||||
"severity": "low",
|
||||
"isDirect": true,
|
||||
"via": [
|
||||
"@sveltejs/kit"
|
||||
],
|
||||
"effects": [],
|
||||
"range": "1.0.0-next.0 - 8.0.0-next.0",
|
||||
"nodes": [
|
||||
"node_modules/@sveltejs/adapter-auto"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "@sveltejs/adapter-auto",
|
||||
"version": "0.0.1",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"@sveltejs/kit": {
|
||||
"name": "@sveltejs/kit",
|
||||
"severity": "low",
|
||||
"isDirect": true,
|
||||
"via": [
|
||||
"cookie"
|
||||
],
|
||||
"effects": [
|
||||
"@sveltejs/adapter-auto",
|
||||
"better-auth"
|
||||
],
|
||||
"range": "1.0.0-next.0 - 2.70.2",
|
||||
"nodes": [
|
||||
"node_modules/@sveltejs/kit"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "@sveltejs/kit",
|
||||
"version": "0.0.30",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"name": "auth",
|
||||
"severity": "moderate",
|
||||
"isDirect": true,
|
||||
"via": [
|
||||
"@mrleebo/prisma-ast",
|
||||
"better-auth"
|
||||
],
|
||||
"effects": [],
|
||||
"range": ">=1.5.0-beta.15",
|
||||
"nodes": [
|
||||
"node_modules/auth"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "auth",
|
||||
"version": "1.2.3",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"better-auth": {
|
||||
"name": "better-auth",
|
||||
"severity": "low",
|
||||
"isDirect": true,
|
||||
"via": [
|
||||
"@sveltejs/kit"
|
||||
],
|
||||
"effects": [
|
||||
"auth"
|
||||
],
|
||||
"range": "1.3.10-beta.1 - 1.3.21 || 1.4.0-beta.1 - 1.4.0-beta.28 || >=1.4.4-beta.1",
|
||||
"nodes": [
|
||||
"node_modules/better-auth"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "better-auth",
|
||||
"version": "1.4.3",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"chevrotain": {
|
||||
"name": "chevrotain",
|
||||
"severity": "moderate",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
"@chevrotain/cst-dts-gen",
|
||||
"@chevrotain/gast",
|
||||
"lodash"
|
||||
],
|
||||
"effects": [
|
||||
"@mrleebo/prisma-ast"
|
||||
],
|
||||
"range": "10.0.0 - 10.5.0",
|
||||
"nodes": [
|
||||
"node_modules/chevrotain"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "auth",
|
||||
"version": "1.2.3",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"cookie": {
|
||||
"name": "cookie",
|
||||
"severity": "low",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
{
|
||||
"source": 1103907,
|
||||
"name": "cookie",
|
||||
"dependency": "cookie",
|
||||
"title": "cookie accepts cookie name, path, and domain with out of bounds characters",
|
||||
"url": "https://github.com/advisories/GHSA-pxg6-pf52-xh8x",
|
||||
"severity": "low",
|
||||
"cwe": [
|
||||
"CWE-74"
|
||||
],
|
||||
"cvss": {
|
||||
"score": 0,
|
||||
"vectorString": null
|
||||
},
|
||||
"range": "<0.7.0"
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
"@sveltejs/kit"
|
||||
],
|
||||
"range": "<0.7.0",
|
||||
"nodes": [
|
||||
"node_modules/cookie"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "@sveltejs/kit",
|
||||
"version": "0.0.30",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"drizzle-kit": {
|
||||
"name": "drizzle-kit",
|
||||
"severity": "moderate",
|
||||
"isDirect": true,
|
||||
"via": [
|
||||
"@esbuild-kit/esm-loader"
|
||||
],
|
||||
"effects": [],
|
||||
"range": "0.19.0 - 1.0.0-beta.1-fd8bfcc",
|
||||
"nodes": [
|
||||
"node_modules/drizzle-kit"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "drizzle-kit",
|
||||
"version": "0.18.1",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"name": "esbuild",
|
||||
"severity": "moderate",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
{
|
||||
"source": 1102341,
|
||||
"name": "esbuild",
|
||||
"dependency": "esbuild",
|
||||
"title": "esbuild enables any website to send any requests to the development server and read the response",
|
||||
"url": "https://github.com/advisories/GHSA-67mh-4wv8-2f99",
|
||||
"severity": "moderate",
|
||||
"cwe": [
|
||||
"CWE-346"
|
||||
],
|
||||
"cvss": {
|
||||
"score": 5.3,
|
||||
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N"
|
||||
},
|
||||
"range": "<=0.24.2"
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
"@esbuild-kit/core-utils"
|
||||
],
|
||||
"range": "<=0.24.2",
|
||||
"nodes": [
|
||||
"node_modules/@esbuild-kit/core-utils/node_modules/esbuild"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "drizzle-kit",
|
||||
"version": "0.18.1",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"name": "lodash",
|
||||
"severity": "high",
|
||||
"isDirect": false,
|
||||
"via": [
|
||||
{
|
||||
"source": 1115806,
|
||||
"name": "lodash",
|
||||
"dependency": "lodash",
|
||||
"title": "lodash vulnerable to Code Injection via `_.template` imports key names",
|
||||
"url": "https://github.com/advisories/GHSA-r5fr-rjxr-66jc",
|
||||
"severity": "high",
|
||||
"cwe": [
|
||||
"CWE-94"
|
||||
],
|
||||
"cvss": {
|
||||
"score": 8.1,
|
||||
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
||||
},
|
||||
"range": ">=4.0.0 <=4.17.23"
|
||||
},
|
||||
{
|
||||
"source": 1115810,
|
||||
"name": "lodash",
|
||||
"dependency": "lodash",
|
||||
"title": "lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and `_.omit`",
|
||||
"url": "https://github.com/advisories/GHSA-f23m-r3pf-42rh",
|
||||
"severity": "moderate",
|
||||
"cwe": [
|
||||
"CWE-1321"
|
||||
],
|
||||
"cvss": {
|
||||
"score": 6.5,
|
||||
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L"
|
||||
},
|
||||
"range": "<=4.17.23"
|
||||
},
|
||||
{
|
||||
"source": 1120370,
|
||||
"name": "lodash",
|
||||
"dependency": "lodash",
|
||||
"title": "Lodash has Prototype Pollution Vulnerability in `_.unset` and `_.omit` functions",
|
||||
"url": "https://github.com/advisories/GHSA-xxjr-mmjv-4gpg",
|
||||
"severity": "moderate",
|
||||
"cwe": [
|
||||
"CWE-1321"
|
||||
],
|
||||
"cvss": {
|
||||
"score": 6.5,
|
||||
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L"
|
||||
},
|
||||
"range": ">=4.0.0 <=4.17.22"
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
"@chevrotain/cst-dts-gen",
|
||||
"@chevrotain/gast",
|
||||
"chevrotain"
|
||||
],
|
||||
"range": "<=4.17.23",
|
||||
"nodes": [
|
||||
"node_modules/lodash"
|
||||
],
|
||||
"fixAvailable": {
|
||||
"name": "auth",
|
||||
"version": "1.2.3",
|
||||
"isSemVerMajor": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"vulnerabilities": {
|
||||
"info": 0,
|
||||
"low": 4,
|
||||
"moderate": 9,
|
||||
"high": 1,
|
||||
"critical": 0,
|
||||
"total": 14
|
||||
},
|
||||
"dependencies": {
|
||||
"prod": 2,
|
||||
"dev": 451,
|
||||
"optional": 139,
|
||||
"peer": 0,
|
||||
"peerOptional": 0,
|
||||
"total": 452
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import prettier from 'eslint-config-prettier';
|
||||
import path from 'node:path';
|
||||
import js from '@eslint/js';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
import { defineConfig, includeIgnoreFile } from 'eslint/config';
|
||||
import globals from 'globals';
|
||||
import ts from 'typescript-eslint';
|
||||
|
||||
const gitignorePath = path.resolve(import.meta.dirname, '.gitignore');
|
||||
|
||||
export default defineConfig(
|
||||
includeIgnoreFile(gitignorePath),
|
||||
js.configs.recommended,
|
||||
ts.configs.recommended,
|
||||
svelte.configs.recommended,
|
||||
prettier,
|
||||
svelte.configs.prettier,
|
||||
{
|
||||
languageOptions: { globals: { ...globals.browser, ...globals.node } },
|
||||
rules: {
|
||||
"svelte/no-navigation-without-resolve": [
|
||||
"error",
|
||||
{
|
||||
"ignoreGoto": true,
|
||||
"ignoreLinks": true,
|
||||
"ignorePushState": true,
|
||||
"ignoreReplaceState": true
|
||||
}
|
||||
],
|
||||
// typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
|
||||
// see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
|
||||
"no-undef": 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
extraFileExtensions: ['.svelte'],
|
||||
parser: ts.parser
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
// Override or add rule settings here, such as:
|
||||
// 'svelte/button-has-type': 'error'
|
||||
rules: {}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "web",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write .",
|
||||
"db:push": "drizzle-kit push",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"auth:schema": "auth generate --config src/lib/server/auth.ts --output src/lib/server/db/auth.schema.ts --yes"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@libsql/client": "^0.17.3",
|
||||
"@sveltejs/adapter-auto": "^7.0.1",
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.70.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
||||
"@tailwindcss/forms": "^0.5.11",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.3.0",
|
||||
"@types/node": "^24",
|
||||
"eslint": "^10.4.1",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-svelte": "^3.19.0",
|
||||
"globals": "^17.6.0",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-svelte": "^4.1.0",
|
||||
"prettier-plugin-tailwindcss": "^0.8.0",
|
||||
"svelte": "^5.56.1",
|
||||
"svelte-check": "^4.6.0",
|
||||
"tailwindcss": "^4.3.0",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.60.1",
|
||||
"vite": "^8.2.0"
|
||||
},
|
||||
"overrides": {
|
||||
"cookie": "^0.7.0",
|
||||
"esbuild": "^0.25.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"oidc-client-ts": "^3.5.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/** @type {import("prettier").Config} */
|
||||
const config = {
|
||||
useTabs: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'none',
|
||||
printWidth: 100,
|
||||
plugins: ['prettier-plugin-svelte', 'prettier-plugin-tailwindcss'],
|
||||
overrides: [{ files: '*.svelte', options: { parser: 'svelte' } }],
|
||||
tailwindStylesheet: './src/routes/layout.css'
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { User, Session } from 'better-auth';
|
||||
|
||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
interface Locals { user?: User; session?: Session }
|
||||
|
||||
// interface Error {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="text-scale" content="scale" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,62 @@
|
||||
import { goto } from "$app/navigation";
|
||||
import { getToken, logout } from "$lib/state/auth.svelte"
|
||||
|
||||
const BASE_URL = import.meta.env.VITE_API_URL;
|
||||
|
||||
interface RequestOptions extends RequestInit {
|
||||
auth?: boolean; // true par défaut
|
||||
}
|
||||
|
||||
class ApiError extends Error {
|
||||
constructor(public status: number, public body: string) {
|
||||
super(`API Error ${status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {
|
||||
const { auth = true, headers, ...rest } = options;
|
||||
|
||||
const requestHeaders: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
...headers,
|
||||
};
|
||||
const fetchHeaders = new Headers(requestHeaders)
|
||||
|
||||
if (auth) {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
fetchHeaders.append('Authorization', `Bearer ${token}`)
|
||||
}
|
||||
}
|
||||
|
||||
const res = await fetch(`${BASE_URL}${path}`, {
|
||||
...rest,
|
||||
headers: fetchHeaders,
|
||||
});
|
||||
|
||||
if (res.status === 401 ) {
|
||||
logout()
|
||||
goto("/login")
|
||||
//throw new ApiError(401, await safeJson(res));
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
throw new ApiError(res.status, await safeJson(res));
|
||||
}
|
||||
|
||||
if (res.status === 204) return undefined as T;
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function safeJson(res: Response) {
|
||||
try { return await res.json(); } catch { return null; }
|
||||
}
|
||||
|
||||
export const api = {
|
||||
get: <T>(path: string, opts?: RequestOptions) => request<T>(path, { ...opts, method: 'GET' }),
|
||||
post: <T>(path: string, body?: unknown, opts?: RequestOptions) =>
|
||||
request<T>(path, { ...opts, method: 'POST', body: JSON.stringify(body) }),
|
||||
put: <T>(path: string, body?: unknown, opts?: RequestOptions) =>
|
||||
request<T>(path, { ...opts, method: 'PUT', body: JSON.stringify(body) }),
|
||||
delete: <T>(path: string, opts?: RequestOptions) => request<T>(path, { ...opts, method: 'DELETE' }),
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
import { api } from '../client';
|
||||
import { type User } from "$lib/types/api"
|
||||
|
||||
export interface Credentials {
|
||||
email: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export interface UserReponse {
|
||||
user : User
|
||||
accessToken: string
|
||||
refreshToken: string
|
||||
expiresAt: Date
|
||||
}
|
||||
|
||||
export interface RegistrationData {
|
||||
method: string // "password"
|
||||
email: string
|
||||
firstname: string
|
||||
lastname: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export const authApi = {
|
||||
register: (data: RegistrationData) => api.post<User>('/auth/register', data),
|
||||
status: () => api.get<User>('/auth/status'),
|
||||
login: (data: Credentials) => api.post<UserReponse>('/auth/login', data),
|
||||
// getAll: () => api.get<User[]>('/users'),
|
||||
// getById: (id: string) => api.get<User>(`/users/${id}`),
|
||||
// create: (data: Partial<User>) => api.post<User>('/users', data),
|
||||
// update: (id: string, data: Partial<User>) => api.put<User>(`/users/${id}`, data),
|
||||
// remove: (id: string) => api.delete<void>(`/users/${id}`),
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
import { api } from '../client';
|
||||
import { type User } from "$lib/types/api"
|
||||
|
||||
export const userApi = {
|
||||
me: () => api.get<User>('/user/me'),
|
||||
update: (id: string, data: Partial<User>) => api.put<User>(`/user/${id}`, data),
|
||||
};
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="13mm"
|
||||
height="13mm"
|
||||
viewBox="0 0 13 13"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
|
||||
sodipodi:docname="favicon.svg"
|
||||
inkscape:export-filename="../backend/web/src/lib/assets/logo-txt.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="1.4431818"
|
||||
inkscape:cx="287.90552"
|
||||
inkscape:cy="214.80315"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1011"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:14.1111px;font-family:pixelart;-inkscape-font-specification:pixelart;writing-mode:lr-tb;direction:ltr;fill:#37abc8;stroke-width:0.264583"
|
||||
x="2.7499995"
|
||||
y="11.549997"
|
||||
id="text1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.1111px;font-family:'GohuFont 11 Nerd Font';-inkscape-font-specification:'GohuFont 11 Nerd Font';fill:#0ea5e9;fill-opacity:1;stroke-width:0.264583"
|
||||
x="2.7499995"
|
||||
y="11.549997">l</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
type Props = {
|
||||
errors: Map<string,string>
|
||||
key: string
|
||||
}
|
||||
let { errors, key }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if errors.has(key)}
|
||||
<span class="text-red-700 dark:text-red-400 text-xs">{errors.get(key)}</span>
|
||||
{:else}
|
||||
<span class="text-xs"> </span>
|
||||
{/if}
|
||||
@@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
import {uiState} from "$lib/state/ui.svelte"
|
||||
let {label='', icon='', link=''} = $props();
|
||||
</script>
|
||||
|
||||
<div class="my-2 block">
|
||||
<a class="p-2 w-full text-left menuitem block" href={link}>
|
||||
<i class={[icon]}></i>
|
||||
{#if uiState.menuContentVisible}
|
||||
<span class="ml-4">{label}</span>
|
||||
{/if}
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,55 @@
|
||||
<script lang="ts">
|
||||
import { uiState } from "$lib/state/ui.svelte"
|
||||
import { auth } from "$lib/state/auth.svelte"
|
||||
import Menu from "$lib/components/Menu.svelte"
|
||||
import { logout } from "$lib/state/auth.svelte"
|
||||
import logo from "$lib/assets/logo-txt.png"
|
||||
|
||||
let {handleMenuDesktop, handleMenuMobile} = $props();
|
||||
|
||||
const handleLogout = () => {
|
||||
logout()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row italic mb-4">
|
||||
{#if uiState.menuContentVisible}
|
||||
<div class="flex-1 p-3 font openonly">
|
||||
<img src={logo} class="h-5" alt="logo"/>
|
||||
</div>
|
||||
{/if}
|
||||
<button id="hamburgerDesktop" onclick={handleMenuDesktop} title="Open menu">
|
||||
<i class="icon-menu pointer block p-2"></i>
|
||||
</button>
|
||||
<button id="hamburgerMobile" onclick={handleMenuMobile} title="Open menu">
|
||||
<i class="icon-menu pointer block p-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="menu" class="flex-1 overflow-y-scroll">
|
||||
<Menu label="Conversation" icon="icon-chat" link="/"/>
|
||||
<Menu label="Tâches" icon="icon-tasks" link="/tasks"/>
|
||||
<Menu label="Connaissances" icon="icon-graduation-cap" link="/kb"/>
|
||||
<Menu label="Historique" icon="icon-history" link="/history"/>
|
||||
{#if auth.user?.administrator}
|
||||
<Menu label="Paramétrage" icon="icon-cog" link="/settings"/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div id="profile" class="w-full flex flex-row items-center border-t border-stone-200 dark:border-stone-800">
|
||||
{#if uiState.menuContentVisible}
|
||||
<div class="p-4 flex-1 profile">
|
||||
<div>Fabien Masson</div>
|
||||
<div class="flex">
|
||||
<a href="/profile" class="text-xs flex-1">Modifier</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<button class="w-full bt" onclick={handleLogout} title="Déconecter">
|
||||
<i class="icon-logout"></i>
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
<Menu label="User" icon="icon-user" link="/profile"/>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
@@ -0,0 +1,26 @@
|
||||
import { type User } from "$lib/types/api"
|
||||
|
||||
type AuthState = {
|
||||
user: User | null;
|
||||
status: 'loading' | 'authenticated' | 'unauthenticated';
|
||||
//accessToken: string | null
|
||||
}
|
||||
|
||||
export const auth: AuthState = $state({
|
||||
user: null,
|
||||
status: 'loading',
|
||||
//accessToken: null
|
||||
})
|
||||
|
||||
export const logout = () => {
|
||||
localStorage.removeItem("accessToken")
|
||||
auth.status = 'unauthenticated'
|
||||
}
|
||||
|
||||
export const getToken = (): string | null => {
|
||||
return localStorage.getItem("accessToken")
|
||||
}
|
||||
|
||||
export const setToken = (token : string) => {
|
||||
localStorage.setItem("accessToken", token)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
let messageIndex = 0
|
||||
|
||||
interface Message {
|
||||
id : number
|
||||
type: 'success' | 'failure'
|
||||
text: string,
|
||||
status: 'appearing' | 'visible' | 'disappearing'
|
||||
}
|
||||
|
||||
export const messages: Array<Message> = $state([])
|
||||
|
||||
export const putMessage = (type: 'success' | 'failure', text: string)=> {
|
||||
messages.push({
|
||||
id: messageIndex++,
|
||||
type: type,
|
||||
text: text,
|
||||
status: 'appearing'
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export const uiState = $state({
|
||||
sidebarDesktopOpen: true,
|
||||
sidebarMobileOpen: false,
|
||||
menuContentVisible: true
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
export interface User {
|
||||
id: string
|
||||
firstname: string
|
||||
lastname: string
|
||||
email: string
|
||||
administrator: boolean
|
||||
theme: string
|
||||
lang: string
|
||||
_version: string
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export const applyTheme = () => {
|
||||
document.documentElement.classList.toggle(
|
||||
"dark",
|
||||
localStorage.theme === "dark" ||
|
||||
(!("theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches),
|
||||
);
|
||||
}
|
||||
|
||||
export const themeToLocalStorage = (theme: string) => {
|
||||
if (theme=='light') {
|
||||
localStorage.setItem('theme','light')
|
||||
} else if (theme=='dark') {
|
||||
localStorage.setItem('theme','dark')
|
||||
} else {
|
||||
localStorage.removeItem('theme')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
const emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
|
||||
export function validateEmail(input: string): boolean {
|
||||
return emailRegex.test(input);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
@@ -0,0 +1,3 @@
|
||||
export function load() {
|
||||
return { title: 'Conversation' };
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
import type { LayoutProps } from './$types';
|
||||
import { page } from '$app/state';
|
||||
import {uiState} from "$lib/state/ui.svelte"
|
||||
import { auth } from '$lib/state/auth.svelte'
|
||||
import Sidebar from "$lib/components/Sidebar.svelte"
|
||||
import { goto } from '$app/navigation'
|
||||
import { onMount } from "svelte";
|
||||
import { applyTheme, themeToLocalStorage } from '$lib/ui/themeswitcher';
|
||||
|
||||
let { data, children }: LayoutProps = $props();
|
||||
|
||||
const handleMenuDesktop = () => {
|
||||
uiState.sidebarDesktopOpen = !uiState.sidebarDesktopOpen
|
||||
if (uiState.sidebarDesktopOpen) {
|
||||
setTimeout(() => { uiState.menuContentVisible = uiState.sidebarDesktopOpen }, 200)
|
||||
} else {
|
||||
uiState.menuContentVisible = uiState.sidebarDesktopOpen
|
||||
}
|
||||
}
|
||||
|
||||
const handleMenuMobile = () => {
|
||||
uiState.sidebarMobileOpen = !uiState.sidebarMobileOpen
|
||||
if (uiState.sidebarMobileOpen) {
|
||||
setTimeout(() => { uiState.menuContentVisible = uiState.sidebarMobileOpen }, 200)
|
||||
} else {
|
||||
uiState.menuContentVisible = uiState.sidebarMobileOpen
|
||||
}
|
||||
}
|
||||
|
||||
const handleResize = () => {
|
||||
if (window.innerWidth < 640) {
|
||||
uiState.menuContentVisible = uiState.sidebarMobileOpen
|
||||
} else {
|
||||
uiState.menuContentVisible = uiState.sidebarDesktopOpen
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
handleResize()
|
||||
if (data.me) {
|
||||
auth.user = data.me
|
||||
themeToLocalStorage(auth.user.theme)
|
||||
applyTheme()
|
||||
auth.status = 'authenticated'
|
||||
} else {
|
||||
auth.status = 'unauthenticated'
|
||||
}
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
if (auth.status == 'unauthenticated') {
|
||||
goto("/login")
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:window onresize={handleResize} />
|
||||
|
||||
<div id="outer" class={[uiState.sidebarDesktopOpen ? "desktopMenuOpen" : "desktopMenuClosed", uiState.sidebarMobileOpen ? "mobileMenuOpen" : "mobileMenuClosed" ]}>
|
||||
<div id="sidebar" class="flex flex-col">
|
||||
<Sidebar {handleMenuDesktop} {handleMenuMobile}/>
|
||||
</div>
|
||||
<div id="main">
|
||||
<div class="flex flex-col h-screen ">
|
||||
<div class={["header", page.data.theme]}>
|
||||
<h1 class="flex">
|
||||
<span class="flex-1">{page.data.title}</span>
|
||||
{#if page.data.back}
|
||||
<span><a href={page.data.back} title="retour"><i class="icon-left-big"></i></a></span>
|
||||
{/if}
|
||||
</h1>
|
||||
</div>
|
||||
<div class="overflow-scroll flex-1 p-2">
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
import { userApi } from "$lib/api/endpoints/user"
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = async () => {
|
||||
return {
|
||||
me: await userApi.me()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
@@ -0,0 +1,3 @@
|
||||
export function load() {
|
||||
return { title: 'Historique' };
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function load() {
|
||||
return { title: 'Base de connaissance' };
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<script lang="ts">
|
||||
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
import type { PageProps } from './$types';
|
||||
import { type User } from '$lib/types/api'
|
||||
import { userApi } from '$lib/api/endpoints/user'
|
||||
import FormError from '$lib/components/FormError.svelte';
|
||||
import { applyTheme, themeToLocalStorage } from '$lib/ui/themeswitcher';
|
||||
import { validateEmail } from '$lib/utilities/validators'
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
let form : User = $state(data.me)
|
||||
let errors = new SvelteMap<string,string>()
|
||||
|
||||
$effect(()=>{
|
||||
themeToLocalStorage(form.theme)
|
||||
applyTheme()
|
||||
})
|
||||
|
||||
let submitUser = (e: Event) => {
|
||||
e.preventDefault()
|
||||
if (!validateEmail(form.email)) {
|
||||
errors.set("email","Adresse email invalide !")
|
||||
}
|
||||
if (!form.firstname) {
|
||||
errors.set("firstname","Le prénom est obligatoire !")
|
||||
}
|
||||
if (!form.lastname) {
|
||||
errors.set("lastname","Le nom est obligatoire !")
|
||||
}
|
||||
if (errors.size==0) {
|
||||
userApi.update(form.id, form)
|
||||
.then(()=>{ console.log('success')})
|
||||
.catch((err: string)=>{ console.error(err)})
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="mb-4 formgroup">
|
||||
<h2>Mon compte</h2>
|
||||
|
||||
<form onsubmit={submitUser} onchange={()=>{errors.clear()}}>
|
||||
|
||||
<label for="email" class="block my-1 flex-1">Email</label>
|
||||
<input
|
||||
id="email"
|
||||
type="text"
|
||||
bind:value={form.email}
|
||||
class="textinput"
|
||||
autofocus
|
||||
/>
|
||||
<FormError key="email" errors={errors} />
|
||||
|
||||
<div class="flex">
|
||||
<div class="flex-1 mr-2">
|
||||
<label for="firstname" class="block my-1 flex-1">Prénom</label>
|
||||
<input
|
||||
id="firstname"
|
||||
type="text"
|
||||
bind:value={form.firstname}
|
||||
class="textinput"
|
||||
/>
|
||||
<FormError key="firstname" errors={errors} />
|
||||
</div>
|
||||
|
||||
<div class="flex-1 ml-2">
|
||||
<label for="lastname" class="block my-1 flex-1">Nom</label>
|
||||
<input
|
||||
id="lastname"
|
||||
type="text"
|
||||
bind:value={form.lastname}
|
||||
class="textinput"
|
||||
/>
|
||||
<FormError key="lastname" errors={errors} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<div class="flex-1 mr-2">
|
||||
<label for="theme" class="block my-1 flex-1">Thème</label>
|
||||
<select bind:value={form.theme} class="textinput">
|
||||
<option value="auto">Automatic</option>
|
||||
<option value="dark">Sombre</option>
|
||||
<option value="light">Clair</option>
|
||||
</select>
|
||||
<FormError key="theme" errors={errors} />
|
||||
</div>
|
||||
|
||||
<div class="flex-1 ml-2">
|
||||
<label for="lang" class="block my-1 flex-1">Langue</label>
|
||||
<select bind:value={form.lang} class="textinput">
|
||||
<option value="en">English</option>
|
||||
<option value="fr">Français</option>
|
||||
</select>
|
||||
<FormError key="lang" errors={errors} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="bt w-full">Enregistrer</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mb-4 formgroup">
|
||||
<h2>Canaux de communication</h2>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
import { userApi } from "$lib/api/endpoints/user"
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async () => {
|
||||
return {
|
||||
title: 'Profil',
|
||||
me: await userApi.me()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<div class="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Modèles"
|
||||
href="/settings/models">
|
||||
Modèles
|
||||
<span class="ml-2 opacity-50 text-xs">mistral-medium-latest</span>
|
||||
</a>
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Outils"
|
||||
href="/settings/tools"
|
||||
>
|
||||
Outils
|
||||
<span class="ml-2 text-xs bg-red-900 text-red-300 rounded-lg p-1">12</span>
|
||||
</a>
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Skills"
|
||||
href="/settings/skills">
|
||||
Skills
|
||||
<span class="ml-2 text-xs bg-red-900 text-red-300 rounded-lg p-1">3</span>
|
||||
</a>
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Canaux de communication"
|
||||
href="/settings/channels"
|
||||
>
|
||||
Canaux de communication
|
||||
<span class="ml-2 text-xs bg-red-900 text-red-300 rounded-lg p-1">12</span>
|
||||
</a>
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Bases de connaissance"
|
||||
href="/settings/kb">
|
||||
Bases de connaissance
|
||||
</a>
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Agents"
|
||||
href="/settings/agents">
|
||||
Agents
|
||||
</a>
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Mémoire"
|
||||
href="/settings/memory">
|
||||
Mémoire
|
||||
<span class="ml-2 opacity-50 text-xs">standard</span>
|
||||
</a>
|
||||
|
||||
<a class="bt p-5 text-center"
|
||||
title="Utilisateurs"
|
||||
href="/settings/users">
|
||||
Utilisateurs
|
||||
<span class="ml-2 text-xs bg-red-900 text-red-300 rounded-lg p-1">1</span>
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
export function load() {
|
||||
return { title: 'Paramétrage', theme: "settings" };
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Agents',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Canaux de communication',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Base de connaissance',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Mémoire',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Modèles',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Skills',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Outils',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<div>Modèles</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
export function load() {
|
||||
return {
|
||||
title: 'Paramétrage : Utilisateurs',
|
||||
back: "/settings",
|
||||
theme: "settings"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<div>
|
||||
Tâches
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
export function load() {
|
||||
return { title: 'Tâches' };
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<script lang="ts">
|
||||
import logo from "$lib/assets/logo-txt.png"
|
||||
import { auth, setToken } from '$lib/state/auth.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { authApi } from "$lib/api/endpoints/auth"
|
||||
|
||||
type Credentials = {
|
||||
email: string
|
||||
validemail: boolean
|
||||
password : string
|
||||
}
|
||||
|
||||
let credentials: Credentials = $state({
|
||||
email: "",
|
||||
password: "",
|
||||
validemail: false
|
||||
})
|
||||
|
||||
const formSubmitEmail = () => {
|
||||
credentials.validemail = true
|
||||
}
|
||||
|
||||
const formSubmitPass = (e: Event) => {
|
||||
e.preventDefault()
|
||||
authApi.login(credentials)
|
||||
.then((res)=>{
|
||||
auth.user = res.user
|
||||
setToken(res.accessToken)
|
||||
goto("/")
|
||||
})
|
||||
.catch((err)=>{
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="h-full w-full flex items-center public">
|
||||
<div class="m-auto w-96 max-w-full p-4">
|
||||
<img src={logo} class="h-10 mb-4" alt="logo"/>
|
||||
<h1>Identifiez-vous ...</h1>
|
||||
{#if !credentials.validemail}
|
||||
<form onsubmit={formSubmitEmail}>
|
||||
<div class="flex">
|
||||
<label for="email" class="block mb-2 flex-1">Email</label>
|
||||
<a href="/recover-password" class="text-xs">Mot de passe oublié ?</a>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={credentials.email}
|
||||
class="textinput mr-1"
|
||||
autofocus
|
||||
/>
|
||||
<button class="bt" title="page suivante">
|
||||
<i class="icon-right-big"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="my-4 text-xs">
|
||||
<a href="/register">Pas encore de compte ? Incrivez-vous.</a>
|
||||
</div>
|
||||
|
||||
|
||||
{:else}
|
||||
<form onsubmit={formSubmitPass}>
|
||||
<div class="flex">
|
||||
<label for="email" class="block mb-2 flex-1">Mot de passe</label>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
type="password"
|
||||
bind:value={credentials.password}
|
||||
class="textinput mr-1"
|
||||
autofocus
|
||||
/>
|
||||
<button class="bt">
|
||||
Entrer
|
||||
</button>
|
||||
</div>
|
||||
<a href="/login" class="text-xs" onclick={()=>{credentials.validemail=false}}>← Retour</a>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-4">
|
||||
<button class="bt p-5 text-center" title="Connexion avec Google">
|
||||
<i class="icon-google"></i>
|
||||
</button>
|
||||
<button class="bt p-5 text-center" title="Connexion avec Facebook">
|
||||
<i class="icon-facebook"></i>
|
||||
</button>
|
||||
<button class="bt p-5 text-center" title="Connexion avec Github">
|
||||
<i class="icon-github"></i>
|
||||
</button>
|
||||
<button class="bt p-5 text-center" title="Connexion avec Apple">
|
||||
<i class="icon-apple"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,120 @@
|
||||
<script lang="ts">
|
||||
import logo from "$lib/assets/logo-txt.png"
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
import { goto } from '$app/navigation';
|
||||
import { validateEmail } from '$lib/utilities/validators'
|
||||
import FormError from "$lib/components/FormError.svelte";
|
||||
import { authApi } from "$lib/api/endpoints/auth"
|
||||
|
||||
type RegisterForm = {
|
||||
email: string
|
||||
firstname: string
|
||||
lastname: string
|
||||
password : string
|
||||
verifPassword: string
|
||||
}
|
||||
|
||||
let errors = new SvelteMap<string,string>()
|
||||
|
||||
let form: RegisterForm = $state({
|
||||
email: "",
|
||||
firstname: "",
|
||||
lastname: "",
|
||||
password: "",
|
||||
verifPassword: ""
|
||||
})
|
||||
|
||||
const handleSubmit = (e: Event) => {
|
||||
e.preventDefault()
|
||||
errors.clear()
|
||||
|
||||
if (!validateEmail(form.email)) {
|
||||
errors.set("email","Adresse email invalide !")
|
||||
}
|
||||
if (form.password!==form.verifPassword) {
|
||||
errors.set("verifPassword","Les mots de pass ne correspondent pas.")
|
||||
}
|
||||
if (errors.size==0) {
|
||||
|
||||
let data = {
|
||||
method: "password",
|
||||
email: form.email,
|
||||
firstname: form.firstname,
|
||||
lastname: form.lastname,
|
||||
password: form.password
|
||||
}
|
||||
|
||||
authApi.register(data)
|
||||
.then(()=>{ goto("/") })
|
||||
.catch((reason: string)=>{ errors.set("submit","Erreur: "+reason) })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<div class="h-full w-full flex items-center public">
|
||||
<div class="m-auto w-96 max-w-full p-4">
|
||||
<img src={logo} class="h-10 mb-4" alt="logo"/>
|
||||
<h1>Inscription</h1>
|
||||
|
||||
<form onsubmit={handleSubmit} onchange={()=>{errors.clear()}}>
|
||||
|
||||
<label for="email" class="block my-1 flex-1">Email</label>
|
||||
<input
|
||||
id="email"
|
||||
type="text"
|
||||
bind:value={form.email}
|
||||
class="textinput"
|
||||
autofocus
|
||||
/>
|
||||
<FormError key="email" errors={errors} />
|
||||
|
||||
|
||||
<label for="firstname" class="block my-1 flex-1">Prénom</label>
|
||||
<input
|
||||
id="firstname"
|
||||
type="text"
|
||||
bind:value={form.firstname}
|
||||
class="textinput"
|
||||
/>
|
||||
<FormError key="firstname" {errors} />
|
||||
|
||||
<label for="lastname" class="block my-1 flex-1">Nom</label>
|
||||
<input
|
||||
id="lastname"
|
||||
type="text"
|
||||
bind:value={form.lastname}
|
||||
class="textinput"
|
||||
/>
|
||||
<FormError key="lastname" {errors} />
|
||||
|
||||
<label for="password" class="block my-1 flex-1">Mot de passe</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
bind:value={form.password}
|
||||
class="textinput"
|
||||
/>
|
||||
<FormError key="password" {errors} />
|
||||
|
||||
<label for="verifpassword" class="block my-1 flex-1">Vérification du mot de passe</label>
|
||||
<input
|
||||
id="verifpassword"
|
||||
type="password"
|
||||
bind:value={form.verifPassword}
|
||||
class="textinput"
|
||||
/>
|
||||
<FormError key="verifPassword" {errors} />
|
||||
|
||||
<button class="bt my-2 w-full ">
|
||||
Enregistrer
|
||||
</button>
|
||||
|
||||
<FormError key="submit" {errors} />
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,2 @@
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import './layout.css';
|
||||
import favicon from '$lib/assets/favicon.svg';
|
||||
import { applyTheme } from '$lib/ui/themeswitcher';
|
||||
import { onMount } from 'svelte';
|
||||
let { children } = $props();
|
||||
|
||||
onMount(()=>{ applyTheme() })
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Lasssistanoque</title>
|
||||
<link rel="icon" href={favicon} />
|
||||
<link rel="stylesheet" href="/assets/fontello/css/fontello.css">
|
||||
</svelte:head>
|
||||
|
||||
{@render children()}
|
||||
@@ -0,0 +1,107 @@
|
||||
@import 'tailwindcss';
|
||||
@plugin '@tailwindcss/forms';
|
||||
@plugin '@tailwindcss/typography';
|
||||
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
html {
|
||||
@apply h-full;
|
||||
}
|
||||
body {
|
||||
@apply h-full bg-stone-100 text-stone-900 dark:bg-stone-900 dark:text-stone-200;
|
||||
}
|
||||
|
||||
label {
|
||||
@apply text-xs text-stone-600 uppercase dark:text-stone-400;
|
||||
}
|
||||
hr {
|
||||
@apply border-stone-200 dark:border-stone-800;
|
||||
}
|
||||
h2 {
|
||||
@apply mb-4 font-bold;
|
||||
}
|
||||
|
||||
.textinput {
|
||||
@apply w-full rounded bg-white p-1 text-stone-900 dark:bg-stone-700 dark:text-stone-100;
|
||||
}
|
||||
.pointer {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
.bt {
|
||||
@apply cursor-pointer rounded bg-stone-200 px-4 py-2 hover:bg-stone-300 dark:bg-stone-800 dark:hover:bg-stone-700;
|
||||
}
|
||||
.menuitem {
|
||||
@apply text-stone-800 text-stone-950 dark:text-stone-300 hover:dark:text-stone-50;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply p-2 text-lg;
|
||||
|
||||
h1 {
|
||||
@apply rounded bg-stone-200 px-2 font-bold text-sky-600 dark:bg-stone-800 dark:text-sky-200;
|
||||
}
|
||||
|
||||
&.settings {
|
||||
h1 {
|
||||
@apply rounded border-none bg-sky-200 px-2 text-sky-700 dark:bg-sky-950 dark:text-sky-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.public h1 {
|
||||
@apply mb-4 text-3xl font-bold;
|
||||
}
|
||||
.profile a,
|
||||
.public a {
|
||||
@apply text-sky-500;
|
||||
}
|
||||
|
||||
.formgroup {
|
||||
@apply rounded border border-stone-300 bg-stone-100 p-2 dark:border-stone-700 dark:bg-stone-900;
|
||||
}
|
||||
|
||||
#outer {
|
||||
@apply flex h-full flex-row;
|
||||
}
|
||||
#main {
|
||||
@apply flex w-full flex-col;
|
||||
}
|
||||
#sidebar {
|
||||
@apply min-w-64 border-r border-r-stone-200 transition-all duration-300 dark:border-stone-800;
|
||||
}
|
||||
|
||||
#content {
|
||||
@apply p-2;
|
||||
}
|
||||
#hamburgerDesktop,
|
||||
#hamburgerMobile {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
@media (width >= 640px) {
|
||||
#hamburgerDesktop {
|
||||
@apply inline;
|
||||
}
|
||||
.desktopMenuClosed {
|
||||
#sidebar {
|
||||
@apply w-10 min-w-10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (width < 640px) {
|
||||
#hamburgerMobile {
|
||||
@apply inline;
|
||||
}
|
||||
#main {
|
||||
@apply ml-10;
|
||||
}
|
||||
#sidebar {
|
||||
@apply fixed left-0 h-full w-full bg-stone-100 dark:bg-stone-900;
|
||||
}
|
||||
.mobileMenuClosed {
|
||||
#sidebar {
|
||||
@apply fixed w-10 min-w-10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
Font license info
|
||||
|
||||
|
||||
## Font Awesome
|
||||
|
||||
Copyright (C) 2016 by Dave Gandy
|
||||
|
||||
Author: Dave Gandy
|
||||
License: SIL ()
|
||||
Homepage: http://fortawesome.github.com/Font-Awesome/
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
This webfont is generated by https://fontello.com open source project.
|
||||
|
||||
|
||||
================================================================================
|
||||
Please, note, that you should obey original font licenses, used to make this
|
||||
webfont pack. Details available in LICENSE.txt file.
|
||||
|
||||
- Usually, it's enough to publish content of LICENSE.txt file somewhere on your
|
||||
site in "About" section.
|
||||
|
||||
- If your project is open-source, usually, it will be ok to make LICENSE.txt
|
||||
file publicly available in your repository.
|
||||
|
||||
- Fonts, used in Fontello, don't require a clickable link on your site.
|
||||
But any kind of additional authors crediting is welcome.
|
||||
================================================================================
|
||||
|
||||
|
||||
Comments on archive content
|
||||
---------------------------
|
||||
|
||||
- /font/* - fonts in different formats
|
||||
|
||||
- /css/* - different kinds of css, for all situations. Should be ok with
|
||||
twitter bootstrap. Also, you can skip <i> style and assign icon classes
|
||||
directly to text elements, if you don't mind about IE7.
|
||||
|
||||
- demo.html - demo file, to show your webfont content
|
||||
|
||||
- LICENSE.txt - license info about source fonts, used to build your one.
|
||||
|
||||
- config.json - keeps your settings. You can import it back into fontello
|
||||
anytime, to continue your work
|
||||
|
||||
|
||||
Why so many CSS files ?
|
||||
-----------------------
|
||||
|
||||
Because we like to fit all your needs :)
|
||||
|
||||
- basic file, <your_font_name>.css - is usually enough, it contains @font-face
|
||||
and character code definitions
|
||||
|
||||
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
|
||||
directly into html
|
||||
|
||||
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
|
||||
rules, but still wish to benefit from css generation. That can be very
|
||||
convenient for automated asset build systems. When you need to update font -
|
||||
no need to manually edit files, just override old version with archive
|
||||
content. See fontello source code for examples.
|
||||
|
||||
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
|
||||
CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
|
||||
We strongly recommend to resolve this issue by `Access-Control-Allow-Origin`
|
||||
server headers. But if you ok with dirty hack - this file is for you. Note,
|
||||
that data url moved to separate @font-face to avoid problems with <IE9, when
|
||||
string is too long.
|
||||
|
||||
- animate.css - use it to get ideas about spinner rotation animation.
|
||||
|
||||
|
||||
Attention for server setup
|
||||
--------------------------
|
||||
|
||||
You MUST setup server to reply with proper `mime-types` for font files -
|
||||
otherwise some browsers will fail to show fonts.
|
||||
|
||||
Usually, `apache` already has necessary settings, but `nginx` and other
|
||||
webservers should be tuned. Here is list of mime types for our file extensions:
|
||||
|
||||
- `application/vnd.ms-fontobject` - eot
|
||||
- `application/x-font-woff` - woff
|
||||
- `application/x-font-ttf` - ttf
|
||||
- `image/svg+xml` - svg
|
||||
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"name": "",
|
||||
"css_prefix_text": "icon-",
|
||||
"css_use_suffix": false,
|
||||
"hinting": true,
|
||||
"units_per_em": 1000,
|
||||
"ascent": 850,
|
||||
"glyphs": [
|
||||
{
|
||||
"uid": "dcedf50ab1ede3283d7a6c70e2fe32f3",
|
||||
"css": "chat",
|
||||
"code": 59392,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "31972e4e9d080eaa796290349ae6c1fd",
|
||||
"css": "users",
|
||||
"code": 59393,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "38575a803c4da31ce20d77e1e1236bcb",
|
||||
"css": "paper-plane",
|
||||
"code": 61912,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "5bb103cd29de77e0e06a52638527b575",
|
||||
"css": "wrench",
|
||||
"code": 59394,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "20fc52f9a88bb7bda023ef209acac095",
|
||||
"css": "graduation-cap",
|
||||
"code": 61853,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "e99461abfef3923546da8d745372c995",
|
||||
"css": "cog",
|
||||
"code": 59395,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "8b80d36d4ef43889db10bc1f0dc9a862",
|
||||
"css": "user",
|
||||
"code": 59396,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "9396b2d8849e0213a0f11c5fd7fcc522",
|
||||
"css": "tasks",
|
||||
"code": 61614,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "d4816c0845aa43767213d45574b3b145",
|
||||
"css": "history",
|
||||
"code": 61914,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "559647a6f430b3aeadbecd67194451dd",
|
||||
"css": "menu",
|
||||
"code": 61641,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "41087bc74d4b20b55059c60a33bf4008",
|
||||
"css": "edit",
|
||||
"code": 59397,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "ad6b3fbb5324abe71a9c0b6609cbb9f1",
|
||||
"css": "right-big",
|
||||
"code": 59398,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "f06fe7ff18d1c591bc1183cb3ab105e9",
|
||||
"css": "google",
|
||||
"code": 61856,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "8e04c98c8f5ca0a035776e3001ad2638",
|
||||
"css": "facebook",
|
||||
"code": 61594,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "e9fa538fd5913046497ac148e27cd8ea",
|
||||
"css": "apple",
|
||||
"code": 61817,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "5e0a374728ffa8d0ae1f331a8f648231",
|
||||
"css": "github",
|
||||
"code": 61715,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "0d20938846444af8deb1920dc85a29fb",
|
||||
"css": "logout",
|
||||
"code": 59399,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "555ef8c86832e686fef85f7af2eb7cde",
|
||||
"css": "left-big",
|
||||
"code": 59400,
|
||||
"src": "fontawesome"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Animation example, for spinners
|
||||
*/
|
||||
.animate-spin {
|
||||
-moz-animation: spin 2s infinite linear;
|
||||
-o-animation: spin 2s infinite linear;
|
||||
-webkit-animation: spin 2s infinite linear;
|
||||
animation: spin 2s infinite linear;
|
||||
display: inline-block;
|
||||
}
|
||||
@-moz-keyframes spin {
|
||||
0% {
|
||||
-moz-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-moz-transform: rotate(359deg);
|
||||
-o-transform: rotate(359deg);
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-moz-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-moz-transform: rotate(359deg);
|
||||
-o-transform: rotate(359deg);
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@-o-keyframes spin {
|
||||
0% {
|
||||
-moz-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-moz-transform: rotate(359deg);
|
||||
-o-transform: rotate(359deg);
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@-ms-keyframes spin {
|
||||
0% {
|
||||
-moz-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-moz-transform: rotate(359deg);
|
||||
-o-transform: rotate(359deg);
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
-moz-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-moz-transform: rotate(359deg);
|
||||
-o-transform: rotate(359deg);
|
||||
-webkit-transform: rotate(359deg);
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
.icon-chat:before { content: '\e800'; } /* '' */
|
||||
.icon-users:before { content: '\e801'; } /* '' */
|
||||
.icon-wrench:before { content: '\e802'; } /* '' */
|
||||
.icon-cog:before { content: '\e803'; } /* '' */
|
||||
.icon-user:before { content: '\e804'; } /* '' */
|
||||
.icon-edit:before { content: '\e805'; } /* '' */
|
||||
.icon-right-big:before { content: '\e806'; } /* '' */
|
||||
.icon-logout:before { content: '\e807'; } /* '' */
|
||||
.icon-left-big:before { content: '\e808'; } /* '' */
|
||||
.icon-facebook:before { content: '\f09a'; } /* '' */
|
||||
.icon-tasks:before { content: '\f0ae'; } /* '' */
|
||||
.icon-menu:before { content: '\f0c9'; } /* '' */
|
||||
.icon-github:before { content: '\f113'; } /* '' */
|
||||
.icon-apple:before { content: '\f179'; } /* '' */
|
||||
.icon-graduation-cap:before { content: '\f19d'; } /* '' */
|
||||
.icon-google:before { content: '\f1a0'; } /* '' */
|
||||
.icon-paper-plane:before { content: '\f1d8'; } /* '' */
|
||||
.icon-history:before { content: '\f1da'; } /* '' */
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
.icon-chat { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-users { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-wrench { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-user { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-edit { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-big { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-big { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-tasks { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-apple { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-graduation-cap { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-google { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-paper-plane { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-history { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
@@ -0,0 +1,30 @@
|
||||
[class^="icon-"], [class*=" icon-"] {
|
||||
font-family: 'fontello';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
|
||||
/* fix buttons height */
|
||||
line-height: 1em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
}
|
||||
|
||||
.icon-chat { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-users { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-wrench { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-user { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-edit { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-big { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-big { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-tasks { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-apple { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-graduation-cap { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-google { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-paper-plane { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-history { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
@@ -0,0 +1,74 @@
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('../font/fontello.eot?64785462');
|
||||
src: url('../font/fontello.eot?64785462#iefix') format('embedded-opentype'),
|
||||
url('../font/fontello.woff2?64785462') format('woff2'),
|
||||
url('../font/fontello.woff?64785462') format('woff'),
|
||||
url('../font/fontello.ttf?64785462') format('truetype'),
|
||||
url('../font/fontello.svg?64785462#fontello') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||
/*
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('../font/fontello.svg?64785462#fontello') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
[class^="icon-"]:before, [class*=" icon-"]:before {
|
||||
font-family: "fontello";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: never;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.icon-chat:before { content: '\e800'; } /* '' */
|
||||
.icon-users:before { content: '\e801'; } /* '' */
|
||||
.icon-wrench:before { content: '\e802'; } /* '' */
|
||||
.icon-cog:before { content: '\e803'; } /* '' */
|
||||
.icon-user:before { content: '\e804'; } /* '' */
|
||||
.icon-edit:before { content: '\e805'; } /* '' */
|
||||
.icon-right-big:before { content: '\e806'; } /* '' */
|
||||
.icon-logout:before { content: '\e807'; } /* '' */
|
||||
.icon-left-big:before { content: '\e808'; } /* '' */
|
||||
.icon-facebook:before { content: '\f09a'; } /* '' */
|
||||
.icon-tasks:before { content: '\f0ae'; } /* '' */
|
||||
.icon-menu:before { content: '\f0c9'; } /* '' */
|
||||
.icon-github:before { content: '\f113'; } /* '' */
|
||||
.icon-apple:before { content: '\f179'; } /* '' */
|
||||
.icon-graduation-cap:before { content: '\f19d'; } /* '' */
|
||||
.icon-google:before { content: '\f1a0'; } /* '' */
|
||||
.icon-paper-plane:before { content: '\f1d8'; } /* '' */
|
||||
.icon-history:before { content: '\f1da'; } /* '' */
|
||||
@@ -0,0 +1,280 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--[if lt IE 9]><script language="javascript" type="text/javascript" src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
html {
|
||||
font-size: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
a:focus {
|
||||
outline: thin dotted #333;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
a:hover,
|
||||
a:active {
|
||||
outline: 0;
|
||||
}
|
||||
input {
|
||||
margin: 0;
|
||||
font-size: 100%;
|
||||
vertical-align: middle;
|
||||
*overflow: visible;
|
||||
line-height: normal;
|
||||
}
|
||||
input::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
}
|
||||
a {
|
||||
color: #08c;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
color: #005580;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.row {
|
||||
margin-left: -20px;
|
||||
*zoom: 1;
|
||||
}
|
||||
.row:before,
|
||||
.row:after {
|
||||
display: table;
|
||||
content: "";
|
||||
line-height: 0;
|
||||
}
|
||||
.row:after {
|
||||
clear: both;
|
||||
}
|
||||
.span3 {
|
||||
float: left;
|
||||
min-height: 1px;
|
||||
margin-left: 20px;
|
||||
width: 220px;
|
||||
}
|
||||
.container {
|
||||
width: 940px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
*zoom: 1;
|
||||
}
|
||||
.container:before,
|
||||
.container:after {
|
||||
display: table;
|
||||
content: "";
|
||||
line-height: 0;
|
||||
}
|
||||
.container:after {
|
||||
clear: both;
|
||||
}
|
||||
small {
|
||||
font-size: 85%;
|
||||
}
|
||||
h1 {
|
||||
margin: 10px 0;
|
||||
font-family: inherit;
|
||||
font-weight: bold;
|
||||
line-height: 20px;
|
||||
color: inherit;
|
||||
text-rendering: optimizelegibility;
|
||||
line-height: 40px;
|
||||
font-size: 38.5px;
|
||||
}
|
||||
h1 small {
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
color: #999;
|
||||
font-size: 24.5px;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-top: 90px;
|
||||
}
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
margin-left: -480px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-top: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
.footer {
|
||||
color: #ddd;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.footer a {
|
||||
color: #ccc;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.the-icons {
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
.switch {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 10px;
|
||||
color: #666;
|
||||
}
|
||||
.switch input {
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
.codesOn .i-name {
|
||||
display: none;
|
||||
}
|
||||
.codesOn .i-code {
|
||||
display: inline;
|
||||
}
|
||||
.i-code {
|
||||
display: none;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('./font/fontello.eot?72761720');
|
||||
src: url('./font/fontello.eot?72761720#iefix') format('embedded-opentype'),
|
||||
url('./font/fontello.woff?72761720') format('woff'),
|
||||
url('./font/fontello.ttf?72761720') format('truetype'),
|
||||
url('./font/fontello.svg?72761720#fontello') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
.demo-icon {
|
||||
font-family: "fontello";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: never;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* You can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/" + font.fontname + "-ie7.css"><![endif]-->
|
||||
<script>
|
||||
function toggleCodes(on) {
|
||||
var obj = document.getElementById('icons');
|
||||
|
||||
if (on) {
|
||||
obj.className += ' codesOn';
|
||||
} else {
|
||||
obj.className = obj.className.replace(' codesOn', '');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container header">
|
||||
<h1>fontello <small>font demo</small></h1>
|
||||
<label class="switch">
|
||||
<input type="checkbox" onclick="toggleCodes(this.checked)">show codes
|
||||
</label>
|
||||
</div>
|
||||
<div class="container" id="icons">
|
||||
<div class="row">
|
||||
<div class="span3" title="Code: 0xe800">
|
||||
<i class="demo-icon icon-chat"></i> <span class="i-name">icon-chat</span><span class="i-code">0xe800</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xe801">
|
||||
<i class="demo-icon icon-users"></i> <span class="i-name">icon-users</span><span class="i-code">0xe801</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xe802">
|
||||
<i class="demo-icon icon-wrench"></i> <span class="i-name">icon-wrench</span><span class="i-code">0xe802</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xe803">
|
||||
<i class="demo-icon icon-cog"></i> <span class="i-name">icon-cog</span><span class="i-code">0xe803</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span3" title="Code: 0xe804">
|
||||
<i class="demo-icon icon-user"></i> <span class="i-name">icon-user</span><span class="i-code">0xe804</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xe805">
|
||||
<i class="demo-icon icon-edit"></i> <span class="i-name">icon-edit</span><span class="i-code">0xe805</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xe806">
|
||||
<i class="demo-icon icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe806</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xe807">
|
||||
<i class="demo-icon icon-logout"></i> <span class="i-name">icon-logout</span><span class="i-code">0xe807</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span3" title="Code: 0xe808">
|
||||
<i class="demo-icon icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe808</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xf09a">
|
||||
<i class="demo-icon icon-facebook"></i> <span class="i-name">icon-facebook</span><span class="i-code">0xf09a</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xf0ae">
|
||||
<i class="demo-icon icon-tasks"></i> <span class="i-name">icon-tasks</span><span class="i-code">0xf0ae</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xf0c9">
|
||||
<i class="demo-icon icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xf0c9</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span3" title="Code: 0xf113">
|
||||
<i class="demo-icon icon-github"></i> <span class="i-name">icon-github</span><span class="i-code">0xf113</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xf179">
|
||||
<i class="demo-icon icon-apple"></i> <span class="i-name">icon-apple</span><span class="i-code">0xf179</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xf19d">
|
||||
<i class="demo-icon icon-graduation-cap"></i> <span class="i-name">icon-graduation-cap</span><span class="i-code">0xf19d</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xf1a0">
|
||||
<i class="demo-icon icon-google"></i> <span class="i-name">icon-google</span><span class="i-code">0xf1a0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span3" title="Code: 0xf1d8">
|
||||
<i class="demo-icon icon-paper-plane"></i> <span class="i-name">icon-paper-plane</span><span class="i-code">0xf1d8</span>
|
||||
</div>
|
||||
<div class="span3" title="Code: 0xf1da">
|
||||
<i class="demo-icon icon-history"></i> <span class="i-name">icon-history</span><span class="i-code">0xf1da</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container footer">Generated by <a href="https://fontello.com">fontello.com</a></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Copyright (C) 2026 by original authors @ fontello.com</metadata>
|
||||
<defs>
|
||||
<font id="fontello" horiz-adv-x="1000" >
|
||||
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||
<missing-glyph horiz-adv-x="1000" />
|
||||
<glyph glyph-name="chat" unicode="" d="M786 421q0-77-53-143t-143-104-197-38q-48 0-98 9-70-49-155-72-21-5-48-9h-2q-6 0-12 5t-6 12q-1 1-1 3t1 4 1 3l1 3t2 3 2 3 3 3 2 2q3 3 13 14t15 16 12 17 14 21 11 25q-69 40-108 98t-40 125q0 78 53 144t143 104 197 38 197-38 143-104 53-144z m214-142q0-67-40-126t-108-98q5-14 11-25t14-21 13-16 14-17 13-14q0 0 2-2t3-3 2-3 2-3l1-3t1-3 1-4-1-3q-2-8-7-13t-12-4q-28 4-48 9-86 23-156 72-50-9-98-9-151 0-263 74 32-3 49-3 90 0 172 25t148 72q69 52 107 119t37 141q0 43-13 85 72-39 114-99t42-128z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="users" unicode="" d="M331 350q-90-3-148-71h-75q-45 0-77 22t-31 66q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143z m598-356q0-66-41-105t-108-39h-488q-68 0-108 39t-41 105q0 30 2 58t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 24 12q34 0 62-11t47-30 35-45 24-54 15-61 8-61 2-58z m-572 713q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z m393-214q0-89-63-152t-151-62-152 62-63 152 63 151 152 63 151-63 63-151z m321-126q0-43-31-66t-77-22h-75q-57 68-147 71 45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197z m-71 340q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z" horiz-adv-x="1071.4" />
|
||||
|
||||
<glyph glyph-name="wrench" unicode="" d="M214 29q0 14-10 25t-25 10-25-10-11-25 11-25 25-11 25 11 10 25z m360 234l-381-381q-21-20-50-20-29 0-51 20l-59 61q-21 20-21 50 0 29 21 51l380 380q22-55 64-97t97-64z m354 243q0-22-13-59-27-75-92-122t-144-46q-104 0-177 73t-73 177 73 176 177 74q32 0 67-10t60-26q9-6 9-15t-9-16l-163-94v-125l108-60q2 2 44 27t75 45 40 20q8 0 13-5t5-14z" horiz-adv-x="928.6" />
|
||||
|
||||
<glyph glyph-name="cog" unicode="" d="M571 350q0 59-41 101t-101 42-101-42-42-101 42-101 101-42 101 42 41 101z m286 61v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-27 59-77 6-6 6-13t-5-13q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 21l-79-60q-6-5-14-5-8 0-14 6-70 64-92 94-4 5-4 13 0 6 5 12 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 16 20 16h124q7 0 13-5t7-12l15-103q28-9 51-20l79 59q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-12 0-7-4-13-9-12-29-37t-30-40q15-28 23-54l102-16q7-1 12-7t4-13z" horiz-adv-x="857.1" />
|
||||
|
||||
<glyph glyph-name="user" unicode="" d="M714 69q0-60-35-104t-84-44h-476q-49 0-84 44t-35 104q0 48 5 90t17 85 33 73 52 50 76 19q73-72 174-72t175 72q42 0 75-19t52-50 33-73 18-85 4-90z m-143 495q0-88-62-151t-152-63-151 63-63 151 63 152 151 63 152-63 62-152z" horiz-adv-x="714.3" />
|
||||
|
||||
<glyph glyph-name="edit" unicode="" d="M496 189l64 65-85 85-64-65v-31h53v-54h32z m245 402q-9 9-18 0l-196-196q-9-9 0-18t18 0l196 196q9 9 0 18z m45-331v-106q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q35 0 65-14 9-4 10-13 2-10-5-16l-27-28q-8-8-18-4-13 3-25 3h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v70q0 7 5 12l36 36q8 8 20 4t11-16z m-54 411l161-160-375-375h-161v160z m248-73l-51-52-161 161 51 52q16 15 38 15t38-15l85-85q16-16 16-38t-16-38z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="right-big" unicode="" d="M821 314q0-30-20-50l-363-364q-22-20-51-20-29 0-50 20l-42 42q-22 21-22 51t22 51l163 163h-393q-29 0-47 21t-18 51v71q0 30 18 51t47 20h393l-163 165q-22 20-22 50t22 50l42 42q21 21 50 21 29 0 51-21l363-363q20-20 20-51z" horiz-adv-x="857.1" />
|
||||
|
||||
<glyph glyph-name="logout" unicode="" d="M357 46q0-2 1-11t0-14-2-14-5-11-12-3h-178q-67 0-114 47t-47 114v392q0 67 47 114t114 47h178q8 0 13-5t5-13q0-2 1-11t0-15-2-13-5-11-12-3h-178q-37 0-63-26t-27-64v-392q0-37 27-63t63-27h174t6 0 7-2 4-3 4-5 1-8z m518 304q0-14-11-25l-303-304q-11-10-25-10t-25 10-11 25v161h-250q-14 0-25 11t-11 25v214q0 15 11 25t25 11h250v161q0 14 11 25t25 10 25-10l303-304q11-10 11-25z" horiz-adv-x="928.6" />
|
||||
|
||||
<glyph glyph-name="left-big" unicode="" d="M857 350v-71q0-30-18-51t-47-21h-393l164-164q21-20 21-50t-21-50l-42-43q-21-20-51-20-29 0-50 20l-364 364q-20 21-20 50 0 29 20 51l364 363q21 21 50 21 29 0 51-21l42-41q21-22 21-51t-21-51l-164-164h393q29 0 47-20t18-51z" horiz-adv-x="857.1" />
|
||||
|
||||
<glyph glyph-name="facebook" unicode="" d="M535 843v-147h-87q-48 0-65-20t-17-60v-106h164l-22-165h-142v-424h-171v424h-142v165h142v122q0 104 58 161t155 57q82 0 127-7z" horiz-adv-x="571.4" />
|
||||
|
||||
<glyph glyph-name="tasks" unicode="" d="M571 64h358v72h-358v-72z m-214 286h572v71h-572v-71z m357 286h215v71h-215v-71z m286-465v-142q0-15-11-25t-25-11h-928q-15 0-25 11t-11 25v142q0 15 11 26t25 10h928q15 0 25-10t11-26z m0 286v-143q0-14-11-25t-25-10h-928q-15 0-25 10t-11 25v143q0 15 11 25t25 11h928q15 0 25-11t11-25z m0 286v-143q0-14-11-25t-25-11h-928q-15 0-25 11t-11 25v143q0 14 11 25t25 11h928q15 0 25-11t11-25z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="menu" unicode="" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-14-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
|
||||
|
||||
<glyph glyph-name="github" unicode="" d="M357 171q0-22-7-45t-24-43-40-19-41 19-24 43-7 45 7 46 24 43 41 19 40-19 24-43 7-46z m357 0q0-22-7-45t-24-43-40-19-41 19-24 43-7 45 7 46 24 43 41 19 40-19 24-43 7-46z m90 0q0 67-39 114t-104 47q-23 0-109-12-40-6-88-6t-87 6q-85 12-109 12-66 0-104-47t-39-114q0-49 18-85t45-58 68-33 78-17 83-4h94q46 0 83 4t78 17 69 33 45 58 18 85z m125 99q0-116-34-185-22-43-59-74t-79-48-95-27-96-12-93-3q-43 0-79 2t-82 7-85 17-77 29-67 45-48 64q-35 69-35 185 0 132 76 221-15 45-15 95 0 64 28 121 61 0 106-22t106-69q82 20 172 20 83 0 157-18 58 46 104 67t105 22q29-57 29-121 0-49-15-94 76-89 76-222z" horiz-adv-x="928.6" />
|
||||
|
||||
<glyph glyph-name="apple" unicode="" d="M777 172q-21-70-68-139-72-110-144-110-27 0-78 18-48 18-84 18-34 0-79-19-45-19-74-19-85 0-168 145-82 146-82 281 0 127 63 208 63 81 159 81 40 0 98-17 58-17 77-17 25 0 80 19 57 19 97 19 66 0 119-36 29-20 58-56-44-37-64-66-36-52-36-115 0-69 38-125t88-70z m-209 655q0-34-17-76-16-42-52-77-30-30-60-40-20-7-58-10 2 83 44 143 41 60 139 83 1-2 2-6t1-6q0-2 0-6t1-5z" horiz-adv-x="785.7" />
|
||||
|
||||
<glyph glyph-name="graduation-cap" unicode="" d="M990 384l10-177q2-38-46-71t-131-52-180-20-180 20-131 52-46 71l10 177 320-101q12-4 27-4t27 4z m296 180q0-12-13-17l-625-196q-2-1-5-1t-6 1l-364 115q-24-19-39-63t-19-99q35-20 35-61 0-39-32-60l32-242q1-7-4-13-5-7-14-7h-107q-8 0-13 7-6 6-5 13l33 242q-33 21-33 60 0 41 36 62 7 115 55 184l-186 58q-12 5-12 17t12 18l625 196q3 1 6 1t5-1l625-196q13-5 13-18z" horiz-adv-x="1285.7" />
|
||||
|
||||
<glyph glyph-name="google" unicode="" d="M429 411h404q7-37 7-71 0-121-51-216t-145-149-215-54q-88 0-167 34t-137 91-91 137-34 167 34 167 91 137 137 91 167 34q167 0 287-113l-117-112q-68 67-170 67-72 0-133-37t-97-98-36-136 36-136 97-98 133-37q48 0 89 14t67 33 46 46 28 49 13 43h-243v147z" horiz-adv-x="857.1" />
|
||||
|
||||
<glyph glyph-name="paper-plane" unicode="" d="M984 844q19-13 15-36l-142-857q-3-16-18-25-8-5-18-5-6 0-13 3l-253 104-135-165q-10-13-27-13-7 0-12 2-11 4-17 13t-7 21v195l482 590-596-516-221 91q-20 8-22 30-1 23 18 33l928 536q9 5 18 5 11 0 20-6z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="history" unicode="" d="M857 350q0-87-34-166t-91-137-137-92-166-34q-96 0-183 41t-147 114q-4 6-4 13t5 11l76 77q6 5 14 5 9-1 13-7 41-53 100-82t126-29q58 0 110 23t92 61 61 91 22 111-22 111-61 91-92 61-110 23q-55 0-105-20t-90-57l77-77q17-16 8-38-10-23-33-23h-250q-15 0-25 11t-11 25v250q0 24 22 33 22 10 39-8l72-72q60 57 137 88t159 31q87 0 166-34t137-92 91-137 34-166z m-357 161v-250q0-8-5-13t-13-5h-178q-8 0-13 5t-5 13v35q0 8 5 13t13 5h125v197q0 8 5 13t12 5h36q8 0 13-5t5-13z" horiz-adv-x="857.1" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.1 KiB |
@@ -0,0 +1,3 @@
|
||||
# allow crawling everything by default
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rewriteRelativeImportExtensions": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"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
|
||||
//
|
||||
// To make changes to top-level options such as include and exclude, we recommend extending
|
||||
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import adapter from '@sveltejs/adapter-static';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
server: {
|
||||
host: "0.0.0.0"
|
||||
},
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
sveltekit({
|
||||
compilerOptions: {
|
||||
// Force runes mode for the project, except for libraries. Can be removed in svelte 6.
|
||||
runes: ({ filename }) => filename.split(/[/\\]/).includes('node_modules') ? undefined : true
|
||||
},
|
||||
|
||||
// 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({
|
||||
pages: '../internal/http/web',
|
||||
assets: '../internal/http/web',
|
||||
fallback: 'index.html', // <-- vérifie que c'est bien là et pas oublié/mal placé
|
||||
precompress: false,
|
||||
strict: true
|
||||
}),
|
||||
})
|
||||
]
|
||||
});
|
||||