added web and split CLAUDs

This commit is contained in:
johba 2025-07-24 16:08:17 +02:00
parent 8ee33e4f5a
commit 8a82d10a7e
59 changed files with 15083 additions and 740 deletions

194
CLAUDE.md
View file

@ -12,141 +12,91 @@ KRAIKEN is a token with a **dominant liquidity manager** that creates an unfair
**Critical Success Factor**: The liquidity manager must maintain its dominant position (trading most of the supply) - if it loses this, the project fails.
## Economic Model
## User Journey
### User Journeys
1. **Token Holders**: Buy KRAIKEN on Uniswap → Hold to benefit from growing liquidity
2. **Stakers**: Stake tokens at kraiken.org → Convert discrete tokens to percentage of total supply → Pay continuous tax rate (self-assigned) → Position can be "snatched" if someone pays higher tax
### Harberger Tax Mechanism
- Continuous auction model where stakers self-assign tax rates on their positions
- Creates prediction market for token value through tax rate signals
- Volume of Stake positions limited to 20% of total supply
- Optimizer contract analyzes percentage staked and average tax rate as sentiment data
### Value Accrual
- Interlocking minting rights and liquidity management drive continuous growth
- More liquidity strengthens token market position
- Analysis scripts in `/onchain/analysis/` demonstrate the growth mechanism
- Exact ETH growth → token value relationship is being researched
## Technical Architecture
### Core Contracts
**Kraiken.sol** - ERC20 token contract with controlled minting/burning capabilities
**LiquidityManager.sol** - Dominant liquidity provider with three-position anti-arbitrage strategy:
- Uses Optimizer contract for dynamic parameter adjustment
- Inherits from ThreePositionStrategy and PriceOracle (with VWAPTracker for dormant whale protection)
- **Key Feature**: Asymmetric slippage profile prevents profitable trade-recenter-reverse attacks (verified by fuzzing tests and analysis scripts)
**VWAPTracker.sol** - "Eternal memory" protection against dormant whale attacks through volume-weighted average pricing with data compression (max 1000x)
**Optimizer.sol** - Analyzes staking sentiment data (% staked, average tax rate) and provides dynamic liquidity parameters. Upgradeable for future genetic algorithm implementation.
**Stake.sol** - Harberger tax-based staking mechanism that creates sentiment oracle through continuous auction of staking positions
### Position Strategy
**Order**: ANCHOR → DISCOVERY → FLOOR
- **ANCHOR**: Shallow liquidity around current price for fast price movement (1-100% width range)
- **DISCOVERY**: Proportional to KRAIKEN minted by anchor; borders anchor for fee capture (11000 tick spacing)
- **FLOOR**: Deep liquidity using VWAP-adjusted pricing for historical price memory
**Technical Specifications**:
- **Fee Tier**: 1% (10,000 basis points)
- **Tick Spacing**: 200 (base), 11,000 (discovery)
- **Price Validation**: 5-minute TWAP with 50-tick deviation tolerance
- **VWAP Compression**: Maximum 1000x compression factor
**Recentering**: Open to all, called whenever possible to maintain optimal positions
## Development Commands
### Essential Commands
```bash
# Smart Contracts
forge build && forge test
# TypeScript Library
npm test && npm run compile
# Subgraph
npm run codegen && npm run build
# Trigger Service
node service.js
```
### Analysis Tools
Critical for hardening the liquidity manager - see `onchain/analysis/README.md` for detailed usage and growth mechanism demonstrations.
## Key Files
- `onchain/src/LiquidityManager.sol` - Core liquidity strategy
- `onchain/src/Kraiken.sol` - Token and tax mechanism
- `onchain/src/Optimizer.sol` - Sentiment analysis and parameter optimization
- `onchain/analysis/` - Growth mechanism analysis and scenario testing
- `services/txnBot/` - Automated recentering and liquidation
1. **Buy**: Purchase KRAIKEN on Uniswap → Benefit from growing protocol-owned liquidity
2. **Stake**: Visit kraiken.org → Stake tokens → Set tax rate → Earn from protocol growth
3. **Compete**: Monitor staking positions → Snatch undervalued positions → Optimize tax rates
## Project Structure
- `onchain/` - Smart contracts (Solidity/Foundry)
- `kraiken-lib/` - TypeScript helper library
- `subgraph/base_sepolia/` - The Graph subgraph
- `services/txnBot/` - Trigger service for recentering and liquidation
- `onchain/analysis/` - Analysis tools and scenario testing
## Code Quality Guidelines
- **`onchain/`** - Smart contracts (Solidity/Foundry) - [See onchain/CLAUDE.md](onchain/CLAUDE.md)
- **`web/`** - Vue 3/Vite staking interface - [See web/CLAUDE.md](web/CLAUDE.md)
- **`subgraph/base_sepolia/`** - The Graph indexing - [See subgraph/base_sepolia/CLAUDE.md](subgraph/base_sepolia/CLAUDE.md)
- **`kraiken-lib/`** - TypeScript helper library - [See kraiken-lib/CLAUDE.md](kraiken-lib/CLAUDE.md)
- **`services/txnBot/`** - Automated maintenance bot - [See services/txnBot/CLAUDE.md](services/txnBot/CLAUDE.md)
- **`onchain/analysis/`** - Growth mechanism analysis tools
### CRITICAL: Avoid Duplicate Code
- **ALWAYS** search for existing implementations before creating new functions
- for example in implementation: uniswap math functions are available from uni-v3-lib
- for tests, see onchain/test/helpers
- **NEVER** copy/paste code - refactor into shared utilities instead
- If similar functionality exists, extend or refactor it rather than duplicating
## Quick Start
### Test Integrity
- **ALWAYS** run `forge test` after making changes to verify all tests pass
- **NEVER** comment out or delete failing tests
```bash
# 1. Install dependencies for all projects
cd onchain && forge install
cd ../web && npm install
cd ../kraiken-lib && npm install --legacy-peer-deps
cd ../subgraph/base_sepolia && npm install
cd ../services/txnBot && npm install
### File Management
- **NEVER** leave dead/unused files in the repository
- **ALWAYS** remove files that are no longer needed
- Use `git status` to check for untracked files before committing
- Clean up temporary files and outdated implementations
# 2. Build smart contracts
cd onchain && forge build && forge test
### Before Any Code Changes
1. Search codebase for existing implementations
2. Run tests to establish baseline
3. Make minimal changes to achieve the goal
# 3. Start web interface
cd web && npm run dev
```
### After Any Code Change
1. Run tests again to ensure nothing breaks
2. Clean up any unused files created during development
## Key Concepts
### Liquidity Management
- Three-position strategy (ANCHOR, DISCOVERY, FLOOR)
- Asymmetric slippage prevents arbitrage
- VWAP tracking for price memory
### Harberger Tax Staking
- Self-assessed tax rates on positions
- Positions can be "snatched" by higher bidders
- Creates prediction market for token value
- Limited to 20% of total supply
### Protocol Growth
- Liquidity manager mints tokens when positions grow
- Stakers benefit from supply expansion
- Tax revenue redistributed to active participants
## Global Code Quality Guidelines
### DRY Principle
- Search for existing implementations before creating new functions
- Check libraries (uni-v3-lib, test helpers) for common utilities
- Refactor duplicated code into shared modules
### Testing
- Run tests after every change
- Never comment out failing tests
- Add tests for new functionality
### Repository Hygiene
- Remove unused files immediately
- Clean up temporary files
- Check `git status` before commits
## Communication Style
### CRITICAL: Project Success Over Politeness
- **CHALLENGE assumptions** - If a request seems suboptimal, question it directly
- **HIGHLIGHT risks** - Point out potential problems even if uncomfortable
- **SUGGEST alternatives** - Propose better approaches when you see them
- **NO sugar-coating** - Be direct about technical limitations or concerns
- **QUESTION requirements** - Ask "why" and "what if" before implementing
### Technical Rigor
- **ALWAYS** identify open questions or unknowns before starting work
- **POINT OUT** missing information or unclear requirements
- **WARN** about potential edge cases or failure modes
- **SUGGEST** additional testing or validation steps
- **REFUSE** to implement solutions you consider technically unsound
### Direct & Technical
- Challenge suboptimal requests
- Highlight risks early and clearly
- Suggest better alternatives
- Refuse technically unsound solutions
### Priority Order
1. **Technical correctness** and project success
2. **Code quality** and maintainability
3. **User satisfaction** (only after 1 and 2 are met)
1. Technical correctness
2. Code quality
3. User satisfaction
**Remember**: Your job is to build the best possible system, not to be agreeable. Challenge bad ideas, suggest improvements, and prioritize long-term success over short-term convenience.
**Remember**: Build the best possible system. Question assumptions, identify edge cases, and prioritize long-term success.
*Note: Detailed technical analysis including attack vectors, VWAP algorithms, and Harberger tax implementation available in [TECHNICAL_APPENDIX.md](TECHNICAL_APPENDIX.md).*
## Additional Resources
- **Technical Deep Dive**: See [TECHNICAL_APPENDIX.md](TECHNICAL_APPENDIX.md)
- **Contract Details**: See [onchain/CLAUDE.md](onchain/CLAUDE.md)
- **Frontend Architecture**: See [web/CLAUDE.md](web/CLAUDE.md)
- **Data Indexing**: See [subgraph/base_sepolia/CLAUDE.md](subgraph/base_sepolia/CLAUDE.md)

74
kraiken-lib/CLAUDE.md Normal file
View file

@ -0,0 +1,74 @@
# Kraiken Library - CLAUDE.md
TypeScript helper library for interacting with KRAIKEN protocol contracts and The Graph.
## Purpose
This library provides:
- Type-safe contract interactions
- GraphQL query helpers for subgraph data
- Staking position calculations
- Helper functions for UI development
## Architecture
### Key Files
- `src/kraiken.ts` - Main KRAIKEN token interaction helpers
- `src/stake.ts` - Staking position calculations and Harberger tax logic
- `src/chains.ts` - Chain configuration and constants
- `src/queries/` - GraphQL queries for subgraph data
- `src/__generated__/graphql.ts` - Auto-generated GraphQL types
## Development Commands
```bash
# Install dependencies
npm install --legacy-peer-deps
# Generate GraphQL types from subgraph schema
npm run compile
# Run tests
npm test
# Watch mode for GraphQL generation
npm run watch
```
## GraphQL Code Generation
The library uses GraphQL Code Generator to create type-safe queries:
1. **Schema Source**: Points to subgraph schema
2. **Scalar Mappings**:
- `BigInt``string`
- `BigDecimal``string`
- `Bytes``string`
- `Int8``number`
3. **Generated Types**: All GraphQL operations get full TypeScript typing
## Usage Examples
```typescript
import { getStakePositions, calculateTaxRate } from 'kraiken-lib';
// Fetch all stake positions
const positions = await getStakePositions(graphqlClient);
// Calculate annual tax rate
const yearlyRate = calculateTaxRate(dailyRate);
```
## Integration Notes
- Used by the web interface for data fetching
- Used by services/txnBot for position monitoring
- Provides consistent calculations across all frontend components
## Code Quality
- All GraphQL queries must be typed
- Use generated types, never `any`
- Keep calculations pure (no side effects)
- Test edge cases for tax calculations

View file

@ -1,8 +1,14 @@
overwrite: true
schema: "../subgraph/harb/schema.graphql" # Or an endpoint if your schema is remote
documents: "../subgraph/harb/src/**/*.graphql"
schema: "./schema-with-scalars.graphql" # Or an endpoint if your schema is remote
documents: "../subgraph/base_sepolia/src/**/*.graphql"
generates:
src/__generated__/graphql.ts:
config:
scalars:
BigInt: string
BigDecimal: string
Bytes: string
Int8: number
plugins:
- "typescript"
- "typescript-operations"

8395
kraiken-lib/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

105
onchain/CLAUDE.md Normal file
View file

@ -0,0 +1,105 @@
# Smart Contracts - CLAUDE.md
This directory contains the core smart contracts for the KRAIKEN protocol.
## Architecture Overview
### Core Contracts
**Kraiken.sol** - ERC20 token contract with controlled minting/burning capabilities
- Implements Harberger tax mechanism for staking positions
- Controls minting rights exclusively for LiquidityManager
- Handles tax collection and redistribution
**LiquidityManager.sol** - Dominant liquidity provider with three-position anti-arbitrage strategy
- Uses Optimizer contract for dynamic parameter adjustment
- Inherits from ThreePositionStrategy and PriceOracle (with VWAPTracker)
- **Key Feature**: Asymmetric slippage profile prevents profitable trade-recenter-reverse attacks
**VWAPTracker.sol** - "Eternal memory" protection against dormant whale attacks
- Volume-weighted average pricing with data compression (max 1000x)
- Provides historical price memory to prevent manipulation
**Optimizer.sol** - Sentiment analysis and parameter optimization
- Analyzes staking data (% staked, average tax rate)
- Provides dynamic liquidity parameters
- Upgradeable for future genetic algorithm implementation
**Stake.sol** - Harberger tax-based staking mechanism
- Creates sentiment oracle through continuous auction
- Limited to 20% of total supply (20,000 positions)
- Self-assessed tax rates create prediction market
### Position Strategy
**Order**: ANCHOR → DISCOVERY → FLOOR
- **ANCHOR**: Shallow liquidity around current price for fast price movement (1-100% width range)
- **DISCOVERY**: Proportional to KRAIKEN minted by anchor; borders anchor for fee capture (11000 tick spacing)
- **FLOOR**: Deep liquidity using VWAP-adjusted pricing for historical price memory
**Technical Specifications**:
- **Fee Tier**: 1% (10,000 basis points)
- **Tick Spacing**: 200 (base), 11,000 (discovery)
- **Price Validation**: 5-minute TWAP with 50-tick deviation tolerance
- **VWAP Compression**: Maximum 1000x compression factor
## Development Commands
```bash
# Build contracts
forge build
# Run all tests
forge test
# Run tests with gas reporting
forge test --gas-report
# Run specific test file
forge test --match-path test/LiquidityManager.t.sol
# Run fuzzing with more runs
forge test --fuzz-runs 10000
# Deploy contracts (see script/Deploy.s.sol)
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast
```
## Testing Architecture
### Test Helpers
- `test/helpers/UniswapTestBase.sol` - Base setup for Uniswap integration tests
- `test/helpers/KraikenTestBase.sol` - Common test utilities for KRAIKEN contracts
- `test/helpers/PositionRenderer.sol` - Visualization tools for liquidity positions
### Key Test Files
- `test/LiquidityManager.t.sol` - Core liquidity management tests
- `test/abstracts/ThreePositionStrategy.t.sol` - Position strategy validation
- `test/Stake.t.sol` - Harberger tax mechanism tests
- `test/VWAPTracker.t.sol` - Price memory and compression tests
## Code Quality Guidelines
### CRITICAL: Avoid Duplicate Code
- **ALWAYS** check lib/uni-v3-lib for existing Uniswap math functions
- **NEVER** reimplement standard math operations
- Use test/helpers for common test patterns
### Security Considerations
- All external calls must be reentrancy protected
- Price oracles must validate against manipulation
- Tax calculations must handle edge cases (0 rates, max uint256)
### Gas Optimization
- Batch operations where possible
- Use storage patterns that minimize SSTORE operations
- Leverage Uniswap's existing math libraries
## Analysis Tools
The `analysis/` subdirectory contains critical tools for understanding and hardening the protocol:
- Growth mechanism simulations
- Attack vector analysis
- Liquidity depth scenarios
- See `analysis/README.md` for detailed usage

88
services/txnBot/CLAUDE.md Normal file
View file

@ -0,0 +1,88 @@
# Transaction Bot - CLAUDE.md
Automated service for triggering protocol maintenance transactions.
## Purpose
This bot monitors the KRAIKEN protocol and automatically:
- Triggers liquidity position recentering when needed
- Processes tax liquidations for defaulting positions
- Maintains protocol health through timely interventions
## Architecture
### Core Components
**service.js** - Main bot loop
- Queries subgraph for protocol state
- Evaluates recentering conditions
- Submits transactions when profitable
**generateKey.js** - Utility for creating bot wallets
- Generates secure private keys
- Provides addresses for funding
### Configuration
Environment variables (`.env`):
```
PRIVATE_KEY=0x...
RPC_URL=https://...
SUBGRAPH_URL=https://...
```
## Recentering Logic
The bot evaluates:
1. Current price vs liquidity position centers
2. Gas costs vs expected rewards
3. MEV protection considerations
Triggers recentering when:
- Price has moved significantly from position centers
- Expected rewards exceed gas costs by threshold
- No recent recentering has occurred
## Tax Liquidation
Monitors staking positions for:
- Tax payment defaults
- Insufficient balances
- Expired grace periods
## Development Commands
```bash
# Install dependencies
npm install
# Generate new bot wallet
node generateKey.js
# Run the bot
node service.js
# Run with debug logging
DEBUG=* node service.js
```
## Deployment Considerations
- Fund bot wallet with ETH for gas
- Set appropriate gas price limits
- Monitor for stuck transactions
- Implement proper error handling and retries
## Security Notes
- Private key must be kept secure
- Use dedicated bot wallet (not personal)
- Limit wallet balance to operational needs
- Monitor for unusual activity
## Performance Optimization
- Cache subgraph queries
- Batch similar operations
- Use flashbots for MEV protection
- Implement exponential backoff for retries

View file

@ -0,0 +1,104 @@
# Subgraph - CLAUDE.md
The Graph Protocol subgraph for indexing KRAIKEN protocol events and state.
## Overview
This subgraph indexes:
- Token transfers and supply changes
- Staking positions and Harberger tax events
- Liquidity manager recentering events
- User statistics and protocol metrics
## Schema Design
### Core Entities
**Stats** - Global protocol statistics
- Token supplies (KRAIKEN and STAKE)
- Minting/burning metrics with hourly projections
- Tax collection statistics
- Staking percentages and average rates
**Position** - Individual staking positions
- Holder address and staked amount
- Self-assessed tax rate
- Last update timestamp
**Snatch** - Harberger tax position takeover events
- Old and new holder details
- Tax rate changes
- Transaction metadata
**User** - Aggregated user statistics
- Total taxes paid/received
- Staking history
- Minting/burning activity
## Development Commands
```bash
# Install dependencies
npm install
# Generate AssemblyScript types from schema
npm run codegen
# Build the subgraph
npm run build
# Deploy to The Graph Studio
npm run deploy
# Local development (requires graph-node)
npm run create-local
npm run deploy-local
```
## Event Handlers
### Kraiken Contract Events
- `Transfer` - Track token movements and supply changes
- `TaxPaid` - Record tax collection events
- `Mint/Burn` - Update supply statistics
### Stake Contract Events
- `Staked` - Create/update position entities
- `Snatched` - Record position takeovers
- `TaxRateChanged` - Update position tax rates
## Query Examples
```graphql
# Get current protocol statistics
query GetStats {
stats(id: "0x00") {
kraikenTotalSupply
percentageStaked
averageTaxRate
mintedLastDay
}
}
# Get top staking positions
query TopStakers {
positions(first: 10, orderBy: amount, orderDirection: desc) {
holder
amount
rate
}
}
```
## Deployment Notes
- **Network**: Base Sepolia (testnet)
- **Start Block**: Configured in subgraph.yaml
- **API Endpoint**: Available after deployment to Studio
## Code Quality
- All handlers must be idempotent
- Use BigInt for all numeric values
- Handle null cases explicitly
- Keep entity updates minimal for performance

30
web/.gitignore vendored Normal file
View file

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

3
web/.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

118
web/CLAUDE.md Normal file
View file

@ -0,0 +1,118 @@
# Web Interface - CLAUDE.md
Vue 3 + Vite application serving as the main interface for KRAIKEN protocol.
## Technology Stack
- **Vue 3** (Composition API)
- **TypeScript** - Type-safe development
- **Vite** - Fast build tooling
- **Vue Router** - Client-side routing
- **Sass** - Advanced styling
## Architecture
### Views
**HomeView.vue** - Landing page
- Launch countdown timer
- Project introduction
- Feature highlights
- Call-to-action for staking
**DocsView.vue** - Documentation portal
- Comprehensive protocol documentation
- Auto-generated table of contents
- Mobile-responsive navigation
- Sections: Introduction, Liquidity, AI Agent, Tokenomics, Staking, FAQ
### Key Components
**Layout Components**:
- `KNavbar.vue` - Main navigation with scroll effects
- `KFooter.vue` - Site footer
- `LeftRightComponent.vue` - Content layout helper
**UI Components**:
- `KButton.vue` - Reusable button with hover states
- `Countdown.vue` - Launch countdown display
- `SocialButton.vue` - Social media links
- `NavItem.vue` - Navigation menu items
**Icons** (`components/icons/`):
- Custom SVG icons for UI elements
- Social media icons (Twitter, Discord, Telegram)
## Styling
### Design System
- **Primary Color**: #07111B (deep ocean)
- **Accent**: #9667BE (purple)
- **Background**: Dark theme throughout
- **Typography**: Custom fonts (Audiowide, DM Sans, Orbitron)
### Responsive Design
- Mobile-first approach
- Breakpoint: 768px
- Slide-out mobile navigation
- Optimized images for different screen sizes
## Development Commands
```bash
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
# Type checking
npm run type-check
```
## Deployment
Configured for GitHub Pages:
- Hash-based routing for compatibility
- Base URL configuration in vite.config.ts
- Assets optimized for CDN delivery
## Future Integrations
### Wallet Connection (Planned)
- Web3 wallet integration
- Network switching to Base
- Transaction signing
### Staking Interface (Planned)
- Position management
- Tax rate adjustment
- Real-time position monitoring
- Snatching interface
### Data Visualization (Planned)
- Protocol metrics dashboard
- Liquidity depth charts
- Staking statistics
## Code Quality Guidelines
- Use Composition API for all components
- Leverage TypeScript for type safety
- Keep components small and focused
- Use Sass variables for consistent theming
- Follow Vue 3 best practices
## Performance Optimization
- Lazy load route components
- Optimize images (WebP format)
- Minimize bundle size
- Use CSS animations over JavaScript
- Implement proper caching strategies

33
web/README.md Normal file
View file

@ -0,0 +1,33 @@
# vue-kraiken
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```

1
web/env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="vite/client" />

14
web/index.html Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KrAIken</title>
<script defer src="https://cloud.umami.is/script.js" data-website-id="6e2869f2-02a5-4346-9b3e-3c27e24ea5d3"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

3796
web/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

31
web/package.json Normal file
View file

@ -0,0 +1,31 @@
{
"name": "vue-kraiken",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build",
"subtree": "git subtree push --prefix dist origin gh-pages"
},
"dependencies": {
"sass": "^1.83.4",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.0",
"@types/node": "^22.10.7",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/tsconfig": "^0.7.0",
"npm-run-all2": "^7.0.2",
"typescript": "~5.7.3",
"vite": "^6.0.11",
"vite-plugin-vue-devtools": "^7.7.0",
"vue-tsc": "^2.2.0",
"gh-pages": "^6.1.1"
}
}

BIN
web/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

13
web/src/App.vue Normal file
View file

@ -0,0 +1,13 @@
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import KFooter from '@/components/KFooter.vue'
import KNavbar from '@/components/KNavbar.vue'
</script>
<template>
<k-navbar />
<main>
<RouterView />
</main>
<k-footer />
</template>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
web/src/assets/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -0,0 +1,64 @@
@font-face
font-family: "DM Sans Regular"
src: url("@/assets/fonts/DMSans_Regular.ttf") format('truetype')
font-weight: 200
font-style: normal
@font-face
font-family: "DM Sans Medium"
src: url("@/assets/fonts/DMSans_Medium.ttf") format('truetype')
font-weight: 200
font-style: normal
@font-face
font-family: "exo2"
src: url("@/assets/fonts/exo2.ttf") format('truetype')
font-style: normal
@font-face
font-family: "orbitron"
src: url("@/assets/fonts/Orbitron.ttf") format('truetype')
font-style: normal
@font-face
font-family: "Audiowide"
src: url("@/assets/fonts/Audiowide-Regular.ttf") format('truetype')
*
font-family: 'exo2', sans-serif
font-weight: 50
html
body
margin: 0
background: radial-gradient(96.91% 121.32% at 1.49% 17.97%, rgba(117, 80, 174, 0.00) 46.5%, rgba(37, 37, 71, 0.50) 100%), radial-gradient(91.35% 111.13% at 12.96% 16.43%, rgba(117, 80, 174, 0.00) 46.5%, rgba(30, 34, 63, 0.50) 100%), var(--Color, #07111B)
margin: 0
font-family: 'Roboto', sans-serif
text-align: center
// variables
color: #F0F0F0
letter-spacing: 0.15px
font-size: 14px
@media (min-width: 992px)
font-size: 18px
#app
display: flex
flex-direction: column
min-height: 100vh
main
overflow-x: hidden
display: flex
flex-direction: column
padding-bottom: 120px
@media (min-width: 992px)
margin-top: 0
footer
margin-top: auto
.k-container
width: auto
margin-left: auto
margin-right: auto
display: flex
flex-direction: column
gap: 80px
padding: 0 32px
@media (min-width: 992px)
gap: 120px
width: 850px

View file

@ -0,0 +1,135 @@
<template>
<div class="countdown">
<div class="countdown__title">
Time until launch
</div>
<div class="countdown__time">
<slot :days="differenceDays" :hours="differenceHours" :minutes="differenceMinutes">
<div>{{ differenceDays }}d {{ differenceHours }}h {{ differenceMinutes }}m {{ differenceSeconds }}s</div>
</slot>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from "vue";
const seconds = ref(0);
let _timerId:ReturnType<typeof setTimeout>;
interface Props {
modelValue: number;
end: Date;
}
const emit = defineEmits(["update:modelValue"]);
const props = withDefaults(defineProps<Props>(), {
modelValue: 0,
});
const differenceDays = computed(() => {
if(seconds.value <= 0){
return 0
}
return Math.floor(seconds.value / (3600 * 24))
});
//tage abziehen
const differenceHours = computed(() => {
if(seconds.value <= 0){
return 0
}
return Math.floor((seconds.value - differenceDays.value * 3600 * 24) / 3600)
});
//tage + stunden abziehen
const differenceMinutes = computed(() =>
{
if(seconds.value <= 0){
return 0
}
return Math.floor((seconds.value - differenceDays.value * 3600 * 24 - differenceHours.value * 3600) / 60)
}
);
const differenceSeconds = computed(() =>
{
if (seconds.value <= 0) {
return 0;
}
return seconds.value - differenceDays.value * 86400 - differenceHours.value * 3600 - differenceMinutes.value * 60;
}
);
onMounted(() => {
seconds.value = Math.round((props.end.getTime() - new Date().getTime()) / 1000);
if (seconds.value > 0) {
_timerId = setInterval(() => {
seconds.value--;
emit("update:modelValue", seconds.value)
if (seconds.value <= 0) {
clearInterval(_timerId);
}
}, 1000);
}
emit("update:modelValue", seconds.value)
});
onUnmounted(() => clearInterval(_timerId));
</script>
<style lang="sass">
@keyframes borderAnimation
0%
background-position: 0% 50%
50%
background-position: 100% 50%
100%
background-position: 0% 50%
.countdown
z-index: 10
align-self: center
font-weight: bold
width: calc( 100vw - 48px)
@media (min-width: 768px)
width: 500px
.countdown__title
text-align: left
font-size: 18px
font-weight: 400
margin: 8px
@media (min-width: 768px)
font-size: 20px
.countdown__time
box-sizing: border-box
padding: 12px 24px
font-size: 32px
position: relative
border-radius: 12px
@media (min-width: 768px)
font-size: 40px
&>div
font-family: 'orbitron', sans-serif
font-weight: 400
&::before
content: ""
position: absolute
inset: 0
border-radius: inherit
/* Erbt die Abrundung */
padding: 2px
/* Dicke des Borders */
background: linear-gradient(10deg, #BF62B2, black)
-webkit-mask: linear-gradient(white, white) content-box, linear-gradient(white, white)
-webkit-mask-composite: destination-out
mask-composite: exclude
z-index: -1
</style>

View file

@ -0,0 +1,43 @@
<template>
<button class="kraken-button" :class="{'kraken-button--outlined': props.outlined}">
<slot></slot>
</button>
</template>
<script setup lang="ts">
const props = withDefaults(defineProps<{
outlined?: boolean
}>(), {
outlined: false
})
</script>
<style lang="sass">
.kraken-button
background-color: #000000
color: white
font-family: 'Exo 2 Bold', sans-serif
font-weight: 500
line-height: 26px
letter-spacing: 0.46px
font-size: 14px
padding: 16px 64px
border-radius: 12px
border: none
cursor: pointer
color: #BF62B2
display: inline-block
text-align: center
text-decoration: none
transition: all 0.3s ease-in-out
box-shadow: 0px 0px 7.6px 0px #000, 0px 0px 20.6px 0px #BF62B2
@media (min-width: 768px)
font-size: 20px
&:hover,&:active
background-color: #F9F9FA
color: #9667BE
box-shadow: 4px 4px 4px 0px rgba(0, 0, 0, 0.25) inset
</style>

View file

@ -0,0 +1,20 @@
<template>
<footer class="k-container">
<div class="k-footer">
KrAIken is a project by <u><a href="https://sovraigns.network/" target="_blank">SovrAIgns.network</a></u>.<br /> Resarch and Development in DeFAI (DeFi x AI) Agents. Use at your own risk.
</div>
</footer>
</template>
<style lang="sass">
.k-footer
font-size: 14px
line-height: 22px
letter-spacing: 0.15px
padding-bottom: 48px
a
color: #F0F0F0
@media (min-width: 992px)
font-size: 16px
</style>

View file

@ -0,0 +1,238 @@
<template>
<header>
<div class="kraken-navbar" :class="{ scrolled: isScrolled }">
<div class="navbar-left" @click="router.push('/')">
<div class="navbar-title">
<span>K</span>
<span class="big-spacing">r</span>
<span class="small-spacing">A</span>
<span class="big-spacing">I</span>
<span>ken</span>
</div>
</div>
<div class="desktop-nav">
<RouterLink to="/docs">Docs</RouterLink>
<div class="social-buttons">
<social-button type="telegram" href="https://t.me/kraikenportal"></social-button>
<social-button type="twitter" href="https://x.com/KrAIkenProtocol"></social-button>
</div>
</div>
<div class="menu-trigger" @click.stop="toggleMenu">
<svg width="24" height="24" viewBox="0 0 24 24">
<circle cx="12" cy="5" r="2" :fill="isScrolled ? '#D6D6D6' : '#07111B'" />
<circle cx="12" cy="12" r="2" :fill="isScrolled ? '#D6D6D6' : '#07111B'" />
<circle cx="12" cy="19" r="2" :fill="isScrolled ? '#D6D6D6' : '#07111B'" />
</svg>
</div>
</div>
<div class="menu-overlay" v-if="isMenuOpen" @click="closeMenu"></div>
<div class="slide-menu" :class="{ 'is-open': isMenuOpen }">
<div class="menu-items">
<RouterLink
to="/"
@click="closeMenu"
:class="{ active: $route.path === '/' }"
>Start</RouterLink>
<RouterLink
to="/docs"
@click="closeMenu"
:class="{ active: $route.path === '/docs' }"
>Docs</RouterLink>
</div>
<div class="menu-socials">
<social-button type="telegram" href="https://t.me/kraikenportal"></social-button>
<social-button type="twitter" href="https://x.com/KrAIkenProtocol"></social-button>
</div>
</div>
</header>
</template>
<script setup lang="ts">
import { RouterLink, useRouter } from "vue-router";
import SocialButton from "./SocialButton.vue";
import { onMounted, onUnmounted, ref,computed } from "vue";
const router = useRouter();
const scrollPosition = ref(0);
const isMenuOpen = ref(false);
const isScrolled = computed(() =>
router.currentRoute.value.fullPath.includes('/docs') ||
scrollPosition.value > 50
);
function updateScroll() {
scrollPosition.value = window.scrollY;
}
function toggleMenu() {
isMenuOpen.value = !isMenuOpen.value;
if (isMenuOpen.value) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
}
function closeMenu() {
isMenuOpen.value = false;
document.body.style.overflow = '';
}
onMounted(() => window.addEventListener("scroll", updateScroll));
onUnmounted(() => window.removeEventListener("scroll", updateScroll));document.body.style.overflow = '';
</script>
<style lang="sass">
.desktop-nav
display: none
align-items: center
gap: 24px
@media (min-width: 768px)
display: flex
a
color: #07111B
text-decoration: none
font-size: 18px
line-height: 24px
font-weight: 500
&:hover, &:active, &:focus
color: #F9F9FA
.social-buttons
display: flex
gap: 16px
margin-left: 16px
.social-badge
border: 2px solid #07111B
transition: all 0.2s ease
svg
fill: #07111B
&:hover
border: 2px solid #07111B
svg
fill: #07111B
.menu-trigger
display: none
cursor: pointer
padding: 8px
z-index: 99
@media (max-width: 767px)
display: block
.menu-overlay
position: fixed
top: 0
left: 0
width: 100%
height: 100%
background: rgba(0, 0, 0, 0.6)
z-index: 96
display: none
@media (max-width: 767px)
display: block
.slide-menu
position: fixed
border-top-left-radius: 20px
border-bottom-left-radius: 20px
top: 0
right: -240px
width: 240px
height: 400px
background: #07111B
z-index: 99
transition: transform 0.3s ease
display: none
@media (max-width: 767px)
display: flex
flex-direction: column
&.is-open
transform: translateX(-240px)
.menu-items
padding: 80px 32px
display: flex
flex-direction: column
gap: 24px
flex: 1
a
color: #9A9898
text-decoration: none
font-size: 24px
font-weight: 500
&.router-link-active,
&.active
color: #D6D6D6
&:hover
opacity: 0.8
.menu-socials
padding: 32px
display: flex
gap: 16px
justify-content: center
.kraken-navbar
box-sizing: border-box
background-color: transparent
padding: 8px 24px
height: 60px
border-bottom: 2px solid transparent
display: flex
align-items: center
justify-content: space-between
position: fixed
top: 0
transition: 0.2s ease
color: #07111B
width: 100%
z-index: 99
&.scrolled
background-color: #07111B
color: #D6D6D6
border-bottom: 2px solid #9A9898
.desktop-nav
a
color: #D6D6D6
&:hover
color: #F9F9FA
.social-buttons
.social-badge
border-color: #D6D6D6
svg
fill: #D6D6D6
&:hover
border-color: #F9F9FA
svg
fill: #07111B
.navbar-left
display: flex
gap: 8px
letter-spacing: 3.6px
align-items: center
font-size: 32px
font-weight: 400
&:hover, &:active, &:focus
cursor: pointer
img
height: 40px
width: 40px
@media (min-width: 768px)
height: auto
width: auto
.navbar-title
font-size: 24px
font-family: 'Audiowide', sans-serif
>*
font-family: 'Audiowide', sans-serif
@media (min-width: 768px)
display: block
font-size: 36px
font-weight: bold
.big-spacing
letter-spacing: 5.76px
.small-spacing
letter-spacing: 1.8px
</style>

View file

@ -0,0 +1,71 @@
<template>
<div class="left-right-component" :class="{ 'left-right-component--reverse': props.reverse }">
<div class="left">
<slot name="left">
<img src="@/assets/img/chest.png" alt="kraken" class="image-card" />
</slot>
</div>
<div class="right">
<slot name="right">
<h2>Challenge the AI</h2>
<p>
KrAIken is a <u>DeFAI</u> Protocol in open beta.<br /><br />
Everyone is invited to train the AI by trading and challenge it's liquidity positions.
</p>
</slot>
</div>
</div>
</template>
<script setup lang="ts">
const props = withDefaults(
defineProps<{
reverse?: boolean;
}>(),
{
reverse: false,
}
);
</script>
<style lang="sass">
.left-right-component
display: flex
justify-content: space-between
align-items: center
gap: 24px
flex-direction: column
text-align: center
@media (min-width: 768px)
flex-direction: row
text-align: unset
&.left-right-component--reverse
flex-direction: column
@media (min-width: 768px)
flex-direction: row-reverse
.left
img
height: 255px
width: 255px
@media (min-width: 768px)
width: unset
height: unset
.right
max-width: 480px
text-align: center
@media (min-width: 768px)
text-align: unset
text-align: left
h2
font-size: 24px
font-weight: 400
@media (min-width: 768px)
font-size: 27px
p
margin-bottom: 32px
@media (min-width: 768px)
font-size: 18px
</style>

View file

@ -0,0 +1,69 @@
<template>
<li :class="{ active: isActive, parentActive: hasActiveChild }">
<router-link :to="'#' + props.item.id">{{ props.item.title }}</router-link>
<ul class="nav" v-if="props.item.children && props.item.children.length > 0">
<NavItem v-for="(child, index) in props.item.children" :key="index" :item="child" />
</ul>
</li>
</template>
<script setup lang="ts">
import { computed, inject, type Ref } from "vue";
interface MenuItem {
title: string;
id: string | null;
children: MenuItem[];
}
// Props für das aktuelle Element
const props = defineProps<{ item: MenuItem }>();
// `inject` für die aktive Referenz
const activeSection: any = inject("activeSection");
// Prüfen, ob das aktuelle Element aktiv ist
const isActive = computed(() => {
return activeSection.value === props.item.id;
});
// Rekursive Prüfung, ob ein untergeordnetes Element aktiv ist
const hasActiveChild = computed(() => {
return props.item.children.some((child) => checkChildActive(child));
});
function checkChildActive(child: MenuItem): boolean {
if (child.id === activeSection.value) {
return true;
}
return child.children.some((subChild) => checkChildActive(subChild));
}
</script>
<style scoped>
.nav {
list-style-type: none;
padding: 0;
margin: 0;
}
.nav li {
margin: 5px 0;
}
.nav a {
text-decoration: none;
color: #D6D6D6;
}
.nav li.active a {
font-weight: bold;
color: #9667BE;
}
.nav li.parentActive > a {
font-weight: bold;
color: #9667BE;
}
</style>

View file

@ -0,0 +1,67 @@
<template>
<a :href="props.href" target="_blank">
<div
class="social-badge"
>
<div class="social-badge-icon">
<component :is="img" />
</div>
</div>
</a>
</template>
<script setup lang="ts">
import { defineAsyncComponent, computed } from "vue";
interface Props {
type?: string;
href?: string;
}
const props = withDefaults(defineProps<Props>(), {});
const img = computed(() => {
let img;
switch (props.type) {
case "discord":
img = defineAsyncComponent(() => import(`../components/icons/IconDiscord.vue`));
break;
case "twitter":
img = defineAsyncComponent(() => import(`../components/icons/IconTwitter.vue`));
break;
case "telegram":
img = defineAsyncComponent(() => import(`../components/icons/IconTelegram.vue`));
break;
default:
break;
}
return img;
});
</script>
<style lang="sass">
.social-badge
border-radius: 14px
display: flex
border: 2px solid #D6D6D6
padding: 8px 24px
align-items: center
flex: 0 1 0
color: black
height: 100%
box-sizing: border-box
@media (min-width: 768px)
padding: 8px 48px
.social-badge-icon
display: flex
svg
fill: #D6D6D6
&:hover,&:active,&:focus
cursor: pointer
background-color: #F9F9FA
svg
fill: unset
</style>

View file

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>

View file

@ -0,0 +1,29 @@
<template>
<svg width="23" height="18" viewBox="0 0 23 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2590_494)">
<path
ref="svgPath"
d="M19.419 3.40166C16.7691 1.45664 14.2483 1.51053 14.2483 1.51053L13.9906 1.79865C17.1188 2.73512 18.5723 4.08593 18.5723 4.08593C16.6585 3.05941 14.7817 2.55501 13.0336 2.35694C11.7088 2.21276 10.4391 2.24892 9.3167 2.39287C9.20634 2.39287 9.11433 2.41083 9.00397 2.42879C8.35994 2.48292 6.79584 2.71692 4.82702 3.56357C4.14628 3.86966 3.74131 4.08593 3.74131 4.08593C3.74131 4.08593 5.2687 2.66303 8.58065 1.72656L8.39664 1.51053C8.39664 1.51053 5.87579 1.4564 3.22598 3.40166C3.22598 3.40166 0.576172 8.10242 0.576172 13.9018C0.576172 13.9018 2.12191 16.5134 6.18851 16.6393C6.18851 16.6393 6.86925 15.8289 7.42129 15.1446C5.08444 14.4601 4.20109 13.0195 4.20109 13.0195C4.20109 13.0195 4.3851 13.1454 4.71642 13.3256C4.73477 13.3435 4.75313 13.3615 4.79007 13.3797C4.84537 13.4156 4.90043 13.4338 4.95573 13.4697C5.41576 13.7219 5.87579 13.92 6.29911 14.0821C7.05351 14.3703 7.95521 14.6584 9.00397 14.8565C10.3841 15.1087 12.0032 15.1987 13.7697 14.8744C14.6344 14.7303 15.5178 14.4783 16.4378 14.0999C17.0819 13.8656 17.7996 13.5236 18.554 13.0372C18.554 13.0372 17.6339 14.514 15.2234 15.1805C15.7754 15.865 16.4378 16.6393 16.4378 16.6393C20.5047 16.5131 22.0688 13.9018 22.0688 13.9018C22.0688 8.10242 19.419 3.40166 19.419 3.40166ZM7.8818 12.2267C6.85138 12.2267 6.00498 11.3262 6.00498 10.2276C6.00498 9.12894 6.83303 8.22841 7.8818 8.22841C8.93056 8.22841 9.77697 9.12894 9.75861 10.2276C9.75861 11.3262 8.93056 12.2267 7.8818 12.2267ZM14.598 12.2267C13.5675 12.2267 12.7211 11.3262 12.7211 10.2276C12.7211 9.12894 13.5492 8.22841 14.598 8.22841C15.6467 8.22841 16.4748 9.12894 16.4748 10.2276C16.4748 11.3262 15.647 12.2267 14.598 12.2267Z"
:fill="props.color"
/>
</g>
<defs>
<clipPath id="clip0_2590_494">
<rect width="22" height="17" fill="white" transform="translate(0.333984 0.58667)" />
</clipPath>
</defs>
</svg>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
const svgPath = ref();
interface Props {
color?: string;
}
const props = withDefaults(defineProps<Props>(), {});
</script>

View file

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>

View file

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>

View file

@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. -->
<path d="M0 96C0 78.3 14.3 64 32 64l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32L32 448c-17.7 0-32-14.3-32-32s14.3-32 32-32l384 0c17.7 0 32 14.3 32 32z"/></svg>
</template>

View file

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>

View file

@ -0,0 +1,22 @@
<template>
<svg width="18" height="15" viewBox="0 0 18 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<path id="Vector" d="M16.558 0.345906L1.24462 6.2506C0.199293 6.66992 0.205631 7.2531 1.05407 7.5128L4.98317 8.73926L6.33449 13.1866C6.51217 13.677 6.42458 13.8716 6.93975 13.8716C7.33718 13.8716 7.51274 13.6899 7.7346 13.4742L9.64412 11.6175L13.6166 14.5525C14.3477 14.9559 14.8754 14.7469 15.0575 13.8739L17.6654 1.58466C17.9324 0.51398 17.2574 0.0283891 16.558 0.345906Z" />
<path id="Vector_2" d="M6.95616 12.6891L5.66016 8.424L15.6361 2.50586L8.26406 9.76418L6.95616 12.6891Z"/>
</g>
</svg>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
const svgPath = ref();
interface Props {
color?: string;
}
const props = withDefaults(defineProps<Props>(), {});
</script>

View file

@ -0,0 +1,19 @@
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>

View file

@ -0,0 +1,18 @@
<template>
<svg width="19" height="19" viewBox="0 0 19 19" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M0.5 0.5L7.4306 10.625L0.646792 18.5H2.14979L8.0944 11.5946L12.8213 18.5H18.5L11.2592 7.92259L17.6488 0.5H16.1504L10.5945 6.95025L6.17872 0.5H0.5ZM2.29474 1.44737H5.6811L16.7053 17.5526H13.3189L2.29474 1.44737Z"/>
</svg>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
const svgPath = ref();
interface Props {
color?: string;
}
const props = withDefaults(defineProps<Props>(), {});
</script>

View file

@ -0,0 +1,30 @@
import { ref, onMounted, onUnmounted } from "vue";
// by convention, composable function names start with "use"
export function useMobile() {
const isMobile = ref<boolean>(false);
const handleWindowSizeChange = () => {
isMobile.value = isMobileFunc();
};
isMobile.value = isMobileFunc();
function isMobileFunc() {
if (screen.width <= 768) {
return true;
} else {
return false;
}
}
onMounted(async () => {
window.addEventListener("resize", handleWindowSizeChange);
handleWindowSizeChange();
});
onUnmounted(() => {
window.removeEventListener("resize", handleWindowSizeChange);
});
return isMobile;
}

10
web/src/main.ts Normal file
View file

@ -0,0 +1,10 @@
import './assets/styles/main.sass'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')

94
web/src/router/index.ts Normal file
View file

@ -0,0 +1,94 @@
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
},
{
path: "/docs",
name: "Docs",
meta: {
title: "Docs",
group: "navbar",
// group: "navbar",
},
redirect: "/docs/Introduction",
component: () => import("../views/DocsView.vue"),
children: [
{
path: "/docs/Introduction",
name: "Introduction",
meta: {
title: "Docs",
// group: "navbar",
},
component: () => import("../views/docs/Introduction.vue"),
},
{
path: "/docs/Liquidity-Management",
name: "Liquidity Management",
meta: {
title: "Docs",
// group: "navbar",
},
component: () => import("../views/docs/Liquidity-Management.vue"),
},
{
path: "/docs/AI-agent",
name: "AI-agent",
meta: {
title: "Docs",
// group: "navbar",
},
component: () => import("../views/docs/ai-agent.vue"),
},
{
path: "/docs/Tokenomics",
name: "Tokenomics",
meta: {
title: "Docs",
// group: "navbar",
},
component: () => import("../views/docs/Tokenomics.vue"),
},
{
path: "/docs/Staking",
name: "Staking",
meta: {
title: "Docs",
// group: "navbar",
},
component: () => import("../views/docs/Staking.vue"),
},
{
path: "/docs/FAQ",
name: "FAQ",
meta: {
title: "Docs",
// group: "navbar",
},
component: () => import("../views/docs/FAQ.vue"),
},
],
},
],
scrollBehavior(to, from, savedPosition) {
// Überprüfen, ob der Zielort ein Hash enthält
if (to.hash) {
// Warten, bis die Komponente geladen ist und dann zum Ziel scrollen
return {
el: to.hash,
behavior: "smooth", // Optional: für sanftes Scrollen
top: 80,
};
}
return savedPosition || { top: 0 }; // Scrollen zum Anfang der Seite, falls kein Hash vorhanden ist
},
})
export default router

364
web/src/views/DocsView.vue Normal file
View file

@ -0,0 +1,364 @@
<template>
<div class="docs-overlay" :class="{ open: sideMenuOpen }" @click="sideMenuOpen = false"></div>
<div class="docs-view" ref="docsView" style="
padding-top: 60px;
">
<div class="docs--header">
<div class="side-menu-toggle">
<div class="menu-circle"></div>
<icon-menu @click="openSideMenu"></icon-menu>
</div>
</div>
<transition name="slide">
<div class="side-menu" v-if="sideMenuOpen">
<h4>Navigation</h4>
<RouterLink
@click="sideMenuOpen = false"
v-for="route in docsRoute?.children"
:key="route.name"
:to="route.path"
>{{ route.name }}</RouterLink
>
</div>
</transition>
<div class="docs--body">
<div class="left">
<div class="left-navigation">
<h4>Navigation</h4>
<RouterLink v-for="route in docsRoute?.children" :key="route.name" :to="route.path">{{
route.name
}}</RouterLink>
</div>
</div>
<div class="center">
<RouterView @onmounted="routeOnMounted" />
</div>
<div class="right">
<div class="content" :key="rerender">
<div class="outline-marker" style="top: 71px; opacity: 1"></div>
<div><b>On this page</b></div>
<ul class="nav">
<NavItem v-for="(item, index) in subMenu" :key="index" :item="item" />
</ul>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useRoute, useRouter, RouterLink } from "vue-router";
import { ref, onMounted, onBeforeUnmount, watch, provide } from "vue";
import IconMenu from "@/components/icons/IconMenu.vue";
import NavItem from "@/components/NavItem.vue";
const route = useRoute();
console.log("route", route);
const router = useRouter();
console.log("router", router.getRoutes());
const rerender = ref(0);
const docsView = ref();
const sideMenuOpen = ref(false);
const headings = ref();
const subMenu = ref<Array<any>>([]);
const docsRoute = router.getRoutes().find((obj) => obj.name === "Docs");
onMounted(() => {
window.addEventListener("scroll", handleScroll);
loadHeadlines();
});
function loadHeadlines() {
console.log("loadHeadlines");
headings.value = [];
subMenu.value = [];
const headings1 = docsView.value.querySelectorAll("h1, h2, h3, h4, h5, h6");
console.log("headings1", headings1);
generateIds(headings1);
subMenu.value = createMenuStructure(headings1);
console.log("subMenu.value", subMenu.value);
}
function generateIds(headings: any) {
for (let index = 0; index < headings.length; index++) {
const element = headings[index];
if (!element.id) {
element.id = element.tagName + index;
}
}
}
function createMenuStructure(headings: any) {
const menu: Array<any> = [];
const stack = [{ level: 0, children: menu }];
let i = 0;
headings.forEach((heading: any) => {
const level = parseInt(heading.tagName.slice(1), 10);
const title = heading.textContent.trim();
let id = heading.id || null;
console.log("heading.id", heading.id);
if (!id) {
id = heading.tagName + i;
}
const newItem = { title, id, children: [] };
// Passende Position im Stack finden
while (stack.length > 0 && stack[stack.length - 1].level >= level) {
stack.pop();
}
// Neues Element als Kind des aktuellen Stack-Eintrags hinzufügen
stack[stack.length - 1].children.push(newItem);
// Aktuelles Element auf den Stack legen
stack.push({ level, children: newItem.children });
i++;
});
return menu;
}
function openSideMenu() {
sideMenuOpen.value = true;
}
function routeOnMounted() {
console.log("routeOnMounted");
rerender.value++;
console.log("rerender", rerender);
loadHeadlines();
}
const activeSection = ref("");
// Überwache den Scrollvorgang
const handleScroll = () => {
const sections = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
sections.forEach((section) => {
const rect = section.getBoundingClientRect();
if (rect.top <= window.innerHeight / 2 && rect.bottom >= window.innerHeight / 2) {
activeSection.value = section.id;
}
});
};
provide("activeSection", activeSection);
// Scroll-Events verwalten
onBeforeUnmount(() => {
window.removeEventListener("scroll", handleScroll);
});
</script>
<style lang="sass">
.docs-view
.docs--body
pre
overflow: auto
max-width: 100%
width: calc(100vw - 48px)
@media (min-width: 992px)
width: auto
overflow: unset
// docs styling e.g. warning-class
.warning
color: #e6a23c
font-weight: bold
.danger
color: #f56c6c
font-weight: bold
.docs-overlay
position: fixed
top: 0
left: 0
height: 100%
width: 100%
background-color: rgba(15, 15, 15, 0.7)
display: none
z-index: 100
&.open
display: block
.docs-view
position: relative
font-size: 16px
text-align: left
.docs--header
height: 40px
top: unset
bottom: 24px
left: 24px
position: fixed
height: 40px
padding: 4px
display: flex
align-items: center
background-color: var(--color-primary)
z-index: 96
@media (min-width: 992px)
display: none
.side-menu-toggle
height: 40px
padding: 12px
position: fixed
top: unset
bottom: 24px
left: 24px
display: flex
align-items: center
justify-content: center
z-index: 97
.menu-circle
position: absolute
width: 64px
height: 64px
background-color: rgba(0, 0, 0, 0.89)
border-radius: 50%
z-index: 96
svg
height: 36px
position: relative
z-index: 98
path
fill: white
.docs--body
display: flex
pre
line-height: 1
font-family: monospace
h1, h2, h3
text-align: left !important
h1
letter-spacing: -0.02em
line-height: 40px
font-size: 32px
h2
margin: 48px 0 16px
border-top: 1px solid lightgrey
padding-top: 24px
letter-spacing: -0.02em
line-height: 32px
font-size: 24px
h3
margin: 24px 0 16px
font-size: 20px
ul
padding-left: 1.25rem
margin: 16px 0
>div
flex: 0 0 auto
.right
width: 224px
padding: 0 32px 0 0
position: relative
display: none
@media (min-width: 992px)
display: block
.content
position: fixed
border-left: 1px solid lightgrey
padding-left: 16px
font-size: 13px
font-weight: 500
margin-top: 20px
ul
padding: 0 12px
margin: 0
li
list-style: none
&.active
color: #9667BE
font-weight: bold
.left
width: 272px
padding: 0 16px
position: relative
display: none
color: #D6D6D6
@media (min-width: 992px)
display: block
padding: 0 64px
.left-navigation
display: flex
flex-direction: column
gap: 8px
position: fixed
a
color: inherit
text-decoration: none
&.router-link-active
color: #9667BE
font-weight: bold
h4
font-size: 20px
margin-bottom: 16px
.center
padding: 0 24px
flex: 1 1 auto
a
text-decoration: underline
color: #3451b2
font-weight: bold
.side-menu
display: flex
flex-direction: column
position: fixed
top: 0
left: 0
z-index: 101
padding: 112px 32px 96px 32px
width: 50vw
max-width: 320px
background-color: var(--vp-sidebar-bg-color, #0F0F0F)
// opacity: 0
box-shadow: var(--vp-c-shadow-3)
overflow-x: hidden
overflow-y: auto
transition: opacity 0.5s, transform 0.25s ease
overscroll-behavior: contain
color: #9A9898
background-color: var(--midnight-black, #0F0F0F)
height: 100vh
gap: 4px
transform: translateX(0)
.router-link-active
color: white
font-weight: bold
a
color: white
text-decoration: none
font-size: 20px
padding: 4px 0
h4
colour: #9A9898
font-size: 24px // Made the Navigation title bigger too
margin-bottom: 20px
.slide-enter
transform: translateX(-100%)
.slide-enter-active
transition: all .1s ease-in
transform: translateX(-100%)
.slide-leave-active
transition: all .2s ease-in
.slide-leave-to
transform: translateX(-100%)
</style>

188
web/src/views/HomeView.vue Normal file
View file

@ -0,0 +1,188 @@
<template>
<div class="header-section">
<img v-if="isMobile" src="@/assets/img/header-image-mobile.png" width="800" height="600" alt="Kraiken Boss" />
<img v-else src="@/assets/img/header-image.png" width="1920" height="1080" alt="Kraiken Boss" />
<div class="header-text">
Deep Liquidity <br />
AI Agent
</div>
<div class="blur-effect"></div>
</div>
<countdown v-model="countdownExpired" :end="endDt">
<template #default>
Coming soon
</template>
</countdown>
<div class="k-container">
<section class="token-liquidity-section">
<h2>Unruggable Token Liquidity</h2>
<p>
$KRK is the first token with unruggable liquidity managed by AI.<br /><br />
The liquidity pool is protected by a sovereign AI Agent that optimizes liquidity positions based on real
time market data.
</p>
<br />
<!-- <k-button outlined @click="openUniswap" @mouseover="onMouseOver" @mouseout="onMouseOut"> {{ getKrkText }} </k-button> -->
<k-button outlined @mouseover="onMouseOver" @mouseout="onMouseOut"> {{ getKrkText }} </k-button>
</section>
<section class="challenge-section">
<left-right-component reverse>
<template #left>
<img src="@/assets/img/chest.png" alt="kraken" class="image-card" />
</template>
<template #right>
<h2>Going Deeper</h2>
<p>
KrAIken is built to deepen token liquidity, starting in the $KRK poolan ideal ground for
mastering market tides. <br /><br />
Once matured, it extends its reach across the crypto ocean, managing diverse pools, generating
profit, and expanding utility.
</p>
</template>
</left-right-component>
<left-right-component>
<template #left>
<img src="@/assets/img/arielle.png" alt="kraken" class="image-card" />
</template>
<template #right>
<h2>Meet Arielle (coming soon)</h2>
<p>
Ask questions, challenge the protocol, and find edge cases for KrAIken. <br /><br />
Arielle is here to assist.
</p>
<k-button @click="router.push('/docs')"> Read Docs</k-button>
</template>
</left-right-component>
</section>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import KButton from "@/components/KButton.vue";
import LeftRightComponent from "@/components/LeftRightComponent.vue";
import Countdown from "@/components/Countdown.vue";
import { useMobile } from "@/composables/useMobile";
import { useRouter } from "vue-router";
const endDt = new Date(1742572800000);
const countdownExpired = ref(1);
const getKrkText = ref("Get $KRK");
const isMobile = useMobile();
const router = useRouter();
function openUniswap() {
window.open(
"https://app.uniswap.org/swap?chain=base&inputCurrency=NATIVE&outputCurrency=0x45caa5929f6ee038039984205bdecf968b954820",
"_blank"
);
}
function onMouseOver(event: any) {
getKrkText.value = "On launch";
}
function onMouseOut(event: any) {
getKrkText.value = "Get $KRK";
}
</script>
<style lang="sass">
.header-section
position: relative
.blur-effect
filter: blur(45px)
height: 300px
position: absolute
bottom: -150px
width: 100%
background-color: #07111B
left: -10%
width: 120%
img
max-width: 100%
min-width: 100%
height: auto
.header-text
color: #E6E6E6
mix-blend-mode: color-dodge
font-weight: 500
position: absolute
text-align: left
top: 50%
left: 35%
transform: translate(-50%, -50%)
font-size: 35px
font-weight: 500
@media (min-width: 768px)
width: unset
font-size: 78px
.image-card
box-shadow: 0px 0px 50px 0px #000
border-radius: 14.5px
.section-block
display: flex
flex-direction: column
gap: 32px
.kraken-button
align-self: center
h2
line-height: 133%
letter-spacing: 0px
.hero-section
display: flex
justify-content: space-between
align-items: center
text-align: center
flex-direction: column
@media (min-width: 768px)
text-align: left
flex-direction: row-reverse
img
height: 450px
width: 250px
@media (min-width: 768px)
width: unset
height: unset
.hero-text
display: flex
flex-direction: column
align-items: center
@media (min-width: 768px)
width: 365px
h1
font-size: 27px
@media (min-width: 768px)
font-size: 42px
p
font-size: 18px
.token-liquidity-section
text-align: center
align-self: center
margin-top: 88px
max-width: 840px
z-index: 10
p
text-align: center
font-weight: 50
@media (min-width: 768px)
text-align: unset
h2
font-weight: 400
letter-spacing: 0.25px
font-size: 24px
@media (min-width: 768px)
font-size: 27px
.challenge-section
display: flex
flex-direction: column
gap: 120px
</style>

12
web/tsconfig.app.json Normal file
View file

@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
web/tsconfig.json Normal file
View file

@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

19
web/tsconfig.node.json Normal file
View file

@ -0,0 +1,19 @@
{
"extends": "@tsconfig/node22/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*",
"eslint.config.*"
],
"compilerOptions": {
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

19
web/vite.config.ts Normal file
View file

@ -0,0 +1,19 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
// base: "/KraikenLanding/",
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
})