Gitlab@Informatics

Skip to content
Snippets Groups Projects
Commit 3c0648eb authored by 65160018's avatar 65160018
Browse files

first update

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 1045 additions and 0 deletions
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
# next.js
/.next/
/out/
# production
/build
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
\ No newline at end of file
app.js 0 → 100644
const express = require("express")
const session = require("express-session")
const app = express()
const testRoutes = require("./routes/testRoutes")
const authRoutes = require("./routes/authRoutes")
const testResultRoutes = require("./routes/testResultRoutes")
const testCaseRoutes = require("./routes/testCaseRoutes")
const infoRoutes = require("./routes/infoRoutes")
const path = require("path")
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
app.use(
session({
secret: process.env.SESSION_SECRET || "your-secret-key", // Ideally use environment variable
resave: false,
saveUninitialized: true,
}),
)
app.set("views", path.join(__dirname, "views")) // Set views directory
app.set("view engine", "ejs") // Set view engine to ejs
// Serve static files
app.use(express.static(path.join(__dirname, "public")))
// Root route redirects to login
app.get("/", (req, res) => {
res.redirect("/login")
})
// Routes
app.use("/tests", testRoutes)
app.use("/", authRoutes)
app.use("/testresults", testResultRoutes)
app.use("/testcases", testCaseRoutes)
app.use("/more-info", infoRoutes)
app.listen(3000, () => {
console.log("Server running on port 3000")
})
const mysql = require("mysql2/promise")
// Create connection pool
const pool = mysql.createPool({
host: process.env.DB_HOST || "localhost",
user: process.env.DB_USER || "root",
password: process.env.DB_PASSWORD || "",
database: process.env.DB_NAME || "test_dashboard3",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
})
// Test connection
async function testConnection() {
try {
const connection = await pool.getConnection()
console.log("Connected to database")
connection.release()
} catch (err) {
console.error("Database connection error: " + err.stack)
}
}
testConnection()
module.exports = pool
const bcrypt = require("bcrypt")
const User = require("../models/userModel")
exports.login = async (req, res) => {
const { email, password } = req.body
try {
const user = await User.getUserByEmail(email)
if (!user) {
return res.render("login", { error: "Invalid credentials" })
}
const isPasswordValid = await bcrypt.compare(password, user.password)
if (isPasswordValid) {
req.session.userId = user.id
return res.redirect("/dashboard")
} else {
return res.render("login", { error: "Invalid credentials" })
}
} catch (err) {
console.error(err)
res.status(500).render("login", { error: "Server error" })
}
}
exports.logout = (req, res) => {
req.session.destroy(() => {
res.redirect("/login")
})
}
exports.renderLogin = (req, res) => {
res.render("login", { error: null })
}
exports.renderRegister = (req, res) => {
res.render("register", { error: null })
}
exports.register = async (req, res) => {
const { username, email, password, confirmPassword } = req.body
try {
// Validate input
if (!username || !email || !password || !confirmPassword) {
return res.render("register", { error: "All fields are required" })
}
if (password !== confirmPassword) {
return res.render("register", { error: "Passwords do not match" })
}
// Check if user already exists
const existingUser = await User.getUserByEmail(email)
if (existingUser) {
return res.render("register", { error: "Email already in use" })
}
const existingUsername = await User.getUserByUsername(username)
if (existingUsername) {
return res.render("register", { error: "Username already taken" })
}
// Hash password
const saltRounds = 10
const hashedPassword = await bcrypt.hash(password, saltRounds)
// Create user
await User.createUser(username, email, hashedPassword)
// Redirect to login
res.render("login", { error: "Registration successful! Please login." })
} catch (err) {
console.error(err)
res.status(500).render("register", { error: "Server error during registration" })
}
}
exports.renderDashboard = (req, res) => {
res.render("dashboard")
}
const TestCase = require("../models/testCaseModel")
const Test = require("../models/testModel")
exports.getAllTestCases = async (req, res) => {
try {
const testCases = await TestCase.getAllTestCases()
const tests = await Test.getAllTests()
res.render("testCase/listTestCases", {
testCases,
tests,
error: null,
selectedTest: null,
selectedStatus: null,
selectedFramework: null
})
} catch (err) {
console.error(err)
res.status(500).render("testCase/listTestCases", {
testCases: [],
tests: [],
error: "Failed to fetch test cases"
})
}
}
exports.getTestCaseById = async (req, res) => {
const id = req.params.id
try {
const testCase = await TestCase.getTestCaseById(id)
const tests = await Test.getAllTests()
if (!testCase) {
return res.status(404).render("error", { message: "Test case not found" })
}
res.render("testCase/editTestCase", { testCase, tests, error: null })
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Server error" })
}
}
exports.createTestCase = async (req, res) => {
try {
// Add user_id from session to the test case data
const testCaseData = {
...req.body,
user_id: req.session.userId,
}
await TestCase.createTestCase(testCaseData)
res.redirect("/testcases")
} catch (err) {
console.error(err)
const tests = await Test.getAllTests()
res.status(500).render("testCase/addTestCase", { error: "Failed to create test case", tests })
}
}
exports.updateTestCase = async (req, res) => {
const id = req.params.id
try {
const result = await TestCase.updateTestCase(id, req.body)
if (result.affectedRows === 0) {
return res.status(404).render("error", { message: "Test case not found" })
}
res.redirect("/testcases")
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Server error" })
}
}
exports.deleteTestCase = async (req, res) => {
const id = req.params.id
try {
const result = await TestCase.deleteTestCase(id)
if (result.affectedRows === 0) {
return res.status(404).render("error", { message: "Test case not found" })
}
res.redirect("/testcases")
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Server error" })
}
}
exports.searchTestCases = async (req, res) => {
const searchTerm = req.query.searchTerm || ""
try {
const testCases = await TestCase.searchTestCases(searchTerm)
const tests = await Test.getAllTests()
res.render("testCase/listTestCases", {
testCases,
tests,
error: null,
selectedTest: null,
selectedStatus: null,
selectedFramework: null
})
} catch (err) {
console.error(err)
res.status(500).render("testCase/listTestCases", {
testCases: [],
tests: [],
error: "Failed to search test cases"
})
}
}
exports.getTestCasesByFramework = async (req, res) => {
const framework = req.query.framework || ""
try {
const testCases = await TestCase.getTestCasesByFramework(framework)
const tests = await Test.getAllTests()
res.render("testCase/listTestCases", {
testCases,
tests,
error: null,
selectedTest: null,
selectedStatus: null,
selectedFramework: framework
})
} catch (err) {
console.error(err)
res.status(500).render("testCase/listTestCases", {
testCases: [],
tests: [],
error: "Failed to fetch test cases",
selectedFramework: framework,
})
}
}
exports.getTestCasesByStatus = async (req, res) => {
const status = req.query.status || ""
try {
const testCases = await TestCase.getTestCasesByStatus(status)
const tests = await Test.getAllTests()
res.render("testCase/listTestCases", {
testCases,
tests,
error: null,
selectedTest: null,
selectedStatus: status,
selectedFramework: null
})
} catch (err) {
console.error(err)
res.status(500).render("testCase/listTestCases", {
testCases: [],
tests: [],
error: "Failed to fetch test cases",
selectedStatus: status,
})
}
}
exports.getTestCasesByTest = async (req, res) => {
const testId = req.query.testId || ""
try {
const testCases = await TestCase.getTestCasesByTestId(testId)
const tests = await Test.getAllTests()
res.render("testCase/listTestCases", {
testCases,
tests,
error: null,
selectedTest: testId,
selectedStatus: null,
selectedFramework: null
})
} catch (err) {
console.error(err)
res.status(500).render("testCase/listTestCases", {
testCases: [],
tests: [],
error: "Failed to fetch test cases",
selectedTest: testId,
})
}
}
exports.renderAddTestCase = async (req, res) => {
try {
const tests = await Test.getAllTests()
res.render("testCase/addTestCase", { error: null, tests })
} catch (err) {
console.error(err)
res.status(500).render("testCase/addTestCase", { error: "Failed to load form data", tests: [] })
}
}
const Test = require("../models/testModel")
exports.getAllTests = async (req, res) => {
try {
const tests = await Test.getAllTests()
res.render("test/listTests", { tests, error: null })
} catch (err) {
console.error(err)
res.status(500).render("test/listTests", { tests: [], error: "Failed to fetch tests" })
}
}
exports.getTestById = async (req, res) => {
const id = req.params.id
try {
const test = await Test.getTestById(id)
if (!test) {
return res.status(404).render("error", { message: "Test not found" })
}
res.render("test/editTest", { test, error: null })
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Server error" })
}
}
exports.createTest = async (req, res) => {
const { test_name, description } = req.body
try {
await Test.createTest(test_name, description)
res.redirect("/tests")
} catch (err) {
console.error(err)
res.status(500).render("test/addTest", { error: "Failed to create test" })
}
}
exports.updateTest = async (req, res) => {
const { test_name, description } = req.body
const id = req.params.id
try {
const result = await Test.updateTest(id, test_name, description)
if (result.affectedRows === 0) {
return res.status(404).render("error", { message: "Test not found" })
}
res.redirect("/tests")
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Server error" })
}
}
exports.deleteTest = async (req, res) => {
const id = req.params.id
try {
const result = await Test.deleteTest(id)
if (result.affectedRows === 0) {
return res.status(404).render("error", { message: "Test not found" })
}
res.redirect("/tests")
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Server error" })
}
}
exports.searchTests = async (req, res) => {
const searchTerm = req.query.searchTerm || ""
try {
const tests = await Test.searchTests(searchTerm)
res.render("test/listTests", { tests, error: null })
} catch (err) {
console.error(err)
res.status(500).render("test/listTests", { tests: [], error: "Failed to search tests" })
}
}
exports.renderAddTest = (req, res) => {
res.render("test/addTest", { error: null })
}
exports.getTestCases = async (req, res) => {
const testId = req.params.id
try {
const test = await Test.getTestById(testId)
if (!test) {
return res.status(404).render("error", { message: "Test not found" })
}
const testCases = await Test.getTestCasesByTestId(testId)
res.render("test/testCases", { test, testCases, error: null })
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Server error" })
}
}
const TestResult = require("../models/testResultModel")
const db = require("../config/db")
exports.getAllTestResults = async (req, res) => {
try {
const testStatistics = await TestResult.getTestStatistics()
const statusStats = await TestResult.getTestCasesByStatus()
const frameworkStats = await TestResult.getTestCasesByFramework()
res.render("testResult/listTestResults", {
testStatistics,
statusStats,
frameworkStats,
error: null
})
} catch (err) {
console.error(err)
res.status(500).render("testResult/listTestResults", {
testStatistics: [],
statusStats: [],
frameworkStats: [],
error: "Failed to fetch test statistics"
})
}
}
exports.addTestResult = async (req, res) => {
const { test_id, user_id, result, score } = req.body
try {
await TestResult.addTestResult(test_id, user_id, result, score)
res.redirect("/testresults")
} catch (err) {
console.error(err)
res.status(500).render("error", { message: "Failed to add test result" })
}
}
exports.renderAddTestResult = async (req, res) => {
try {
// Get all tests and users for the dropdown
const [tests] = await db.query("SELECT id, test_name FROM tests")
const [users] = await db.query("SELECT id, username FROM users")
res.render("testResult/addTestResult", {
error: null,
tests: tests,
users: users,
})
} catch (err) {
console.error(err)
res.status(500).render("testResult/addTestResult", {
error: "Failed to load form data",
tests: [],
users: [],
})
}
}
// ฟังก์ชันสำหรับตรวจสอบว่า user มีการล็อกอินหรือยัง
exports.isAuthenticated = (req, res, next) => {
if (!req.session.userId) {
return res.redirect("/login")
}
next()
}
// Optional: Add role-based middleware if needed
exports.isAdmin = (req, res, next) => {
if (!req.session.userId || !req.session.isAdmin) {
return res.status(403).render("error", { message: "Access denied" })
}
next()
}
const db = require("../config/db")
class TestCase {
static async getAllTestCases() {
try {
const [rows] = await db.query(`
SELECT
tc.*,
u.username as created_by,
t.test_name,
t.description as test_description
FROM test_cases tc
LEFT JOIN users u ON tc.user_id = u.id
LEFT JOIN tests t ON tc.test_id = t.id
ORDER BY tc.test_case_id
`)
return rows
} catch (error) {
console.error("Error in getAllTestCases:", error)
throw error
}
}
static async getTestCaseById(id) {
try {
const [rows] = await db.query(
`
SELECT
tc.*,
u.username as created_by,
t.test_name,
t.description as test_description
FROM test_cases tc
LEFT JOIN users u ON tc.user_id = u.id
LEFT JOIN tests t ON tc.test_id = t.id
WHERE tc.id = ?
`,
[id],
)
return rows[0] || null
} catch (error) {
console.error("Error in getTestCaseById:", error)
throw error
}
}
static async createTestCase(testCaseData) {
try {
const {
test_case_id,
description,
test_step,
test_data,
expected_result,
status,
framework,
user_id,
test_id
} = testCaseData
const [result] = await db.query(
"INSERT INTO test_cases (test_case_id, description, test_step, test_data, expected_result, status, framework, user_id, test_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
[test_case_id, description, test_step, test_data, expected_result, status, framework, user_id, test_id],
)
return result
} catch (error) {
console.error("Error in createTestCase:", error)
throw error
}
}
static async updateTestCase(id, testCaseData) {
try {
const {
test_case_id,
description,
test_step,
test_data,
expected_result,
status,
framework,
test_id
} = testCaseData
const [result] = await db.query(
"UPDATE test_cases SET test_case_id = ?, description = ?, test_step = ?, test_data = ?, expected_result = ?, status = ?, framework = ?, test_id = ? WHERE id = ?",
[test_case_id, description, test_step, test_data, expected_result, status, framework, test_id, id],
)
return result
} catch (error) {
console.error("Error in updateTestCase:", error)
throw error
}
}
static async deleteTestCase(id) {
try {
const [result] = await db.query("DELETE FROM test_cases WHERE id = ?", [id])
return result
} catch (error) {
console.error("Error in deleteTestCase:", error)
throw error
}
}
static async searchTestCases(searchTerm) {
try {
const [rows] = await db.query(
`SELECT
tc.*,
u.username as created_by,
t.test_name,
t.description as test_description
FROM test_cases tc
LEFT JOIN users u ON tc.user_id = u.id
LEFT JOIN tests t ON tc.test_id = t.id
WHERE tc.test_case_id LIKE ?
OR tc.description LIKE ?
OR tc.test_step LIKE ?
OR t.test_name LIKE ?`,
[`%${searchTerm}%`, `%${searchTerm}%`, `%${searchTerm}%`, `%${searchTerm}%`],
)
return rows
} catch (error) {
console.error("Error in searchTestCases:", error)
throw error
}
}
static async getTestCasesByFramework(framework) {
try {
const [rows] = await db.query(
`SELECT
tc.*,
u.username as created_by,
t.test_name,
t.description as test_description
FROM test_cases tc
LEFT JOIN users u ON tc.user_id = u.id
LEFT JOIN tests t ON tc.test_id = t.id
WHERE tc.framework = ?
ORDER BY tc.test_case_id`,
[framework],
)
return rows
} catch (error) {
console.error("Error in getTestCasesByFramework:", error)
throw error
}
}
static async getTestCasesByStatus(status) {
try {
const [rows] = await db.query(
`SELECT
tc.*,
u.username as created_by,
t.test_name,
t.description as test_description
FROM test_cases tc
LEFT JOIN users u ON tc.user_id = u.id
LEFT JOIN tests t ON tc.test_id = t.id
WHERE tc.status = ?
ORDER BY tc.test_case_id`,
[status],
)
return rows
} catch (error) {
console.error("Error in getTestCasesByStatus:", error)
throw error
}
}
static async getTestCasesByTestId(testId) {
try {
const [rows] = await db.query(
`SELECT
tc.*,
u.username as created_by,
t.test_name,
t.description as test_description
FROM test_cases tc
LEFT JOIN users u ON tc.user_id = u.id
LEFT JOIN tests t ON tc.test_id = t.id
WHERE tc.test_id = ?
ORDER BY tc.test_case_id`,
[testId],
)
return rows
} catch (error) {
console.error("Error in getTestCasesByTestId:", error)
throw error
}
}
}
module.exports = TestCase
const db = require("../config/db")
class Test {
static async getAllTests() {
try {
const [rows] = await db.query("SELECT * FROM tests")
return rows
} catch (error) {
console.error("Error in getAllTests:", error)
throw error
}
}
static async getTestById(id) {
try {
const [rows] = await db.query("SELECT * FROM tests WHERE id = ?", [id])
return rows[0] || null
} catch (error) {
console.error("Error in getTestById:", error)
throw error
}
}
static async createTest(test_name, description) {
try {
const [result] = await db.query("INSERT INTO tests (test_name, description) VALUES (?, ?)", [
test_name,
description,
])
return result
} catch (error) {
console.error("Error in createTest:", error)
throw error
}
}
static async updateTest(id, test_name, description) {
try {
const [result] = await db.query("UPDATE tests SET test_name = ?, description = ? WHERE id = ?", [
test_name,
description,
id,
])
return result
} catch (error) {
console.error("Error in updateTest:", error)
throw error
}
}
static async deleteTest(id) {
try {
const [result] = await db.query("DELETE FROM tests WHERE id = ?", [id])
return result
} catch (error) {
console.error("Error in deleteTest:", error)
throw error
}
}
static async searchTests(searchTerm) {
try {
const [rows] = await db.query("SELECT * FROM tests WHERE test_name LIKE ?", [`%${searchTerm}%`])
return rows
} catch (error) {
console.error("Error in searchTests:", error)
throw error
}
}
static async getTestCasesByTestId(testId) {
try {
const [rows] = await db.query(
"SELECT tc.* FROM test_cases tc WHERE tc.test_id = ?",
[testId]
)
return rows
} catch (error) {
console.error("Error in getTestCasesByTestId:", error)
throw error
}
}
}
module.exports = Test
const db = require("../config/db")
class TestResult {
static async getTestStatistics() {
try {
// Get all tests with their test cases statistics
const [rows] = await db.query(`
SELECT
t.id,
t.test_name,
t.description,
COUNT(tc.id) as total_cases,
SUM(CASE WHEN tc.status = 'Passed' THEN 1 ELSE 0 END) as passed_cases,
SUM(CASE WHEN tc.status = 'Failed' THEN 1 ELSE 0 END) as failed_cases,
SUM(CASE WHEN tc.status = 'Not Started' THEN 1 ELSE 0 END) as not_started_cases
FROM tests t
LEFT JOIN test_cases tc ON t.id = tc.test_id
GROUP BY t.id, t.test_name, t.description
ORDER BY t.test_name
`)
return rows
} catch (error) {
console.error("Error in getTestStatistics:", error)
throw error
}
}
static async getTestCasesByStatus() {
try {
const [rows] = await db.query(`
SELECT
status,
COUNT(*) as count
FROM test_cases
GROUP BY status
`)
return rows
} catch (error) {
console.error("Error in getTestCasesByStatus:", error)
throw error
}
}
static async getTestCasesByFramework() {
try {
const [rows] = await db.query(`
SELECT
framework,
COUNT(*) as count
FROM test_cases
GROUP BY framework
`)
return rows
} catch (error) {
console.error("Error in getTestCasesByFramework:", error)
throw error
}
}
}
module.exports = TestResult
const db = require("../config/db")
class User {
static async getUserByUsername(username) {
try {
const [rows] = await db.query("SELECT * FROM users WHERE username = ?", [username])
return rows[0] || null
} catch (error) {
console.error("Error in getUserByUsername:", error)
throw error
}
}
static async getUserByEmail(email) {
try {
const [rows] = await db.query("SELECT * FROM users WHERE email = ?", [email])
return rows[0] || null
} catch (error) {
console.error("Error in getUserByEmail:", error)
throw error
}
}
static async getUserById(id) {
try {
const [rows] = await db.query("SELECT * FROM users WHERE id = ?", [id])
return rows[0] || null
} catch (error) {
console.error("Error in getUserById:", error)
throw error
}
}
static async createUser(username, email, password) {
try {
const [result] = await db.query(
"INSERT INTO users (username, email, password, created_at) VALUES (?, ?, ?, NOW())",
[username, email, password],
)
return result
} catch (error) {
console.error("Error in createUser:", error)
throw error
}
}
static async updateUser(id, userData) {
try {
const { username, email } = userData
const [result] = await db.query("UPDATE users SET username = ?, email = ?, updated_at = NOW() WHERE id = ?", [
username,
email,
id,
])
return result
} catch (error) {
console.error("Error in updateUser:", error)
throw error
}
}
static async updatePassword(id, password) {
try {
const [result] = await db.query("UPDATE users SET password = ?, updated_at = NOW() WHERE id = ?", [password, id])
return result
} catch (error) {
console.error("Error in updatePassword:", error)
throw error
}
}
}
module.exports = User
This diff is collapsed.
{
"name": "my-v0-project",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-aspect-ratio": "^1.1.1",
"@radix-ui/react-avatar": "^1.1.2",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-collapsible": "^1.1.2",
"@radix-ui/react-context-menu": "^2.2.4",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-hover-card": "^1.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-menubar": "^1.1.4",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-progress": "^1.1.1",
"@radix-ui/react-radio-group": "^1.2.2",
"@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slider": "^1.2.2",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-toast": "^1.2.4",
"@radix-ui/react-toggle": "^1.1.1",
"@radix-ui/react-toggle-group": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.6",
"autoprefixer": "^10.4.20",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "1.0.4",
"date-fns": "4.1.0",
"embla-carousel-react": "8.5.1",
"input-otp": "1.4.1",
"lucide-react": "^0.454.0",
"next": "15.1.0",
"next-themes": "latest",
"react": "^19",
"react-day-picker": "8.10.1",
"react-dom": "^19",
"react-hook-form": "^7.54.1",
"react-resizable-panels": "^2.1.7",
"recharts": "2.15.0",
"sonner": "^1.7.1",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.6",
"zod": "^3.24.1",
"mysql2": "latest",
"bcryptjs": "latest",
"express": "latest",
"express-session": "latest",
"path": "latest"
},
"devDependencies": {
"@types/node": "^22",
"@types/react": "^19",
"@types/react-dom": "^19",
"postcss": "^8",
"tailwindcss": "^3.4.17",
"typescript": "^5"
}
}
\ No newline at end of file
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
\ No newline at end of file
public/placeholder-logo.png

958 B

<svg xmlns="http://www.w3.org/2000/svg" width="215" height="48" fill="none"><path fill="#000" d="M57.588 9.6h6L73.828 38h-5.2l-2.36-6.88h-11.36L52.548 38h-5.2l10.24-28.4Zm7.16 17.16-4.16-12.16-4.16 12.16h8.32Zm23.694-2.24c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.486-7.72.12 3.4c.534-1.227 1.307-2.173 2.32-2.84 1.04-.693 2.267-1.04 3.68-1.04 1.494 0 2.76.387 3.8 1.16 1.067.747 1.827 1.813 2.28 3.2.507-1.44 1.294-2.52 2.36-3.24 1.094-.747 2.414-1.12 3.96-1.12 1.414 0 2.64.307 3.68.92s1.84 1.52 2.4 2.72c.56 1.2.84 2.667.84 4.4V38h-4.96V25.92c0-1.813-.293-3.187-.88-4.12-.56-.96-1.413-1.44-2.56-1.44-.906 0-1.68.213-2.32.64-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.84-.48 3.04V38h-4.56V25.92c0-1.2-.133-2.213-.4-3.04-.24-.827-.626-1.453-1.16-1.88-.506-.427-1.133-.64-1.88-.64-.906 0-1.68.227-2.32.68-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.827-.48 3V38h-4.96V16.8h4.48Zm26.723 10.6c0-2.24.427-4.187 1.28-5.84.854-1.68 2.067-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.84 0 3.494.413 4.96 1.24 1.467.827 2.64 2.08 3.52 3.76.88 1.653 1.347 3.693 1.4 6.12v1.32h-15.08c.107 1.813.614 3.227 1.52 4.24.907.987 2.134 1.48 3.68 1.48.987 0 1.88-.253 2.68-.76a4.803 4.803 0 0 0 1.84-2.2l5.08.36c-.64 2.027-1.84 3.64-3.6 4.84-1.733 1.173-3.733 1.76-6 1.76-2.08 0-3.906-.453-5.48-1.36-1.573-.907-2.786-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84Zm15.16-2.04c-.213-1.733-.76-3.013-1.64-3.84-.853-.827-1.893-1.24-3.12-1.24-1.44 0-2.6.453-3.48 1.36-.88.88-1.44 2.12-1.68 3.72h9.92ZM163.139 9.6V38h-5.04V9.6h5.04Zm8.322 7.2.24 5.88-.64-.36c.32-2.053 1.094-3.56 2.32-4.52 1.254-.987 2.787-1.48 4.6-1.48 2.32 0 4.107.733 5.36 2.2 1.254 1.44 1.88 3.387 1.88 5.84V38h-4.96V25.92c0-1.253-.12-2.28-.36-3.08-.24-.8-.64-1.413-1.2-1.84-.533-.427-1.253-.64-2.16-.64-1.44 0-2.573.48-3.4 1.44-.8.933-1.2 2.307-1.2 4.12V38h-4.96V16.8h4.48Zm30.003 7.72c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.443 8.16V38h-5.6v-5.32h5.6Z"/><path fill="#171717" fill-rule="evenodd" d="m7.839 40.783 16.03-28.054L20 6 0 40.783h7.839Zm8.214 0H40L27.99 19.894l-4.02 7.032 3.976 6.914H20.02l-3.967 6.943Z" clip-rule="evenodd"/></svg>
\ No newline at end of file
public/placeholder-user.jpg

2.55 KiB

public/placeholder.jpg

1.56 KiB

<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment