White-label multi-domain tuki (Noxus Intra)
- CSS-muuttujat: kaikki kovakoodatut #0f3460/#16213e korvattu var(--primary-color)/var(--primary-dark) - Uudet API-endpointit: branding (julkinen, domain-pohjainen), company_logo, company_logo_upload - Domain-pohjainen brändäys: HTTP_HOST → yrityksen domains-arrayn matchaus - Login: domain asettaa oletusyrityksen sessioon - check_auth: palauttaa branding-objektin (primary_color, subtitle, logo_url) - company_create/update: käsittelee domains, primary_color, subtitle, logo_file - Dynaaminen login-sivu, header ja footer (logo, nimi, alaotsikko, värit) - JS: loadBranding(), applyBranding(), yritysvaihdon brändäyspäivitys - Admin-paneeli: brändäysasetukset (logo-upload, väri, alaotsikko, domainit) - Git-repo siirretty intra.noxus.fi:hin Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
184
api.php
184
api.php
@@ -1016,6 +1016,143 @@ switch ($action) {
|
|||||||
echo json_encode(['question' => "$a + $b = ?"]);
|
echo json_encode(['question' => "$a + $b = ?"]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// ---------- BRANDING (julkinen) ----------
|
||||||
|
case 'branding':
|
||||||
|
$host = $_SERVER['HTTP_HOST'] ?? '';
|
||||||
|
// Stripaa portti pois (localhost:3001 → localhost)
|
||||||
|
$host = strtolower(explode(':', $host)[0]);
|
||||||
|
$companies = loadCompanies();
|
||||||
|
$matchedCompany = null;
|
||||||
|
foreach ($companies as $comp) {
|
||||||
|
$domains = $comp['domains'] ?? [];
|
||||||
|
foreach ($domains as $d) {
|
||||||
|
if (strtolower(trim($d)) === strtolower($host)) {
|
||||||
|
$matchedCompany = $comp;
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($matchedCompany) {
|
||||||
|
$logoUrl = !empty($matchedCompany['logo_file'])
|
||||||
|
? "api.php?action=company_logo&company_id=" . urlencode($matchedCompany['id'])
|
||||||
|
: '';
|
||||||
|
echo json_encode([
|
||||||
|
'found' => true,
|
||||||
|
'company_id' => $matchedCompany['id'],
|
||||||
|
'nimi' => $matchedCompany['nimi'],
|
||||||
|
'primary_color' => $matchedCompany['primary_color'] ?? '#0f3460',
|
||||||
|
'subtitle' => $matchedCompany['subtitle'] ?? '',
|
||||||
|
'logo_url' => $logoUrl,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// Noxus Intra -oletusbrändäys
|
||||||
|
echo json_encode([
|
||||||
|
'found' => false,
|
||||||
|
'company_id' => '',
|
||||||
|
'nimi' => 'Noxus Intra',
|
||||||
|
'primary_color' => '#0f3460',
|
||||||
|
'subtitle' => 'Hallintapaneeli',
|
||||||
|
'logo_url' => '',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'company_logo':
|
||||||
|
$companyId = $_GET['company_id'] ?? '';
|
||||||
|
if (empty($companyId) || !preg_match('/^[a-z0-9-]+$/', $companyId)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Virheellinen company_id']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$companies = loadCompanies();
|
||||||
|
$logoFile = '';
|
||||||
|
foreach ($companies as $comp) {
|
||||||
|
if ($comp['id'] === $companyId) {
|
||||||
|
$logoFile = $comp['logo_file'] ?? '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (empty($logoFile)) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo json_encode(['error' => 'Logoa ei löydy']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$logoPath = DATA_DIR . '/companies/' . $companyId . '/' . $logoFile;
|
||||||
|
if (!file_exists($logoPath)) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo json_encode(['error' => 'Logotiedostoa ei löydy']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$ext = strtolower(pathinfo($logoFile, PATHINFO_EXTENSION));
|
||||||
|
$mimeTypes = ['png' => 'image/png', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'svg' => 'image/svg+xml', 'webp' => 'image/webp'];
|
||||||
|
$mime = $mimeTypes[$ext] ?? 'application/octet-stream';
|
||||||
|
header('Content-Type: ' . $mime);
|
||||||
|
header('Cache-Control: public, max-age=3600');
|
||||||
|
readfile($logoPath);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
case 'company_logo_upload':
|
||||||
|
requireAdmin();
|
||||||
|
if ($method !== 'POST') break;
|
||||||
|
$companyId = $_POST['company_id'] ?? '';
|
||||||
|
if (empty($companyId) || !preg_match('/^[a-z0-9-]+$/', $companyId)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Virheellinen company_id']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isset($_FILES['logo']) || $_FILES['logo']['error'] !== UPLOAD_ERR_OK) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Logotiedosto puuttuu tai virhe uploadissa']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$file = $_FILES['logo'];
|
||||||
|
// Validoi koko (max 2MB)
|
||||||
|
if ($file['size'] > 2 * 1024 * 1024) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Logo on liian suuri (max 2MB)']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Validoi tyyppi
|
||||||
|
$allowedTypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'image/webp'];
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
|
$detectedType = finfo_file($finfo, $file['tmp_name']);
|
||||||
|
finfo_close($finfo);
|
||||||
|
if (!in_array($detectedType, $allowedTypes)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Sallitut tiedostotyypit: PNG, JPG, SVG, WebP']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$extMap = ['image/png' => 'png', 'image/jpeg' => 'jpg', 'image/svg+xml' => 'svg', 'image/webp' => 'webp'];
|
||||||
|
$ext = $extMap[$detectedType] ?? 'png';
|
||||||
|
$newFilename = 'logo.' . $ext;
|
||||||
|
$compDir = DATA_DIR . '/companies/' . $companyId;
|
||||||
|
if (!file_exists($compDir)) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo json_encode(['error' => 'Yritystä ei löydy']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Poista vanha logo
|
||||||
|
$companies = loadCompanies();
|
||||||
|
foreach ($companies as &$comp) {
|
||||||
|
if ($comp['id'] === $companyId) {
|
||||||
|
$oldLogo = $comp['logo_file'] ?? '';
|
||||||
|
if ($oldLogo && $oldLogo !== $newFilename && file_exists($compDir . '/' . $oldLogo)) {
|
||||||
|
unlink($compDir . '/' . $oldLogo);
|
||||||
|
}
|
||||||
|
$comp['logo_file'] = $newFilename;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($comp);
|
||||||
|
saveCompanies($companies);
|
||||||
|
move_uploaded_file($file['tmp_name'], $compDir . '/' . $newFilename);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'logo_file' => $newFilename,
|
||||||
|
'logo_url' => "api.php?action=company_logo&company_id=" . urlencode($companyId),
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
|
||||||
// ---------- AUTH ----------
|
// ---------- AUTH ----------
|
||||||
case 'login':
|
case 'login':
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
@@ -1050,8 +1187,24 @@ switch ($action) {
|
|||||||
// Multi-company: aseta käyttäjän yritykset sessioon
|
// Multi-company: aseta käyttäjän yritykset sessioon
|
||||||
$userCompanies = $u['companies'] ?? [];
|
$userCompanies = $u['companies'] ?? [];
|
||||||
$_SESSION['companies'] = $userCompanies;
|
$_SESSION['companies'] = $userCompanies;
|
||||||
// Valitse ensimmäinen yritys oletukseksi
|
// Domain-pohjainen oletusyritys
|
||||||
|
$host = strtolower(explode(':', $_SERVER['HTTP_HOST'] ?? '')[0]);
|
||||||
|
$domainCompanyId = '';
|
||||||
|
$allComps = loadCompanies();
|
||||||
|
foreach ($allComps as $dc) {
|
||||||
|
foreach ($dc['domains'] ?? [] as $d) {
|
||||||
|
if (strtolower(trim($d)) === strtolower($host)) {
|
||||||
|
$domainCompanyId = $dc['id'];
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Jos domain matchaa ja käyttäjällä on oikeus → käytä sitä
|
||||||
|
if ($domainCompanyId && in_array($domainCompanyId, $userCompanies)) {
|
||||||
|
$_SESSION['company_id'] = $domainCompanyId;
|
||||||
|
} else {
|
||||||
$_SESSION['company_id'] = !empty($userCompanies) ? $userCompanies[0] : '';
|
$_SESSION['company_id'] = !empty($userCompanies) ? $userCompanies[0] : '';
|
||||||
|
}
|
||||||
// Hae yritysten nimet
|
// Hae yritysten nimet
|
||||||
$allCompanies = loadCompanies();
|
$allCompanies = loadCompanies();
|
||||||
$companyList = [];
|
$companyList = [];
|
||||||
@@ -1116,6 +1269,20 @@ switch ($action) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Brändäystiedot aktiivisesta yrityksestä
|
||||||
|
$branding = ['primary_color' => '#0f3460', 'subtitle' => '', 'logo_url' => '', 'company_nimi' => ''];
|
||||||
|
$activeCompanyId = $_SESSION['company_id'] ?? '';
|
||||||
|
foreach ($allCompanies as $bc) {
|
||||||
|
if ($bc['id'] === $activeCompanyId) {
|
||||||
|
$branding['primary_color'] = $bc['primary_color'] ?? '#0f3460';
|
||||||
|
$branding['subtitle'] = $bc['subtitle'] ?? '';
|
||||||
|
$branding['company_nimi'] = $bc['nimi'] ?? '';
|
||||||
|
$branding['logo_url'] = !empty($bc['logo_file'])
|
||||||
|
? "api.php?action=company_logo&company_id=" . urlencode($bc['id'])
|
||||||
|
: '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'authenticated' => true,
|
'authenticated' => true,
|
||||||
'user_id' => $_SESSION['user_id'],
|
'user_id' => $_SESSION['user_id'],
|
||||||
@@ -1125,6 +1292,7 @@ switch ($action) {
|
|||||||
'companies' => $companyList,
|
'companies' => $companyList,
|
||||||
'company_id' => $_SESSION['company_id'] ?? '',
|
'company_id' => $_SESSION['company_id'] ?? '',
|
||||||
'signatures' => $userSignatures,
|
'signatures' => $userSignatures,
|
||||||
|
'branding' => $branding,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
echo json_encode(['authenticated' => false]);
|
echo json_encode(['authenticated' => false]);
|
||||||
@@ -2479,9 +2647,18 @@ switch ($action) {
|
|||||||
break 2;
|
break 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Brändäyskentät
|
||||||
|
$domains = [];
|
||||||
|
if (isset($input['domains']) && is_array($input['domains'])) {
|
||||||
|
$domains = array_values(array_filter(array_map('trim', $input['domains'])));
|
||||||
|
}
|
||||||
$company = [
|
$company = [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'nimi' => $nimi,
|
'nimi' => $nimi,
|
||||||
|
'domains' => $domains,
|
||||||
|
'primary_color' => trim($input['primary_color'] ?? '#0f3460'),
|
||||||
|
'subtitle' => trim($input['subtitle'] ?? ''),
|
||||||
|
'logo_file' => '',
|
||||||
'luotu' => date('Y-m-d H:i:s'),
|
'luotu' => date('Y-m-d H:i:s'),
|
||||||
'aktiivinen' => true,
|
'aktiivinen' => true,
|
||||||
];
|
];
|
||||||
@@ -2521,6 +2698,11 @@ switch ($action) {
|
|||||||
if ($c['id'] === $id) {
|
if ($c['id'] === $id) {
|
||||||
if (isset($input['nimi'])) $c['nimi'] = trim($input['nimi']);
|
if (isset($input['nimi'])) $c['nimi'] = trim($input['nimi']);
|
||||||
if (isset($input['aktiivinen'])) $c['aktiivinen'] = (bool)$input['aktiivinen'];
|
if (isset($input['aktiivinen'])) $c['aktiivinen'] = (bool)$input['aktiivinen'];
|
||||||
|
if (isset($input['domains']) && is_array($input['domains'])) {
|
||||||
|
$c['domains'] = array_values(array_filter(array_map('trim', $input['domains'])));
|
||||||
|
}
|
||||||
|
if (isset($input['primary_color'])) $c['primary_color'] = trim($input['primary_color']);
|
||||||
|
if (isset($input['subtitle'])) $c['subtitle'] = trim($input['subtitle']);
|
||||||
$found = true;
|
$found = true;
|
||||||
echo json_encode($c);
|
echo json_encode($c);
|
||||||
break;
|
break;
|
||||||
|
|||||||
46
index.html
46
index.html
@@ -3,15 +3,16 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>CuituNet Intra - Asiakashallinta</title>
|
<title>Noxus Intra</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Login -->
|
<!-- Login -->
|
||||||
<div id="login-screen" class="login-screen">
|
<div id="login-screen" class="login-screen">
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
<h1>CuituNet Intra</h1>
|
<img id="login-logo" src="" alt="Logo" style="height:48px;margin-bottom:0.75rem;display:none;">
|
||||||
<p>Kirjaudu sisään</p>
|
<h1 id="login-title">Noxus Intra</h1>
|
||||||
|
<p id="login-subtitle">Kirjaudu sisään</p>
|
||||||
<form id="login-form">
|
<form id="login-form">
|
||||||
<input type="text" id="login-username" placeholder="Käyttäjätunnus" required autofocus>
|
<input type="text" id="login-username" placeholder="Käyttäjätunnus" required autofocus>
|
||||||
<input type="password" id="login-password" placeholder="Salasana" required>
|
<input type="password" id="login-password" placeholder="Salasana" required>
|
||||||
@@ -26,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Salasanan palautuspyyntö -->
|
<!-- Salasanan palautuspyyntö -->
|
||||||
<div class="login-box" id="forgot-box" style="display:none">
|
<div class="login-box" id="forgot-box" style="display:none">
|
||||||
<h1>CuituNet Intra</h1>
|
<h1 class="login-brand-title">Noxus Intra</h1>
|
||||||
<p>Salasanan palautus</p>
|
<p>Salasanan palautus</p>
|
||||||
<form id="forgot-form">
|
<form id="forgot-form">
|
||||||
<input type="text" id="forgot-username" placeholder="Käyttäjätunnus" required autofocus>
|
<input type="text" id="forgot-username" placeholder="Käyttäjätunnus" required autofocus>
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Uusi salasana (reset token) -->
|
<!-- Uusi salasana (reset token) -->
|
||||||
<div class="login-box" id="reset-box" style="display:none">
|
<div class="login-box" id="reset-box" style="display:none">
|
||||||
<h1>CuituNet Intra</h1>
|
<h1 class="login-brand-title">Noxus Intra</h1>
|
||||||
<p>Aseta uusi salasana</p>
|
<p>Aseta uusi salasana</p>
|
||||||
<form id="reset-form">
|
<form id="reset-form">
|
||||||
<input type="password" id="reset-password" placeholder="Uusi salasana" required>
|
<input type="password" id="reset-password" placeholder="Uusi salasana" required>
|
||||||
@@ -55,10 +56,11 @@
|
|||||||
<header>
|
<header>
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<div class="header-brand" id="brand-home" style="cursor:pointer;">
|
<div class="header-brand" id="brand-home" style="cursor:pointer;">
|
||||||
<span class="brand-icon">⚡</span>
|
<img id="header-logo" src="" alt="Logo" style="height:32px;display:none;">
|
||||||
|
<span class="brand-icon" id="header-brand-icon">⚡</span>
|
||||||
<div>
|
<div>
|
||||||
<h1>CuituNet Intra</h1>
|
<h1 id="header-title">Noxus Intra</h1>
|
||||||
<span class="subtitle">Kuituasiakkaiden hallinta</span>
|
<span class="subtitle" id="header-subtitle">Hallintapaneeli</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -514,16 +516,36 @@
|
|||||||
<div id="company-detail-view" style="display:none;">
|
<div id="company-detail-view" style="display:none;">
|
||||||
<button class="btn-secondary" id="btn-company-back" style="color:#555;border-color:#ddd;margin-bottom:1rem;">← Takaisin yrityslistaan</button>
|
<button class="btn-secondary" id="btn-company-back" style="color:#555;border-color:#ddd;margin-bottom:1rem;">← Takaisin yrityslistaan</button>
|
||||||
<div class="table-card" style="padding:1.5rem;">
|
<div class="table-card" style="padding:1.5rem;">
|
||||||
<h3 style="color:#0f3460;margin-bottom:0.5rem;" id="company-detail-title">Yrityksen asetukset</h3>
|
<h3 style="margin-bottom:0.5rem;" id="company-detail-title">Yrityksen asetukset</h3>
|
||||||
<div class="form-grid" style="max-width:400px;margin-bottom:1.5rem;">
|
<div class="form-grid" style="max-width:600px;margin-bottom:1.5rem;">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Yrityksen nimi</label>
|
<label>Yrityksen nimi</label>
|
||||||
<input type="text" id="company-edit-nimi">
|
<input type="text" id="company-edit-nimi">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn-primary" id="btn-save-company-name" style="font-size:0.85rem;">Tallenna nimi</button>
|
<label>Alaotsikko</label>
|
||||||
|
<input type="text" id="company-edit-subtitle" placeholder="esim. Asiakashallinta">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Pääväri</label>
|
||||||
|
<div style="display:flex;align-items:center;gap:0.5rem;">
|
||||||
|
<input type="color" id="company-edit-color" value="#0f3460" style="width:50px;height:36px;border:none;cursor:pointer;">
|
||||||
|
<input type="text" id="company-edit-color-text" placeholder="#0f3460" style="width:100px;font-family:monospace;font-size:0.85rem;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Logo</label>
|
||||||
|
<div style="display:flex;align-items:center;gap:0.75rem;">
|
||||||
|
<img id="company-logo-preview" src="" style="height:36px;display:none;border-radius:4px;">
|
||||||
|
<input type="file" id="company-logo-upload" accept="image/png,image/jpeg,image/svg+xml,image/webp" style="font-size:0.82rem;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group full-width">
|
||||||
|
<label>Domainit (yksi per rivi)</label>
|
||||||
|
<textarea id="company-edit-domains" rows="3" placeholder="intra.yritys.fi intra.toinen.fi" style="font-family:monospace;font-size:0.85rem;"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-primary" id="btn-save-company-settings" style="font-size:0.85rem;">Tallenna asetukset</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Postilaatikot -->
|
<!-- Postilaatikot -->
|
||||||
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
||||||
@@ -592,7 +614,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>CuituNet Intra — Asiakashallintajärjestelmä</p>
|
<p id="footer-text">Noxus Intra © 2026</p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
124
script.js
124
script.js
@@ -136,6 +136,7 @@ async function checkAuth() {
|
|||||||
availableCompanies = data.companies || [];
|
availableCompanies = data.companies || [];
|
||||||
currentCompany = availableCompanies.find(c => c.id === data.company_id) || availableCompanies[0] || null;
|
currentCompany = availableCompanies.find(c => c.id === data.company_id) || availableCompanies[0] || null;
|
||||||
currentUserSignatures = data.signatures || {};
|
currentUserSignatures = data.signatures || {};
|
||||||
|
if (data.branding) applyBranding(data.branding);
|
||||||
showDashboard();
|
showDashboard();
|
||||||
}
|
}
|
||||||
} catch (e) { /* not logged in */ }
|
} catch (e) { /* not logged in */ }
|
||||||
@@ -171,6 +172,7 @@ document.getElementById('btn-logout').addEventListener('click', async () => {
|
|||||||
document.getElementById('login-captcha').value = '';
|
document.getElementById('login-captcha').value = '';
|
||||||
showLoginView();
|
showLoginView();
|
||||||
loadCaptcha();
|
loadCaptcha();
|
||||||
|
loadBranding(); // Domain-pohjainen brändäys uudelleen
|
||||||
});
|
});
|
||||||
|
|
||||||
async function showDashboard() {
|
async function showDashboard() {
|
||||||
@@ -206,6 +208,11 @@ async function switchCompany(companyId) {
|
|||||||
try {
|
try {
|
||||||
await apiCall('company_switch', 'POST', { company_id: companyId });
|
await apiCall('company_switch', 'POST', { company_id: companyId });
|
||||||
currentCompany = availableCompanies.find(c => c.id === companyId) || null;
|
currentCompany = availableCompanies.find(c => c.id === companyId) || null;
|
||||||
|
// Päivitä brändäys vaihdetun yrityksen mukaan
|
||||||
|
try {
|
||||||
|
const auth = await apiCall('check_auth');
|
||||||
|
if (auth.branding) applyBranding(auth.branding);
|
||||||
|
} catch (e2) {}
|
||||||
// Lataa uudelleen aktiivinen tab
|
// Lataa uudelleen aktiivinen tab
|
||||||
const hash = window.location.hash.replace('#', '') || 'customers';
|
const hash = window.location.hash.replace('#', '') || 'customers';
|
||||||
switchToTab(hash);
|
switchToTab(hash);
|
||||||
@@ -1837,6 +1844,20 @@ async function showCompanyDetail(id) {
|
|||||||
const comp = companiesTabData.find(c => c.id === id);
|
const comp = companiesTabData.find(c => c.id === id);
|
||||||
document.getElementById('company-detail-title').textContent = (comp ? comp.nimi : id) + ' — Asetukset';
|
document.getElementById('company-detail-title').textContent = (comp ? comp.nimi : id) + ' — Asetukset';
|
||||||
document.getElementById('company-edit-nimi').value = comp ? comp.nimi : '';
|
document.getElementById('company-edit-nimi').value = comp ? comp.nimi : '';
|
||||||
|
// Brändäyskentät
|
||||||
|
document.getElementById('company-edit-subtitle').value = comp?.subtitle || '';
|
||||||
|
const color = comp?.primary_color || '#0f3460';
|
||||||
|
document.getElementById('company-edit-color').value = color;
|
||||||
|
document.getElementById('company-edit-color-text').value = color;
|
||||||
|
document.getElementById('company-edit-domains').value = (comp?.domains || []).join('\n');
|
||||||
|
// Logo-esikatselu
|
||||||
|
const logoPreview = document.getElementById('company-logo-preview');
|
||||||
|
if (comp?.logo_file) {
|
||||||
|
logoPreview.src = 'api.php?action=company_logo&company_id=' + encodeURIComponent(id) + '&t=' + Date.now();
|
||||||
|
logoPreview.style.display = '';
|
||||||
|
} else {
|
||||||
|
logoPreview.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
// Vaihda aktiivinen yritys jotta API-kutsut kohdistuvat oikein
|
// Vaihda aktiivinen yritys jotta API-kutsut kohdistuvat oikein
|
||||||
await apiCall('company_switch', 'POST', { company_id: id });
|
await apiCall('company_switch', 'POST', { company_id: id });
|
||||||
@@ -1853,18 +1874,60 @@ document.getElementById('btn-company-back').addEventListener('click', () => {
|
|||||||
renderCompaniesTable();
|
renderCompaniesTable();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('btn-save-company-name').addEventListener('click', async () => {
|
// Synkronoi color picker <-> text input
|
||||||
|
document.getElementById('company-edit-color').addEventListener('input', function() {
|
||||||
|
document.getElementById('company-edit-color-text').value = this.value;
|
||||||
|
});
|
||||||
|
document.getElementById('company-edit-color-text').addEventListener('input', function() {
|
||||||
|
if (/^#[0-9a-fA-F]{6}$/.test(this.value)) {
|
||||||
|
document.getElementById('company-edit-color').value = this.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logo-upload
|
||||||
|
document.getElementById('company-logo-upload').addEventListener('change', async function() {
|
||||||
|
if (!this.files[0] || !currentCompanyDetail) return;
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('logo', this.files[0]);
|
||||||
|
formData.append('company_id', currentCompanyDetail);
|
||||||
|
try {
|
||||||
|
const res = await fetch('api.php?action=company_logo_upload', { method: 'POST', body: formData, credentials: 'include' });
|
||||||
|
const data = await res.json();
|
||||||
|
if (!res.ok) throw new Error(data.error || 'Virhe');
|
||||||
|
// Päivitä preview
|
||||||
|
const preview = document.getElementById('company-logo-preview');
|
||||||
|
preview.src = data.logo_url + '&t=' + Date.now();
|
||||||
|
preview.style.display = '';
|
||||||
|
// Päivitä paikallinen data
|
||||||
|
const comp = companiesTabData.find(c => c.id === currentCompanyDetail);
|
||||||
|
if (comp) comp.logo_file = data.logo_file;
|
||||||
|
} catch (e) { alert(e.message); }
|
||||||
|
this.value = ''; // Reset file input
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('btn-save-company-settings').addEventListener('click', async () => {
|
||||||
const nimi = document.getElementById('company-edit-nimi').value.trim();
|
const nimi = document.getElementById('company-edit-nimi').value.trim();
|
||||||
if (!nimi) return;
|
if (!nimi) return;
|
||||||
|
const subtitle = document.getElementById('company-edit-subtitle').value.trim();
|
||||||
|
const primary_color = document.getElementById('company-edit-color').value;
|
||||||
|
const domainsText = document.getElementById('company-edit-domains').value;
|
||||||
|
const domains = domainsText.split('\n').map(d => d.trim()).filter(d => d);
|
||||||
try {
|
try {
|
||||||
await apiCall('company_update', 'POST', { id: currentCompanyDetail, nimi });
|
await apiCall('company_update', 'POST', { id: currentCompanyDetail, nimi, subtitle, primary_color, domains });
|
||||||
alert('Nimi tallennettu!');
|
alert('Asetukset tallennettu!');
|
||||||
// Päivitä paikalliset tiedot
|
// Päivitä paikalliset tiedot
|
||||||
const comp = companiesTabData.find(c => c.id === currentCompanyDetail);
|
const comp = companiesTabData.find(c => c.id === currentCompanyDetail);
|
||||||
if (comp) comp.nimi = nimi;
|
if (comp) { comp.nimi = nimi; comp.subtitle = subtitle; comp.primary_color = primary_color; comp.domains = domains; }
|
||||||
const avail = availableCompanies.find(c => c.id === currentCompanyDetail);
|
const avail = availableCompanies.find(c => c.id === currentCompanyDetail);
|
||||||
if (avail) avail.nimi = nimi;
|
if (avail) avail.nimi = nimi;
|
||||||
populateCompanySelector();
|
populateCompanySelector();
|
||||||
|
// Jos tämä on aktiivinen yritys → päivitä brändäys heti
|
||||||
|
if (currentCompany && currentCompany.id === currentCompanyDetail) {
|
||||||
|
applyBranding({
|
||||||
|
nimi, subtitle, primary_color,
|
||||||
|
logo_url: comp?.logo_file ? 'api.php?action=company_logo&company_id=' + encodeURIComponent(currentCompanyDetail) + '&t=' + Date.now() : ''
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1985,6 +2048,59 @@ async function toggleCompanyUser(userId, companyId, add) {
|
|||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== BRANDING ====================
|
||||||
|
|
||||||
|
function applyBranding(branding) {
|
||||||
|
const color = branding.primary_color || '#0f3460';
|
||||||
|
const nimi = branding.nimi || 'Noxus Intra';
|
||||||
|
const subtitle = branding.subtitle || '';
|
||||||
|
const logoUrl = branding.logo_url || '';
|
||||||
|
|
||||||
|
// CSS-muuttuja
|
||||||
|
document.documentElement.style.setProperty('--primary-color', color);
|
||||||
|
// Laske tumma variantti
|
||||||
|
document.documentElement.style.setProperty('--primary-dark', color);
|
||||||
|
|
||||||
|
// Login-sivu
|
||||||
|
const loginLogo = document.getElementById('login-logo');
|
||||||
|
const loginTitle = document.getElementById('login-title');
|
||||||
|
const loginSubtitle = document.getElementById('login-subtitle');
|
||||||
|
if (loginLogo) {
|
||||||
|
if (logoUrl) { loginLogo.src = logoUrl; loginLogo.style.display = ''; }
|
||||||
|
else { loginLogo.style.display = 'none'; }
|
||||||
|
}
|
||||||
|
if (loginTitle) loginTitle.textContent = nimi;
|
||||||
|
if (loginSubtitle) loginSubtitle.textContent = subtitle || 'Kirjaudu sisään';
|
||||||
|
// Muut login-boxien otsikot
|
||||||
|
document.querySelectorAll('.login-brand-title').forEach(el => el.textContent = nimi);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
const headerLogo = document.getElementById('header-logo');
|
||||||
|
const headerIcon = document.getElementById('header-brand-icon');
|
||||||
|
const headerTitle = document.getElementById('header-title');
|
||||||
|
const headerSubtitle = document.getElementById('header-subtitle');
|
||||||
|
if (headerLogo) {
|
||||||
|
if (logoUrl) { headerLogo.src = logoUrl; headerLogo.style.display = ''; if (headerIcon) headerIcon.style.display = 'none'; }
|
||||||
|
else { headerLogo.style.display = 'none'; if (headerIcon) headerIcon.style.display = ''; }
|
||||||
|
}
|
||||||
|
if (headerTitle) headerTitle.textContent = nimi;
|
||||||
|
if (headerSubtitle) headerSubtitle.textContent = subtitle || 'Hallintapaneeli';
|
||||||
|
|
||||||
|
// Sivun title
|
||||||
|
document.title = nimi;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadBranding() {
|
||||||
|
try {
|
||||||
|
const data = await apiCall('branding');
|
||||||
|
applyBranding(data);
|
||||||
|
} catch (e) {
|
||||||
|
// Oletusbrändäys
|
||||||
|
applyBranding({ nimi: 'Noxus Intra', primary_color: '#0f3460', subtitle: 'Hallintapaneeli', logo_url: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
|
loadBranding();
|
||||||
loadCaptcha();
|
loadCaptcha();
|
||||||
checkAuth();
|
checkAuth();
|
||||||
|
|||||||
79
style.css
79
style.css
@@ -1,3 +1,10 @@
|
|||||||
|
:root {
|
||||||
|
--primary-color: #0f3460;
|
||||||
|
--primary-dark: #16213e;
|
||||||
|
--primary-light: color-mix(in srgb, var(--primary-color) 10%, white);
|
||||||
|
--primary-hover: color-mix(in srgb, var(--primary-color) 85%, black);
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -17,7 +24,7 @@ body {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: linear-gradient(135deg, #0f3460, #16213e);
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-box {
|
.login-box {
|
||||||
@@ -34,7 +41,7 @@ body {
|
|||||||
.login-box h1 {
|
.login-box h1 {
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-box p {
|
.login-box p {
|
||||||
@@ -54,13 +61,13 @@ body {
|
|||||||
|
|
||||||
.login-box input:focus {
|
.login-box input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #0f3460;
|
border-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-box button {
|
.login-box button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background: #0f3460;
|
background: var(--primary-color);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -70,7 +77,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-box button:hover {
|
.login-box button:hover {
|
||||||
background: #16213e;
|
background: var(--primary-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
@@ -88,7 +95,7 @@ body {
|
|||||||
.forgot-link {
|
.forgot-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
@@ -110,7 +117,7 @@ body {
|
|||||||
.captcha-question {
|
.captcha-question {
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -127,7 +134,7 @@ body {
|
|||||||
|
|
||||||
/* Header */
|
/* Header */
|
||||||
header {
|
header {
|
||||||
background: linear-gradient(135deg, #0f3460, #16213e);
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 1rem 2rem;
|
padding: 1rem 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -221,7 +228,7 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-stats .stat-card.highlight {
|
.sidebar-stats .stat-card.highlight {
|
||||||
background: #0f3460;
|
background: var(--primary-color);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +260,7 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.stat-highlight {
|
.stat-highlight {
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-stats .stat-card.trivia .stat-value {
|
.sidebar-stats .stat-card.trivia .stat-value {
|
||||||
@@ -285,7 +292,7 @@ header {
|
|||||||
|
|
||||||
.speed-item.top {
|
.speed-item.top {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.speed-bar {
|
.speed-bar {
|
||||||
@@ -297,7 +304,7 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.speed-item.top .speed-bar {
|
.speed-item.top .speed-bar {
|
||||||
background: #0f3460;
|
background: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Toolbar */
|
/* Toolbar */
|
||||||
@@ -331,7 +338,7 @@ header {
|
|||||||
|
|
||||||
.search-bar input:focus {
|
.search-bar input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #0f3460;
|
border-color: var(--primary-color);
|
||||||
box-shadow: 0 0 0 3px rgba(15,52,96,0.1);
|
box-shadow: 0 0 0 3px rgba(15,52,96,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +357,7 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
thead th {
|
thead th {
|
||||||
background: #16213e;
|
background: var(--primary-dark);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 11px 14px;
|
padding: 11px 14px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -401,7 +408,7 @@ tbody td {
|
|||||||
|
|
||||||
.price-cell {
|
.price-cell {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions-cell {
|
.actions-cell {
|
||||||
@@ -460,7 +467,7 @@ tbody td {
|
|||||||
|
|
||||||
#total-billing {
|
#total-billing {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Footer */
|
/* Footer */
|
||||||
@@ -604,7 +611,7 @@ footer {
|
|||||||
|
|
||||||
.modal-header h2 {
|
.modal-header h2 {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-close {
|
.modal-close {
|
||||||
@@ -635,7 +642,7 @@ form {
|
|||||||
|
|
||||||
form h3 {
|
form h3 {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
margin: 1.25rem 0 0.75rem;
|
margin: 1.25rem 0 0.75rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
border-bottom: 2px solid #f0f2f5;
|
border-bottom: 2px solid #f0f2f5;
|
||||||
@@ -688,7 +695,7 @@ form h3:first-of-type {
|
|||||||
.form-group textarea:focus,
|
.form-group textarea:focus,
|
||||||
.form-group select:focus {
|
.form-group select:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #0f3460;
|
border-color: var(--primary-color);
|
||||||
box-shadow: 0 0 0 3px rgba(15,52,96,0.1);
|
box-shadow: 0 0 0 3px rgba(15,52,96,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,7 +711,7 @@ form h3:first-of-type {
|
|||||||
.checkbox-label input[type="checkbox"] {
|
.checkbox-label input[type="checkbox"] {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
accent-color: #0f3460;
|
accent-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-actions {
|
.form-actions {
|
||||||
@@ -744,7 +751,7 @@ form h3:first-of-type {
|
|||||||
.liittyma-row-title {
|
.liittyma-row-title {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detail view */
|
/* Detail view */
|
||||||
@@ -762,7 +769,7 @@ form h3:first-of-type {
|
|||||||
|
|
||||||
.detail-section h3 {
|
.detail-section h3 {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
border-bottom: 2px solid #f0f2f5;
|
border-bottom: 2px solid #f0f2f5;
|
||||||
@@ -794,7 +801,7 @@ form h3:first-of-type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.detail-value a {
|
.detail-value a {
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -820,7 +827,7 @@ span.empty {
|
|||||||
.liittyma-num {
|
.liittyma-num {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
margin-bottom: 0.4rem;
|
margin-bottom: 0.4rem;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
@@ -830,7 +837,7 @@ span.empty {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
border-top: 2px solid #e8ebf0;
|
border-top: 2px solid #e8ebf0;
|
||||||
@@ -869,7 +876,7 @@ span.empty {
|
|||||||
.file-name {
|
.file-name {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -995,12 +1002,12 @@ span.empty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tab:hover {
|
.tab:hover {
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.active {
|
.tab.active {
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
border-bottom-color: #0f3460;
|
border-bottom-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-content {
|
.tab-content {
|
||||||
@@ -1023,7 +1030,7 @@ span.empty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.role-admin {
|
.role-admin {
|
||||||
background: #0f3460;
|
background: var(--primary-color);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1257,7 +1264,7 @@ span.empty {
|
|||||||
|
|
||||||
.ticket-reply-form textarea:focus {
|
.ticket-reply-form textarea:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #0f3460;
|
border-color: var(--primary-color);
|
||||||
box-shadow: 0 0 0 3px rgba(15, 52, 96, 0.1);
|
box-shadow: 0 0 0 3px rgba(15, 52, 96, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1279,9 +1286,9 @@ span.empty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-reply-tab.active {
|
.btn-reply-tab.active {
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-color: #0f3460;
|
border-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ticket tags */
|
/* Ticket tags */
|
||||||
@@ -1339,7 +1346,7 @@ span.empty {
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #0f3460;
|
color: var(--primary-color);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.2s;
|
transition: border-color 0.2s;
|
||||||
@@ -1347,7 +1354,7 @@ span.empty {
|
|||||||
|
|
||||||
.company-selector:hover,
|
.company-selector:hover,
|
||||||
.company-selector:focus {
|
.company-selector:focus {
|
||||||
border-color: #0f3460;
|
border-color: var(--primary-color);
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1357,7 +1364,7 @@ span.empty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mailbox-item:hover {
|
.mailbox-item:hover {
|
||||||
border-color: #0f3460 !important;
|
border-color: var(--primary-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Company badge */
|
/* Company badge */
|
||||||
|
|||||||
Reference in New Issue
Block a user