first commit
This commit is contained in:
39
.gitignore
vendored
Normal file
39
.gitignore
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
# 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
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Cypress
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Vitest
|
||||
__screenshots__/
|
||||
|
||||
# Vite
|
||||
*.timestamp-*-*.mjs
|
||||
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
25
index.html
Normal file
25
index.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;700&display=swap">
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Sonoma - Free Lossless Audio Streaming</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.6.0.min.js"
|
||||
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
3216
package-lock.json
generated
Normal file
3216
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
package.json
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "sonoma-site",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.5.27",
|
||||
"vue-router": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node24": "^24.0.4",
|
||||
"@types/node": "^24.10.9",
|
||||
"@vitejs/plugin-vue": "^6.0.3",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"npm-run-all2": "^8.0.4",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-vue-devtools": "^8.0.5",
|
||||
"vue-tsc": "^3.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 261 KiB |
BIN
public/icon.png
Normal file
BIN
public/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
51
src/App.vue
Normal file
51
src/App.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<header>
|
||||
<div class="logo"><a href="/"><img src="/public/icon.png"></a></div>
|
||||
<nav>
|
||||
<RouterLink to='/'>Главная</RouterLink>
|
||||
<a href="https://open.sonoma.su">Слушать</a>
|
||||
<a onclick="toastr.error('В разработке')">Для исполнителей</a>
|
||||
</nav>
|
||||
<button class="theme-toggle" @click="toggleTheme">
|
||||
<i :class="isLightTheme ? 'fas fa-moon' : 'fas fa-sun'"></i>
|
||||
</button>
|
||||
</header>
|
||||
<RouterView />
|
||||
<footer>
|
||||
<div class="footer-top">
|
||||
<div class="footer-links">
|
||||
<a href="https://sonoma.su">Создано группой Sonoma</a>
|
||||
<a>Обратная связь - support@sonoma.su</a>
|
||||
</div>
|
||||
<div class="footer-icons">
|
||||
<a href="https://git.sonoma.su/Sonoma/sonoma-site"><i class="fab fa-github"></i></a>
|
||||
<a href="https://t.me/saddydead"><i class="fab fa-telegram"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>Copyright ©2026 Sonoma</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
data(): { isLightTheme: boolean } {
|
||||
return {
|
||||
isLightTheme: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggleTheme(): void {
|
||||
this.isLightTheme = !this.isLightTheme;
|
||||
if (this.isLightTheme) {
|
||||
document.body.classList.add('light-theme');
|
||||
} else {
|
||||
document.body.classList.remove('light-theme');
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
312
src/assets/main.css
Normal file
312
src/assets/main.css
Normal file
@ -0,0 +1,312 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(180deg, #2b1d3a, #000);
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
transition: background 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
body.light-theme {
|
||||
background: linear-gradient(180deg, #f0f0f0, #ffffff);
|
||||
color: #000;
|
||||
}
|
||||
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
transition: background 0.3s;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
body.light-theme header {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: #fff;
|
||||
margin: 0 15px;
|
||||
text-decoration: none;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
details a {
|
||||
text-decoration: none;
|
||||
color: #a18cd1;
|
||||
}
|
||||
|
||||
.r1 {
|
||||
text-decoration: none;
|
||||
background: linear-gradient(90deg, #a18cd1, #fbc2eb);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
summary {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
body.light-theme nav a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
margin-top: 150px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: 'Manrope', sans serif;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: 'Manrope', sans serif;
|
||||
}
|
||||
|
||||
.main-title h1 {
|
||||
font-family: 'Manrope', sans serif;
|
||||
font-size: 64px;
|
||||
background: linear-gradient(90deg, #a18cd1, #fbc2eb);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.main-title button {
|
||||
margin-top: 20px;
|
||||
padding: 15px 30px;
|
||||
font-size: 18px;
|
||||
border: none;
|
||||
border-radius: 30px;
|
||||
background: linear-gradient(90deg, #a18cd1, #fbc2eb);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pricing {
|
||||
margin: 100px auto;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
.pricing h2 {
|
||||
font-family: 'Manrope', sans serif;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.artists {
|
||||
margin: 100px auto;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
.artists h2 {
|
||||
font-family: 'Manrope', sans serif;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #2b1d3a;
|
||||
border-radius: 20px;
|
||||
padding: 30px;
|
||||
width: 250px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||
transition: background 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
body.light-theme .card {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.card p {
|
||||
font-size: 18px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.card button {
|
||||
margin-top: 20px;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
background: linear-gradient(90deg, #a18cd1, #fbc2eb);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.artist {
|
||||
background: #2b1d3a;
|
||||
border-radius: 200px;
|
||||
padding: 30px;
|
||||
width: 250px;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||
transition: background 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
body.light-theme .artist {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.artist h3 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.artist p {
|
||||
font-size: 18px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.artist button {
|
||||
margin-top: 20px;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
background: linear-gradient(90deg, #a18cd1, #fbc2eb);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: #fff;
|
||||
color: #2b1d3a;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
width: 50px;
|
||||
}
|
||||
footer {
|
||||
background: #0e0e0e;
|
||||
color: #fff;
|
||||
padding: 40px 100px;
|
||||
font-family: 'Manrope', sans-serif;
|
||||
}
|
||||
|
||||
.footer-top {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
border-bottom: 1px solid #444;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.footer-links a {
|
||||
color: #aaa;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.footer-links a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.footer-icons a {
|
||||
margin-right: 15px;
|
||||
color: #aaa;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.footer-icons a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.footer-bottom p {
|
||||
font-size: 12px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.footer-top {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
justify-content: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.footer-icons {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.ticker {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.ticker-track {
|
||||
display: inline-flex;
|
||||
gap: 64px;
|
||||
padding-left: 100%;
|
||||
animation: scroll 20s linear infinite;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
|
||||
.ticker-track span {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
|
||||
@keyframes scroll {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
}
|
||||
to {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
101
src/components/Main.vue
Normal file
101
src/components/Main.vue
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
<template>
|
||||
|
||||
<section class="main-title">
|
||||
<h1>Sonoma Hi-Res</h1>
|
||||
<p>Полностью бесплатный стриминговый сервис для прослушивания FLAC, Lossless и Hi-Res! <br> До 24bit/192kHz</p>
|
||||
<button @click="$router.push('register')">Начать</button>
|
||||
</section>
|
||||
|
||||
<section class="pricing">
|
||||
<h2>Наши преимущества</h2>
|
||||
<p>Чем же мы отличаемся от конкурентов?</p>
|
||||
<div class="options">
|
||||
<div class="card">
|
||||
<h3>Для всех устройств</h3>
|
||||
<p>У нас есть приложения для каждого</p>
|
||||
<p>Windows, Mac, Linux,</p>
|
||||
<p>Web, Android и iOS</p>
|
||||
</div>
|
||||
<div class="card highlight">
|
||||
<h3>Бесплатно</h3>
|
||||
<p>Сервис полностью бесплатный</p>
|
||||
<p>До 24bit/192kHz</p>
|
||||
<p>Все форматы, включая FLAC, Lossless и Hi-Res</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>Поддержка исполнителей</h3>
|
||||
<p>Наш сервис строится на музыке,</p>
|
||||
<p>которую может загрузить любой желающий!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<div class="card highlight">
|
||||
<h3>От таких же как вы</h3>
|
||||
<p>Мы тоже любим музыку в хорошем качестве и бесплатно</p>
|
||||
<p>Также мы знаем, как сложно найти лейбл маленькому артисту</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>Open Source</h3>
|
||||
<p>Весь исходный код сервиса открыт</p>
|
||||
<p>Любой желающий может на него посмотреть</p>
|
||||
<p>MIT License</p>
|
||||
</div>
|
||||
<div class="card highlight">
|
||||
<h3>Сервера в России</h3>
|
||||
<p>Не будет проблем с задержкой или лагами</p>
|
||||
<p>Сервис сделан русскими людьми</p>
|
||||
<p>Поддержка 24/7</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="pricing">
|
||||
<h2>Варианты подписок</h2>
|
||||
<p>Все возможные варианты подписок</p>
|
||||
<div class="options">
|
||||
<div class="card">
|
||||
<h3>Sonoma Artist</h3>
|
||||
<p>Специально для исполнителей</p>
|
||||
<p>Мы ищем исполнителей,</p>
|
||||
<p>Но вы можете сами оставить нам заявку!</p>
|
||||
<button onclick="toastr.error('В разработке')">Связаться</button>
|
||||
</div>
|
||||
<div class="card highlight">
|
||||
<h3>Sonoma Plus</h3>
|
||||
<p>Free</p>
|
||||
<p>Доступ к сервису</p>
|
||||
<p>24bit/192kHz</p>
|
||||
<p>Все форматы, включая FLAC, Lossless и Hi-Res</p>
|
||||
<button onclick="location.href='https://discord.gg/sEqEEchsQW'">Регистрация</button>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>Sonoma Staff</h3>
|
||||
<p>Хотите присоединиться к разработке?</p>
|
||||
<p>Сервис разрабатывается одним человеком</p>
|
||||
<p>Будем рады в поддержке!</p>
|
||||
<button onclick="location.href='https://t.me/saddydead'">Связаться</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="artists">
|
||||
<h2>Нас выбирают</h2>
|
||||
<p>Посмотрите артистов, которые выбрали нас</p>
|
||||
<div class="ticker">
|
||||
<div class="ticker-track">
|
||||
<span>SaddyDEAD</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
<span>ARTIST</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
20
src/main.ts
Normal file
20
src/main.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
import { createMemoryHistory, createRouter } from 'vue-router'
|
||||
|
||||
import Main from './components/Main.vue'
|
||||
|
||||
|
||||
const routes = [
|
||||
{ path: '/', component: Main }
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
createApp(App).use(router).mount('#app')
|
||||
12
tsconfig.app.json
Normal file
12
tsconfig.app.json
Normal 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
tsconfig.json
Normal file
11
tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
tsconfig.node.json
Normal file
19
tsconfig.node.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@tsconfig/node24/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"]
|
||||
}
|
||||
}
|
||||
18
vite.config.ts
Normal file
18
vite.config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
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({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueDevTools(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user