mirror of
https://github.com/rajnandan1/kener.git
synced 2026-05-03 00:49:48 -05:00
feat: added analytics
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
||||
IsValidHTTPMethod,
|
||||
ValidateIpAddress
|
||||
} from "./src/lib/server/tool.js";
|
||||
import { API_TIMEOUT } from "./src/lib/server/constants.js";
|
||||
import { API_TIMEOUT, AnalyticsProviders } from "./src/lib/server/constants.js";
|
||||
|
||||
const configPathFolder = "./config";
|
||||
const databaseFolder = process.argv[2] || "./database";
|
||||
@@ -251,6 +251,22 @@ async function Build() {
|
||||
if (site.github.incidentSince === undefined || site.github.incidentSince === null) {
|
||||
site.github.incidentSince = 48;
|
||||
}
|
||||
if (!!site.analytics) {
|
||||
const providers = {};
|
||||
|
||||
for (let i = 0; i < site.analytics.length; i++) {
|
||||
const element = site.analytics[i];
|
||||
if (!!AnalyticsProviders[element.type]) {
|
||||
if (providers[element.type] === undefined) {
|
||||
providers[element.type] = {};
|
||||
providers[element.type].measurementIds = [];
|
||||
providers[element.type].script = AnalyticsProviders[element.type];
|
||||
}
|
||||
providers[element.type].measurementIds.push(element.id);
|
||||
}
|
||||
}
|
||||
site.analytics = providers;
|
||||
}
|
||||
if (!!!site.font || !!!site.font.cssSrc || !!!site.font.family) {
|
||||
site.font = {
|
||||
cssSrc: "https://fonts.googleapis.com/css2?family=Albert+Sans:ital,wght@0,100..900;1,100..900&display=swap",
|
||||
|
||||
@@ -41,4 +41,10 @@ i18n:
|
||||
zh-CN: "中文"
|
||||
ja: "日本語"
|
||||
vi: "Tiếng Việt"
|
||||
theme: dark
|
||||
pattern: "squares"
|
||||
font:
|
||||
cssSrc: "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap"
|
||||
family: "\"Lato\", sans-serif"
|
||||
analytics:
|
||||
- id: "G-Q3MLRXCBFT"
|
||||
type: "GA"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: Categorize Monitors Guide | Kener
|
||||
description: Categorize Monitors in Kener
|
||||
---
|
||||
|
||||
# Categorize Monitors
|
||||
|
||||
Let us add a category to our monitors.
|
||||
|
||||
## Sample monitors.yaml
|
||||
|
||||
```yaml
|
||||
- name: OkBookmarks
|
||||
description: A free bookmark manager that lets you save and search your bookmarks in the cloud.
|
||||
tag: "okbookmarks"
|
||||
image: "https://okbookmarks.com/assets/img/extension_icon128.png"
|
||||
api:
|
||||
method: GET
|
||||
url: https://okbookmarks.com
|
||||
- name: Earth
|
||||
description: Our blue planet
|
||||
tag: "earth"
|
||||
defaultStatus: "UP"
|
||||
image: "/earth.png"
|
||||
category: "Hello"
|
||||
- name: Frogment
|
||||
description: A free openAPI spec editor and linter that breaks down your spec into fragments to make editing easier and more intuitive. Visit https://www.frogment.com
|
||||
tag: "frogment"
|
||||
image: "/frogment.png"
|
||||
api:
|
||||
method: GET
|
||||
url: https://www.frogment.com
|
||||
```
|
||||
|
||||
## Sample site.yaml
|
||||
|
||||
```yaml
|
||||
#...
|
||||
categories:
|
||||
- name: Hello
|
||||
description: Say Hello to the world
|
||||
#...
|
||||
```
|
||||
|
||||
The above will have OkBookmarks and Frogment under home. Earth will be under Hello category.
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: Changelogs | Kener
|
||||
description: Changelogs for Kener
|
||||
---
|
||||
|
||||
# Changelogs
|
||||
|
||||
## v0.0.16
|
||||
|
||||
Here are the changes in this release
|
||||
|
||||
### Features
|
||||
|
||||
- Added support for `hideURLForGet` in monitors. Read more [here](/docs/monitors)
|
||||
- New SVG badges for LIVE status. Read more [here](/docs/status-badges#live)
|
||||
- `[Breaking Change]` Removed dependency on Environment variable `PUBLIC_KENER_FOLDER`. Read more [here](#migration)
|
||||
- Simplified build and deploy process
|
||||
- Added support for fonts. Read more [here](/docs/customize-site#font)
|
||||
- Added support for home page pattern. Read more [here](/docs/customize-site#pattern)
|
||||
- Added support for adding your analytics provider. Read more [here](/docs/site-analytics)
|
||||
- New Documentation Site
|
||||
- Redesigned the UI for better consistency
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Custom JS and CSS Guide | Kener
|
||||
description: Custom JS and CSS Guide for Kener
|
||||
---
|
||||
|
||||
Here is a guide to add custom JS and CSS to your Kener instance.
|
||||
|
||||
## Adding Custom JS
|
||||
|
||||
Add your custom JS to `static/` file. And in the `src/app.html` file, add the following line:
|
||||
|
||||
```html
|
||||
<script src="/your-custom-js-file.js"></script>
|
||||
```
|
||||
|
||||
## Adding Custom CSS
|
||||
|
||||
Add your custom CSS to `static/` file. And in the `src/app.html` file, add the following line:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="/your-custom-css-file.css" />
|
||||
```
|
||||
|
||||
Do not forget to add the base path if you are using a subpath. For example, if you are using a subpath `/kener`, then the path should be `/kener/your-custom-js-file.js`.
|
||||
+29
-1
@@ -1,6 +1,11 @@
|
||||
---
|
||||
title: Customize Site - Site.yaml - Kener
|
||||
description: Customize your Kener site using site.yaml
|
||||
---
|
||||
|
||||
# Customize Site
|
||||
|
||||
There is a folder called `src/lib/server/config`. Inside which there is a `site.yaml` file. You can modify this file to have your own branding and do few other things.
|
||||
There is a folder called `./config`. Inside which there is a `site.yaml` file. You can modify this file to have your own branding and do few other things.
|
||||
|
||||
## Sample site.yaml
|
||||
|
||||
@@ -46,6 +51,13 @@ pattern: "squares"
|
||||
font:
|
||||
cssSrc: "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap"
|
||||
family: '"Lato", sans-serif'
|
||||
analytics:
|
||||
- id: "G-QsFT"
|
||||
type: "GA"
|
||||
- id: "deasf0d350"
|
||||
type: "AMPLITUDE"
|
||||
- id: "FKOdsKener"
|
||||
type: "MIXPANEL"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -299,3 +311,19 @@ URL of the font css
|
||||
### family
|
||||
|
||||
Font family
|
||||
|
||||
---
|
||||
|
||||
## analytics
|
||||
|
||||
You can add analytics to your site. You can add multiple analytics. Supported analytics are `GA`, `AMPLITUDE`, `MIXPANEL`
|
||||
|
||||
```yaml
|
||||
analytics:
|
||||
- id: "G-QsFT"
|
||||
type: "GA"
|
||||
- id: "deasf0d350"
|
||||
type: "AMPLITUDE"
|
||||
- id: "FKOdsKener"
|
||||
type: "MIXPANEL"
|
||||
```
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: Embed Monitor | Kener
|
||||
description: Embed your monitor in your website
|
||||
---
|
||||
|
||||
# Embed Monitor
|
||||
|
||||
There are two ways to embed your monitor in your website
|
||||
|
||||
## Javascript
|
||||
|
||||
You can embed your monitor in your website using javascript. We recommend using this method as it takes care of the height of the embedded monitor.
|
||||
|
||||
```html
|
||||
<script
|
||||
async
|
||||
src="http://[hostname]/embed-[tag]/js?theme=light&monitor=http://[hostname]/embed-[tag]"
|
||||
></script>
|
||||
```
|
||||
|
||||
Here is an example
|
||||
|
||||
```html
|
||||
<script
|
||||
async
|
||||
src="https://kener.ing/embed-okbookmarks/js?theme=light&monitor=http://localhost:3000/embed-okbookmarks"
|
||||
></script>
|
||||
```
|
||||
|
||||
Replace `[hostname]` with your kener hostname and `[tag]` with your monitor tag.
|
||||
|
||||
## Iframe
|
||||
|
||||
This is the simplest way to embed your monitor in your website. You can use the following code to embed your monitor in your website.
|
||||
|
||||
```html
|
||||
<iframe
|
||||
src="http://[hostname]/embed-[tag]?theme=light"
|
||||
width="100%"
|
||||
height="200"
|
||||
allowfullscreen="allowfullscreen"
|
||||
allowpaymentrequest
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
```
|
||||
|
||||
Here is an example
|
||||
|
||||
```html
|
||||
<iframe
|
||||
src="http://localhost:3000/embed-okbookmarks?theme=light"
|
||||
width="100%"
|
||||
height="200"
|
||||
allowfullscreen="allowfullscreen"
|
||||
allowpaymentrequest
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
```
|
||||
|
||||
Replace `[hostname]` with your kener hostname and `[tag]` with your monitor tag.
|
||||
|
||||
## Parameters
|
||||
|
||||
You can pass the following parameters to the embed code
|
||||
|
||||
- `theme`: You can pass `light` or `dark` theme
|
||||
- `monitor`: The monitor url
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Environment Variables | Kener
|
||||
description: Kener needs some environment variables to be set to run properly. Here are the list of environment variables that you need to set.
|
||||
---
|
||||
|
||||
# Environment Variables
|
||||
|
||||
Kener needs some environment variables to be set to run properly. Here are the list of environment variables that you need to set.
|
||||
|
||||
+6
-2
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Github Setup | Kener
|
||||
description: Kener uses github for incident management. Issues created in github using certain tags go to kener as incidents.
|
||||
---
|
||||
|
||||
# Github Setup
|
||||
|
||||
Kener uses github for incident management. Issues created in github using certain tags go to kener as incidents.
|
||||
@@ -36,7 +41,6 @@ You can create either a classic token or personal access token
|
||||
|
||||
## Step 3: Set environment
|
||||
|
||||
|
||||
```shell
|
||||
export GH_TOKEN=github_pat_11AD3ZA3Y0
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Kener - A Sveltekit NodeJS Status Page System
|
||||
description: Kener is an open-source Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents.
|
||||
---
|
||||
|
||||
# Kener - A Sveltekit NodeJS Status Page System
|
||||
|
||||
<p align="center">
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: How it works | Kener
|
||||
description: Folder structure and how Kener works
|
||||
---
|
||||
|
||||
# How it works
|
||||
|
||||
Kener has two parts.
|
||||
@@ -27,3 +32,7 @@ This is the configuration file for your site. This is where you define the name
|
||||
## Monitors.yaml
|
||||
|
||||
This is the configuration file for your monitors. This is where you define the monitors you want to show on your site. Read more about it [here](/docs/monitors)
|
||||
|
||||
## Data
|
||||
|
||||
Kener stores its data in a folder which is `./database`. This is where all the data is stored. You can delete this folder if you want to start fresh.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: i18n | Kener
|
||||
description: Kener supports multiple languages. You can add translations to your site.
|
||||
---
|
||||
|
||||
# i18n
|
||||
|
||||
You can add translations to your site. By default it is set to `en`. Available translations are present in `/src/lib/locales/` folders in the root directory. You can add more translations by adding a new file in the `/src/lib/locales` folder.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Incident Management | Kener
|
||||
description: Kener uses Github to power incident management using labels
|
||||
---
|
||||
|
||||
# Incident Management
|
||||
|
||||
Kener uses Github to power incident management using labels
|
||||
@@ -22,4 +27,4 @@ Kener auto creates labels for your monitors using the `tag` parameter
|
||||
|
||||
If you clone the repo it gives you an issue template to create incidents
|
||||
|
||||
Here is a [sample incident](https://github.com/rajnandan1/kener/issues/15) for your reference.
|
||||
Here is a [sample incident](https://github.com/rajnandan1/kener/issues/15) for your reference.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Kener APIs
|
||||
description: Kener gives APIs to push data and create incident.
|
||||
---
|
||||
|
||||
# Kener APIs
|
||||
|
||||
Kener also gives APIs to push data and create incident. Before you use kener apis you will have to set an authorization token called `API_TOKEN`. This also has to be set as an environment variable.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Monitor Examples | Kener
|
||||
description: Here are some exhaustive examples for monitors
|
||||
---
|
||||
|
||||
# Monitor Examples
|
||||
|
||||
Here are some exhaustive examples for monitors
|
||||
|
||||
+6
-1
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Monitors | monitors.yaml | Kener
|
||||
description: Monitors are the heart of Kener. This is where you define the monitors you want to show on your site.
|
||||
---
|
||||
|
||||
# Monitors
|
||||
|
||||
Inside `config/` folder there is a file called `monitors.yaml`. We will be adding our monitors here. Please note that your yaml must be valid. It is an array.
|
||||
@@ -53,7 +58,7 @@ Sample
|
||||
| api.eval | Optional | Evaluator written in JS, to parse HTTP response and calculate uptime and latency |
|
||||
| defaultStatus | Optional | If no API is given this will be the default status. can be UP/DOWN/DEGRADED |
|
||||
| hidden | Optional | If set to `true` will not show the monitor in the UI |
|
||||
| category | Optional | Use this to group your monitors. Make sure you have defined category in `site.yaml` and use the `name` attribute here |
|
||||
| category | Optional | Use this to group your monitors. Make sure you have defined category in `site.yaml` and use the `name` attribute. More about it [here](/docs/customize-site#categories). |
|
||||
| dayDegradedMinimumCount | Optional | Default is 1. It means minimum this number of count for the day to be classified as DEGRADED(Yellow Bar) in 90 day view. Has to be `number` greater than 0 |
|
||||
| dayDownMinimumCount | Optional | Default is 1. It means minimum this number of count for the day to be classified as DOWN(Red Bar) in 90 day view. Has to be `number` greater than 0 |
|
||||
| includeDegradedInDowntime | Optional | By deafault uptime percentage is calculated as (UP+DEGRADED/UP+DEGRADED+DOWN). Setting it as `true` will change the calculation to (UP/UP+DEGRADED+DOWN) |
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Quick Start | Kener
|
||||
description: Get started with Kener
|
||||
---
|
||||
|
||||
# Quick Start
|
||||
|
||||
Please make sure you have [Node](https://nodejs.org/en) installed in your system. Minimum version required is `v16.17.0`.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Site Analytics | Kener
|
||||
description: Add Google Analytics, Amplitude, Mixpanel etc to your Kener site
|
||||
---
|
||||
|
||||
# Site Analytics
|
||||
|
||||
You can add Google Analytics, Amplitude, Mixpanel etc to your Kener site. In order to do this, you need to add the following configuration to your `site.yaml` file.
|
||||
|
||||
```yaml
|
||||
analytics:
|
||||
- id: "G-QsFT"
|
||||
type: "GA"
|
||||
- id: "deasf0d350"
|
||||
type: "AMPLITUDE"
|
||||
- id: "FKOdsKener"
|
||||
type: "MIXPANEL"
|
||||
```
|
||||
|
||||
## Google Analytics
|
||||
|
||||
To add Google Analytics to your site, you need to add the following configuration to your `site.yaml` file.
|
||||
|
||||
```yaml
|
||||
analytics:
|
||||
- id: "G-QsFT"
|
||||
type: "GA"
|
||||
```
|
||||
|
||||
`id` is the tracking ID of your Google Analytics account. You can find this in your Google Analytics account.
|
||||
|
||||
## Amplitude
|
||||
|
||||
To add Amplitude to your site, you need to add the following configuration to your `site.yaml` file.
|
||||
|
||||
```yaml
|
||||
analytics:
|
||||
- id: "deasf0d350"
|
||||
type: "AMPLITUDE"
|
||||
```
|
||||
|
||||
`id` is the API key of your Amplitude account. You can find this in your Amplitude account.
|
||||
|
||||
## Mixpanel
|
||||
|
||||
To add Mixpanel to your site, you need to add the following configuration to your `site.yaml` file.
|
||||
|
||||
```yaml
|
||||
analytics:
|
||||
- id: "FKOdsKener"
|
||||
type: "MIXPANEL"
|
||||
```
|
||||
|
||||
`id` is the token of your Mixpanel account. You can find this in your Mixpanel account.
|
||||
+18
-7
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Status Badges | Kener
|
||||
description: Status badges for your monitors
|
||||
---
|
||||
|
||||
# Status Badges
|
||||
|
||||
There are three types of badges
|
||||
@@ -14,8 +19,6 @@ http://[hostname]/badge/[tag]/uptime
|
||||
|
||||
## Status
|
||||
|
||||
### Badge SVG
|
||||
|
||||
Shows the last health check was UP/DOWN/DEGRADED
|
||||
|
||||

|
||||
@@ -32,21 +35,29 @@ Example in MarkDown
|
||||

|
||||
```
|
||||
|
||||
### Icon SVG
|
||||
---
|
||||
|
||||
## Live
|
||||
|
||||
Shows the last health check was UP/DOWN/DEGRADED as SVG dot
|
||||
|
||||
#### Standard
|
||||
```shell
|
||||
http://[hostname]/badge/[tag]/dot
|
||||
#or
|
||||
http://[hostname]/badge/[tag]/dot?animate=ping
|
||||
```
|
||||
|
||||

|
||||
### Standard
|
||||
|
||||

|
||||
|
||||
```html
|
||||
<img src="https://kener.ing/badge/earth/dot" />
|
||||
```
|
||||
|
||||
#### Animated
|
||||
### Animated
|
||||
|
||||

|
||||

|
||||
|
||||
```html
|
||||
<img src="https://kener.ing/badge/earth/dot?animate=ping" />
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
"title": "How it works",
|
||||
"link": "/docs/how-it-works",
|
||||
"file": "/how-it-works.md"
|
||||
},
|
||||
{
|
||||
"title": "Changelogs",
|
||||
"link": "/docs/changelogs",
|
||||
"file": "/changelogs.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -52,6 +57,16 @@
|
||||
"title": "Badges",
|
||||
"link": "/docs/status-badges",
|
||||
"file": "/status-badges.md"
|
||||
},
|
||||
{
|
||||
"title": "Embed",
|
||||
"link": "/docs/embed",
|
||||
"file": "/embed.md"
|
||||
},
|
||||
{
|
||||
"title": "Analytics",
|
||||
"link": "/docs/site-analytics",
|
||||
"file": "/site-analytics.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -84,6 +99,21 @@
|
||||
"file": "/kener-apis.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionTitle": "Guides",
|
||||
"children": [
|
||||
{
|
||||
"title": "Categorize Monitors",
|
||||
"link": "/docs/categorize-guide",
|
||||
"file": "/categorize-guide.md"
|
||||
},
|
||||
{
|
||||
"title": "Custom JS/CSS",
|
||||
"link": "/docs/custom-js-css-guide",
|
||||
"file": "/custom-js-css-guide.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Generated
+141
-2351
File diff suppressed because it is too large
Load Diff
+4
-8
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "kener",
|
||||
"version": "0.0.15",
|
||||
"version": "0.0.16",
|
||||
"private": false,
|
||||
"license": "MIT",
|
||||
"description": "Kener: An open-source Node.js status page application for real-time service monitoring, incident management, and customizable reporting. Simplify service outage tracking, enhance incident communication, and ensure a seamless user experience.",
|
||||
@@ -58,7 +58,7 @@
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@types/prismjs": "^1.26.5",
|
||||
"analytics": "^0.8.14",
|
||||
"axios": "^1.6.2",
|
||||
"badge-maker": "^3.3.1",
|
||||
"bits-ui": "^0.9.9",
|
||||
@@ -79,12 +79,8 @@
|
||||
"prismjs": "^1.29.0",
|
||||
"queue": "^7.0.0",
|
||||
"randomstring": "^1.3.0",
|
||||
"remark": "^15.0.1",
|
||||
"remark-html": "^16.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-prism": "^1.3.6",
|
||||
"svelte-legos": "^0.2.5",
|
||||
"tailwind-merge": "^2.0.0",
|
||||
"tailwind-variants": "^0.1.18",
|
||||
"vite-node": "^2.1.4"
|
||||
"tailwind-variants": "^0.1.18"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,17 +10,5 @@
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Q3MLRXCBFT"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag("js", new Date());
|
||||
|
||||
gtag("config", "G-Q3MLRXCBFT");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-1
@@ -1,3 +1,8 @@
|
||||
code:not([class^="language-"]) {
|
||||
@apply rounded bg-gray-100 px-1.5 py-0.5 font-mono text-sm text-xs dark:bg-gray-800;
|
||||
@apply rounded bg-gray-100 px-1.5 py-0.5 font-mono text-xs dark:bg-gray-800;
|
||||
}
|
||||
|
||||
.sidebar-item.active,
|
||||
.sidebar-item:hover {
|
||||
color: #ed702d;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// @ts-ignore
|
||||
export const analyticsEvent = (event, data) => {
|
||||
// Do something with the event and data
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("analyticsEvent", {
|
||||
bubbles: true,
|
||||
detail: {
|
||||
event,
|
||||
data
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -22,6 +22,8 @@
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import axios from "axios";
|
||||
import { l, summaryTime, n, ampm } from "$lib/i18n/client";
|
||||
import { analyticsEvent } from "$lib/analytics";
|
||||
import { hoverAction } from "svelte-legos";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
/**
|
||||
@@ -54,6 +56,9 @@
|
||||
|
||||
let pathMonitorLink;
|
||||
function copyLinkToClipboard() {
|
||||
analyticsEvent("monitor_link_copied", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
navigator.clipboard.writeText(pathMonitorLink);
|
||||
copiedLink = true;
|
||||
setTimeout(function () {
|
||||
@@ -63,6 +68,9 @@
|
||||
|
||||
let pathMonitorBadgeUptime;
|
||||
function copyUptimeBadge() {
|
||||
analyticsEvent("monitor_uptime_badge_copied", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
navigator.clipboard.writeText(pathMonitorBadgeUptime);
|
||||
copiedBadgeUptime = true;
|
||||
setTimeout(function () {
|
||||
@@ -72,6 +80,9 @@
|
||||
|
||||
let pathMonitorBadgeStatus;
|
||||
function copyStatusBadge() {
|
||||
analyticsEvent("monitor_status_badge_copied", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
navigator.clipboard.writeText(pathMonitorBadgeStatus);
|
||||
copiedBadgeStatus = true;
|
||||
setTimeout(function () {
|
||||
@@ -81,6 +92,10 @@
|
||||
|
||||
let pathMonitorBadgeDot;
|
||||
function copyDotStandard() {
|
||||
analyticsEvent("monitor_svg_standard_copied", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
|
||||
navigator.clipboard.writeText(pathMonitorBadgeDot);
|
||||
copiedBadgeDotStandard = true;
|
||||
setTimeout(function () {
|
||||
@@ -90,6 +105,9 @@
|
||||
|
||||
let pathMonitorBadgeDotPing;
|
||||
function copyDotPing() {
|
||||
analyticsEvent("monitor_svg_pinging_copied", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
navigator.clipboard.writeText(pathMonitorBadgeDotPing);
|
||||
copiedBadgeDotPing = true;
|
||||
setTimeout(function () {
|
||||
@@ -100,6 +118,11 @@
|
||||
function copyScriptTagToClipboard() {
|
||||
//get domain with port number
|
||||
|
||||
analyticsEvent("monitor_embed_copied", {
|
||||
tag: monitor.tag,
|
||||
type: embedType
|
||||
});
|
||||
|
||||
let path = `${base}/embed-${monitor.tag}`;
|
||||
let scriptTag =
|
||||
`<script async src="${protocol + "//" + domain + path}/js?theme=${theme}&monitor=${protocol + "//" + domain + path}"><` +
|
||||
@@ -145,9 +168,15 @@
|
||||
function switchView(s) {
|
||||
view = s;
|
||||
if (Object.keys(_0Day).length == 0) {
|
||||
analyticsEvent("monitor_view_today", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
getToday();
|
||||
}
|
||||
if (view == "90day") {
|
||||
analyticsEvent("monitor_view_90day", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
scrollToRight();
|
||||
}
|
||||
}
|
||||
@@ -166,6 +195,13 @@
|
||||
afterUpdate(() => {
|
||||
dispatch("heightChange", {});
|
||||
});
|
||||
function show90Inline(e, bar) {
|
||||
if (e.detail.hover) {
|
||||
_90Day[bar.timestamp].showDetails = true;
|
||||
} else {
|
||||
_90Day[bar.timestamp].showDetails = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="monitor relative grid w-full grid-cols-12 gap-2 pb-2 md:w-[655px]">
|
||||
@@ -192,7 +228,15 @@
|
||||
|
||||
<Popover.Root>
|
||||
<Popover.Trigger class="absolute right-14 top-5 h-5 w-5 p-0">
|
||||
<Button class="h-5 p-0" variant="link">
|
||||
<Button
|
||||
class="h-5 p-0"
|
||||
variant="link"
|
||||
on:click={(e) => {
|
||||
analyticsEvent("monitor_share_menu_open", {
|
||||
tag: monitor.tag
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Share2 class="h-4 w-4 text-muted-foreground" />
|
||||
</Button>
|
||||
</Popover.Trigger>
|
||||
@@ -205,7 +249,7 @@
|
||||
{l(lang, "monitor.share_desc")}
|
||||
</p>
|
||||
<Button
|
||||
class="h-8 text-xs"
|
||||
class="h-8 pr-4 text-xs"
|
||||
variant="secondary"
|
||||
on:click={copyLinkToClipboard}
|
||||
>
|
||||
@@ -273,7 +317,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
class="h-8 px-2 text-xs"
|
||||
class="h-8 px-2 pr-4 text-xs"
|
||||
variant="secondary"
|
||||
on:click={copyScriptTagToClipboard}
|
||||
>
|
||||
@@ -300,7 +344,7 @@
|
||||
{l(lang, "monitor.badge_desc")}
|
||||
</p>
|
||||
<Button
|
||||
class="h-8 px-2 text-xs"
|
||||
class="h-8 px-2 pr-4 text-xs"
|
||||
variant="secondary"
|
||||
on:click={copyStatusBadge}
|
||||
>
|
||||
@@ -319,7 +363,7 @@
|
||||
{/if}
|
||||
</Button>
|
||||
<Button
|
||||
class="h-8 px-2 text-xs"
|
||||
class="h-8 px-2 pr-4 text-xs"
|
||||
variant="secondary"
|
||||
on:click={copyUptimeBadge}
|
||||
>
|
||||
@@ -349,7 +393,7 @@
|
||||
{l(lang, "monitor.status_svg_desc")}
|
||||
</p>
|
||||
<Button
|
||||
class="h-8 px-2 text-xs"
|
||||
class="h-8 px-2 pr-4 text-xs"
|
||||
variant="secondary"
|
||||
on:click={copyDotStandard}
|
||||
>
|
||||
@@ -370,7 +414,7 @@
|
||||
{/if}
|
||||
</Button>
|
||||
<Button
|
||||
class="h-8 px-2 text-xs"
|
||||
class="h-8 px-2 pr-4 text-xs"
|
||||
variant="secondary"
|
||||
on:click={copyDotPing}
|
||||
>
|
||||
@@ -449,17 +493,28 @@
|
||||
<div class="chart-status relative col-span-12 mt-1">
|
||||
<div class="daygrid90 flex overflow-x-auto overflow-y-hidden py-1">
|
||||
{#each Object.entries(_90Day) as [ts, bar]}
|
||||
<div class="oneline h-[30px] w-[6px] rounded-sm">
|
||||
<div
|
||||
use:hoverAction
|
||||
on:hover={(e) => {
|
||||
show90Inline(e, bar);
|
||||
}}
|
||||
class="oneline h-[30px] w-[6px] rounded-sm"
|
||||
>
|
||||
<div
|
||||
class="h-[30px] bg-{bar.cssClass} mr-[2px] w-[4px] rounded-sm"
|
||||
></div>
|
||||
</div>
|
||||
<div class="show-hover absolute bg-background text-sm">
|
||||
<div class="text-{bar.cssClass} pt-1 text-xs font-semibold">
|
||||
● {n(lang, new Date(bar.timestamp * 1000).toLocaleDateString())}
|
||||
{summaryTime(lang, bar.message)}
|
||||
{#if bar.showDetails}
|
||||
<div class="show-hover absolute bg-background text-sm">
|
||||
<div class="text-{bar.cssClass} pt-1 text-xs font-semibold">
|
||||
{n(
|
||||
lang,
|
||||
new Date(bar.timestamp * 1000).toLocaleDateString()
|
||||
)}
|
||||
{summaryTime(lang, bar.message)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -477,7 +532,7 @@
|
||||
<div class="hiddenx relative">
|
||||
<div
|
||||
data-index={ts.index}
|
||||
class="message rounded border bg-black p-2 text-sm font-semibold text-white"
|
||||
class="message rounded border bg-black p-2 text-xs font-semibold text-white"
|
||||
>
|
||||
<p>
|
||||
<span class="text-{bar.cssClass}"> ● </span>
|
||||
@@ -490,11 +545,11 @@
|
||||
)}
|
||||
</p>
|
||||
{#if bar.status != "NO_DATA"}
|
||||
<p class="pl-4">
|
||||
<p class="pl-2">
|
||||
{l(lang, "statuses." + bar.status)}
|
||||
</p>
|
||||
{:else}
|
||||
<p class="pl-4">-</p>
|
||||
<p class="pl-2">-</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -530,12 +585,7 @@
|
||||
transform: scaleY(1.2);
|
||||
}
|
||||
|
||||
.oneline:hover + .show-hover {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.show-hover {
|
||||
display: none;
|
||||
top: 40px;
|
||||
padding: 0px;
|
||||
text-align: left;
|
||||
|
||||
@@ -54,8 +54,8 @@
|
||||
"pm": "pm",
|
||||
"standard": "Standard",
|
||||
"pinging": "Pinging",
|
||||
"status_svg": "Status SVG",
|
||||
"status_svg_desc": "Get a SVG dot for this monitor"
|
||||
"status_svg": "Live Status",
|
||||
"status_svg_desc": "Get a LIVE Status for this monitor"
|
||||
},
|
||||
"numbers": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
|
||||
}
|
||||
|
||||
@@ -9,5 +9,10 @@ const UP = "UP";
|
||||
const DOWN = "DOWN";
|
||||
const DEGRADED = "DEGRADED";
|
||||
const API_TIMEOUT = 10 * 1000; // 10 seconds
|
||||
const AnalyticsProviders = {
|
||||
GA: "https://unpkg.com/@analytics/google-analytics@1.0.7/dist/@analytics/google-analytics.min.js",
|
||||
AMPLITUDE: "https://unpkg.com/@analytics/amplitude@0.1.3/dist/@analytics/amplitude.min.js",
|
||||
MIXPANEL: "https://unpkg.com/@analytics/mixpanel@0.4.0/dist/@analytics/mixpanel.min.js"
|
||||
};
|
||||
// Export the constants
|
||||
export { MONITOR, UP, DOWN, SITE, DEGRADED, API_TIMEOUT, ENV };
|
||||
export { MONITOR, UP, DOWN, SITE, DEGRADED, API_TIMEOUT, ENV, AnalyticsProviders };
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
None
|
||||
@@ -1,94 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "Google Search",
|
||||
"description": "Search the world's <span class=\"text-red-500\">information</span>, including webpages, images, videos and more.",
|
||||
"tag": "google-search",
|
||||
"image": "/google.png",
|
||||
"api": {
|
||||
"method": "GET",
|
||||
"url": "https://www.google.com/webhp",
|
||||
"hideURLForGet": true,
|
||||
"eval": "(function (statusCode, responseTime, responseData) {\n\tlet statusCodeShort = Math.floor(statusCode/100);\n if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) {\n return {\n\t\t\tstatus: 'UP',\n\t\t\tlatency: responseTime,\n }\n } \n\treturn {\n\t\tstatus: 'DOWN',\n\t\tlatency: responseTime,\n\t}\n})",
|
||||
"timeout": 10000
|
||||
},
|
||||
"folderName": "google-search",
|
||||
"dayDegradedMinimumCount": 1,
|
||||
"dayDownMinimumCount": 1,
|
||||
"includeDegradedInDowntime": false,
|
||||
"path0Day": "/Users/rajnandan1/Code/kener/db/google-search.0day.utc.json",
|
||||
"path90Day": "/Users/rajnandan1/Code/kener/db/google-search.90day.utc.json",
|
||||
"hasAPI": true
|
||||
},
|
||||
{
|
||||
"name": "Svelte Website",
|
||||
"description": "Cybernetically enhanced web apps <a href=\"https://svelte.dev/\" class=\"font-medium underline underline-offset-4\" target=\"_blank\">https://svelte.dev/</a>",
|
||||
"tag": "svelte-website",
|
||||
"api": {
|
||||
"method": "GET",
|
||||
"url": "https://svelte.dev/",
|
||||
"eval": "(function (statusCode, responseTime, responseData) {\n\tlet statusCodeShort = Math.floor(statusCode/100);\n if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) {\n return {\n\t\t\tstatus: 'UP',\n\t\t\tlatency: responseTime,\n }\n } \n\treturn {\n\t\tstatus: 'DOWN',\n\t\tlatency: responseTime,\n\t}\n})",
|
||||
"timeout": 10000
|
||||
},
|
||||
"image": "/svelte.svg",
|
||||
"folderName": "svelte-website",
|
||||
"dayDegradedMinimumCount": 1,
|
||||
"dayDownMinimumCount": 1,
|
||||
"includeDegradedInDowntime": false,
|
||||
"path0Day": "/Users/rajnandan1/Code/kener/db/svelte-website.0day.utc.json",
|
||||
"path90Day": "/Users/rajnandan1/Code/kener/db/svelte-website.90day.utc.json",
|
||||
"hasAPI": true
|
||||
},
|
||||
{
|
||||
"name": "Earth",
|
||||
"description": "Our blue planet",
|
||||
"tag": "earth",
|
||||
"defaultStatus": "UP",
|
||||
"image": "/earth.png",
|
||||
"cron": "*/2 * * * *",
|
||||
"folderName": "earth",
|
||||
"dayDegradedMinimumCount": 1,
|
||||
"dayDownMinimumCount": 1,
|
||||
"includeDegradedInDowntime": false,
|
||||
"path0Day": "/Users/rajnandan1/Code/kener/db/earth.0day.utc.json",
|
||||
"path90Day": "/Users/rajnandan1/Code/kener/db/earth.90day.utc.json",
|
||||
"hasAPI": false
|
||||
},
|
||||
{
|
||||
"name": "Frogment",
|
||||
"description": "A free openAPI spec editor and linter that breaks down your spec into fragments to make editing easier and more intuitive. Visit https://www.frogment.com <a href=\"https://www.frogment.com\" class=\"font-medium underline underline-offset-4\" target=\"_blank\">https://www.frogment.com</a>",
|
||||
"tag": "frogment",
|
||||
"image": "/frogment.png",
|
||||
"api": {
|
||||
"method": "GET",
|
||||
"url": "https://www.frogment.com",
|
||||
"eval": "(function (statusCode, responseTime, responseData) {\n\tlet statusCodeShort = Math.floor(statusCode/100);\n if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) {\n return {\n\t\t\tstatus: 'UP',\n\t\t\tlatency: responseTime,\n }\n } \n\treturn {\n\t\tstatus: 'DOWN',\n\t\tlatency: responseTime,\n\t}\n})",
|
||||
"timeout": 10000
|
||||
},
|
||||
"folderName": "frogment",
|
||||
"dayDegradedMinimumCount": 1,
|
||||
"dayDownMinimumCount": 1,
|
||||
"includeDegradedInDowntime": false,
|
||||
"path0Day": "/Users/rajnandan1/Code/kener/db/frogment.0day.utc.json",
|
||||
"path90Day": "/Users/rajnandan1/Code/kener/db/frogment.90day.utc.json",
|
||||
"hasAPI": true
|
||||
},
|
||||
{
|
||||
"name": "OkBookmarks",
|
||||
"description": "Stop forgetting about your bookmarks <a href=\"https://okbookmarks.com/\" class=\"font-medium underline underline-offset-4\" target=\"_blank\">https://okbookmarks.com/</a>",
|
||||
"tag": "okbookmarks",
|
||||
"image": "https://okbookmarks.com/app/mybookmark.png",
|
||||
"api": {
|
||||
"method": "GET",
|
||||
"url": "https://okbookmarks.com/",
|
||||
"eval": "(function (statusCode, responseTime, responseData) {\n\tlet statusCodeShort = Math.floor(statusCode/100);\n if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) {\n return {\n\t\t\tstatus: 'UP',\n\t\t\tlatency: responseTime,\n }\n } \n\treturn {\n\t\tstatus: 'DOWN',\n\t\tlatency: responseTime,\n\t}\n})",
|
||||
"timeout": 10000
|
||||
},
|
||||
"folderName": "okbookmarks",
|
||||
"dayDegradedMinimumCount": 1,
|
||||
"dayDownMinimumCount": 1,
|
||||
"includeDegradedInDowntime": false,
|
||||
"path0Day": "/Users/rajnandan1/Code/kener/db/okbookmarks.0day.utc.json",
|
||||
"path90Day": "/Users/rajnandan1/Code/kener/db/okbookmarks.90day.utc.json",
|
||||
"hasAPI": true
|
||||
}
|
||||
]
|
||||
@@ -1,64 +0,0 @@
|
||||
{
|
||||
"title": "Kener - Open-Source and Modern looking Node.js Status Page for Effortless Incident Management",
|
||||
"siteName": "Kener.ing",
|
||||
"home": "/",
|
||||
"logo": "/logo.png",
|
||||
"favicon": "/logo96.png",
|
||||
"github": {
|
||||
"owner": "rajnandan1",
|
||||
"repo": "kener",
|
||||
"incidentSince": 48
|
||||
},
|
||||
"metaTags": {
|
||||
"description": "Kener: Open-source modern looking Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. And the best part? Kener integrates seamlessly with GitHub, making incident management a team effort—making it easier for us to track and fix issues together in a collaborative and friendly environment.",
|
||||
"keywords": "Node.js status page, Incident management tool, Service monitoring, Service outage tracking, Real-time status updates, GitHub integration for incidents, Open-source status page, Node.js monitoring application, Service reliability, User-friendly incident management, Collaborative incident resolution, Seamless outage communication, Service disruption tracker, Real-time incident alerts, Node.js status reporting",
|
||||
"og:description": "Kener: Open-source Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. And the best part? Kener integrates seamlessly with GitHub, making incident management a team effort—making it easier for us to track and fix issues together in a collaborative and friendly environment.",
|
||||
"og:image": "https://kener.ing/ss.png",
|
||||
"og:title": "Kener - Open-Source and Modern looking Node.js Status Page for Effortless Incident Management",
|
||||
"og:type": "website",
|
||||
"og:site_name": "Kener",
|
||||
"twitter:card": "summary_large_image",
|
||||
"twitter:site": "@_rajnandan_",
|
||||
"twitter:creator": "@_rajnandan_",
|
||||
"twitter:image": "https://kener.ing/ss.png",
|
||||
"twitter:title": "Kener: Open-Source and Modern looking Node.js Status Page for Effortless Incident Management",
|
||||
"twitter:description": "Kener: Open-source Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. And the best part? Kener integrates seamlessly with GitHub, making incident management a team effort—making it easier for us to track and fix issues together in a collaborative and friendly environment."
|
||||
},
|
||||
"nav": [
|
||||
{
|
||||
"name": "Documentation",
|
||||
"url": "/docs/home"
|
||||
},
|
||||
{
|
||||
"name": "Github",
|
||||
"iconURL": "/github.svg",
|
||||
"url": "https://github.com/rajnandan1/kener"
|
||||
},
|
||||
{
|
||||
"name": "Buy me a coffee",
|
||||
"iconURL": "/buymeacoffee.svg",
|
||||
"url": "https://buymeacoffee.com/rajnandan1"
|
||||
}
|
||||
],
|
||||
"hero": {
|
||||
"title": "Kener is a Modern Open-Source Status Page System",
|
||||
"subtitle": "Let your users know what's going on."
|
||||
},
|
||||
"footerHTML": "Made using \n<a href=\"https://github.com/rajnandan1/kener\" target=\"_blank\" rel=\"noreferrer\" class=\"font-medium underline underline-offset-4\">\n Kener\n</a>\nan open source status page system built with Svelte and TailwindCSS.\n",
|
||||
"i18n": {
|
||||
"defaultLocale": "en",
|
||||
"locales": {
|
||||
"en": "English",
|
||||
"hi": "हिन्दी",
|
||||
"zh-CN": "中文",
|
||||
"ja": "日本語",
|
||||
"vi": "Tiếng Việt"
|
||||
}
|
||||
},
|
||||
"theme": "dark",
|
||||
"pattern": "squares",
|
||||
"font": {
|
||||
"cssSrc": "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap",
|
||||
"family": "\"Lato\", sans-serif"
|
||||
}
|
||||
}
|
||||
@@ -68,9 +68,20 @@
|
||||
<svelte:window on:pagechange={pageChange} on:rightbar={updateTableOfContents} />
|
||||
<svelte:head>
|
||||
<link rel="icon" id="kener-app-favicon" href="{base}/logo96.png" />
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Q3MLRXCBFT"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag("js", new Date());
|
||||
|
||||
gtag("config", "G-Q3MLRXCBFT");
|
||||
</script>
|
||||
</svelte:head>
|
||||
<div class="squares-pattern"></div>
|
||||
<nav class="fixed left-0 right-0 top-0 z-30 h-16 border-b bg-background">
|
||||
<div class="squares-pattern z-0"></div>
|
||||
<nav class="z-2 fixed left-0 right-0 top-0 z-30 h-16 bg-background shadow-sm">
|
||||
<div class="mx-auto h-full px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-full items-center justify-between">
|
||||
<!-- Logo/Brand -->
|
||||
@@ -78,7 +89,7 @@
|
||||
<a href="/" class="flex items-center space-x-3">
|
||||
<!-- Document Icon - Replace with your own logo -->
|
||||
<img src="https://kener.ing/logo.png" class="h-8 w-8" alt="" />
|
||||
<span class="text-xl font-semibold">Kener Documentation</span>
|
||||
<span class="text-xl font-medium">Kener Documentation</span>
|
||||
<span
|
||||
class="me-2 rounded bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800 dark:bg-blue-900 dark:text-blue-300"
|
||||
>
|
||||
@@ -96,8 +107,14 @@
|
||||
src="https://img.shields.io/github/stars/rajnandan1/kener?label=Star%20Repo&style=social"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/rajnandan1/kener/issues"
|
||||
class="text-sm font-medium"
|
||||
>
|
||||
Report Issue
|
||||
</a>
|
||||
<a href="https://github.com/sponsors/rajnandan1" class="text-sm font-medium">
|
||||
Support
|
||||
Sponsor
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -120,8 +137,8 @@
|
||||
</nav>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="fixed bottom-0 left-0 top-16 w-72 overflow-y-auto">
|
||||
<nav class="p-6">
|
||||
<aside class="z-2 fixed bottom-0 left-0 top-16 w-72 overflow-y-auto">
|
||||
<nav class="bg-background p-6">
|
||||
<!-- Getting Started Section -->
|
||||
{#each sidebar as item}
|
||||
<div class="mb-4">
|
||||
@@ -134,8 +151,8 @@
|
||||
{#each item.children as child}
|
||||
<a
|
||||
href={child.link.startsWith("/") ? base + child.link : child.link}
|
||||
class="group flex items-center rounded-md px-3 py-2 text-sm font-medium hover:underline {!!child.active
|
||||
? 'bg-muted'
|
||||
class="sidebar-item group flex items-center rounded-md px-3 py-2 text-sm font-medium {!!child.active
|
||||
? 'active'
|
||||
: ''}"
|
||||
>
|
||||
{child.title}
|
||||
@@ -148,18 +165,20 @@
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="z-1 ml-72 min-h-screen pt-16">
|
||||
<main class="z-2 relative ml-72 min-h-screen pt-16">
|
||||
<div class="mx-auto max-w-5xl px-4 py-10 sm:px-6 lg:px-8 lg:pr-64">
|
||||
<!-- Content Header -->
|
||||
<div
|
||||
class="prose prose-stone max-w-none dark:prose-invert prose-code:rounded prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:font-normal dark:prose-pre:bg-neutral-900"
|
||||
class="prose prose-stone max-w-none dark:prose-invert prose-code:rounded prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:font-normal prose-pre:bg-opacity-0 dark:prose-pre:bg-neutral-900"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{#if tableOfContents.length > 0}
|
||||
<div class="fixed bottom-0 right-0 top-16 hidden w-64 overflow-y-auto px-6 py-10 lg:block">
|
||||
<div
|
||||
class="blurry-bg fixed bottom-0 right-0 top-16 hidden w-64 overflow-y-auto px-6 py-10 lg:block"
|
||||
>
|
||||
<h4 class="mb-3 text-sm font-semibold uppercase tracking-wider">On this page</h4>
|
||||
<nav class="space-y-2">
|
||||
{#each tableOfContents as item}
|
||||
@@ -176,7 +195,7 @@
|
||||
</nav>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="fixed bottom-4 right-4">
|
||||
<div class=" fixed bottom-4 right-4">
|
||||
<Button on:click={toggleMode} variant="ghost" size="icon" class="flex">
|
||||
<Sun
|
||||
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import Moon from "lucide-svelte/icons/moon";
|
||||
import { Languages } from "lucide-svelte";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { analyticsEvent } from "$lib/analytics";
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -27,6 +28,10 @@
|
||||
classList.add("dark");
|
||||
localStorage.setItem("theme", "dark");
|
||||
}
|
||||
|
||||
analyticsEvent("theme_change", {
|
||||
theme: classList.contains("dark") ? "light" : "dark"
|
||||
});
|
||||
}
|
||||
let defaultLocaleValue;
|
||||
if (!allLocales) {
|
||||
@@ -41,6 +46,9 @@
|
||||
document.cookie = `localLang=${locale};max-age=${60 * 60 * 24 * 365 * 30}`;
|
||||
if (locale === defaultLocaleKey) return;
|
||||
defaultLocaleValue = allLocales[locale];
|
||||
analyticsEvent("language_change", {
|
||||
locale: locale
|
||||
});
|
||||
location.reload();
|
||||
}
|
||||
|
||||
@@ -52,8 +60,8 @@
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
let Analytics;
|
||||
onMount(async () => {
|
||||
let localTz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
if (localTz != data.localTz) {
|
||||
if (data.isBot === false) {
|
||||
@@ -62,9 +70,55 @@
|
||||
}
|
||||
}
|
||||
setTheme();
|
||||
|
||||
const providers = data.site.analytics;
|
||||
const analyticsPlugins = [];
|
||||
if (providers) {
|
||||
//loop object
|
||||
Object.keys(providers).forEach((key) => {
|
||||
const provider = providers[key];
|
||||
if (key == "GA") {
|
||||
analyticsPlugins.push(
|
||||
analyticsGa.default({
|
||||
measurementIds: provider.measurementIds
|
||||
})
|
||||
);
|
||||
} else if (key == "AMPLITUDE") {
|
||||
analyticsPlugins.push(
|
||||
analyticsAmplitude({
|
||||
apiKey: provider.measurementIds[0],
|
||||
options: {
|
||||
trackingOptions: {
|
||||
ip_address: false
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
} else if (key == "MIXPANEL") {
|
||||
analyticsPlugins.push(
|
||||
analyticsMixpanel({
|
||||
token: provider.measurementIds[0]
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
Analytics = _analytics.init({
|
||||
app: "kener",
|
||||
debug: true,
|
||||
version: 100,
|
||||
plugins: analyticsPlugins
|
||||
});
|
||||
Analytics.page();
|
||||
//import googleAnalyticsV3 from '@analytics/google-analytics-v3'
|
||||
});
|
||||
function captureAnalytics(e) {
|
||||
const { event, data } = e.detail;
|
||||
Analytics.track(event, data);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:analyticsEvent={captureAnalytics} />
|
||||
<svelte:head>
|
||||
<title>{data.site.title}</title>
|
||||
{#if data.site.favicon && data.site.favicon[0] == "/"}
|
||||
@@ -76,12 +130,19 @@
|
||||
{#each Object.entries(data.site.metaTags) as [key, value]}
|
||||
<meta name={key} content={value} />
|
||||
{/each}
|
||||
<script src="https://unpkg.com/analytics/dist/analytics.min.js"></script>
|
||||
|
||||
{#if data.site.analytics}
|
||||
{#each Object.entries(data.site.analytics) as [key, value]}
|
||||
<script data-type={key} src={value.script}></script>
|
||||
{/each}
|
||||
{/if}
|
||||
</svelte:head>
|
||||
<main style="--font-family: {data.site.font.family}">
|
||||
{#if data.showNav}
|
||||
<Nav {data} />
|
||||
{/if}
|
||||
<div class="min-h-screen">
|
||||
<div class="min-h-[70vh]">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { l } from "$lib/i18n/client";
|
||||
import { base } from "$app/paths";
|
||||
import { ArrowRight } from "lucide-svelte";
|
||||
|
||||
export let data;
|
||||
let hasActiveIncidents = data.openIncidents.length > 0;
|
||||
@@ -111,26 +112,23 @@
|
||||
{/if}
|
||||
{#if data.site.categories}
|
||||
<section
|
||||
class="mx-auto mb-8 w-full max-w-[890px] flex-1 flex-col items-start backdrop-blur-[2px]"
|
||||
class="mx-auto mb-8 w-full max-w-[890px] flex-1 flex-col items-start backdrop-blur-[2px] md:w-[655px]"
|
||||
>
|
||||
<h2 class="mb-2 mt-2 px-2 text-xl font-semibold">
|
||||
{l(data.lang, "root.other_monitors")}
|
||||
</h2>
|
||||
{#each data.site.categories as category}
|
||||
<Card.Root class="mb-2 w-full">
|
||||
<Card.Header>
|
||||
<Card.Title>{category.name}</Card.Title>
|
||||
<Card.Description class="relative pr-[100px]">
|
||||
<Card.Header class="relative pr-[100px]">
|
||||
<Card.Title class="">{category.name}</Card.Title>
|
||||
<Card.Description>
|
||||
{#if category.description}
|
||||
{category.description}
|
||||
{@html category.description}
|
||||
{/if}
|
||||
<a
|
||||
href="{base}/category-{category.name}"
|
||||
class="{buttonVariants({
|
||||
variant: 'secondary'
|
||||
})} absolute -top-4 right-2"
|
||||
variant: 'ghost'
|
||||
})} absolute right-2 top-1/2 -translate-y-1/2 transform"
|
||||
>
|
||||
View
|
||||
<ArrowRight class="h-4 w-4" />
|
||||
</a>
|
||||
</Card.Description>
|
||||
</Card.Header>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
{/if}
|
||||
{#if hasActiveIncidents}
|
||||
<section
|
||||
class="mx-auto mb-4 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center bg-transparent"
|
||||
class="mx-auto mb-4 flex w-full flex-1 flex-col items-start justify-center bg-transparent backdrop-blur-[2px] md:w-[655px]"
|
||||
id=""
|
||||
>
|
||||
<div class="grid w-full grid-cols-2 gap-4">
|
||||
@@ -54,7 +54,7 @@
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx-auto mb-8 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center backdrop-blur-[2px]"
|
||||
class="mx-auto mb-8 flex w-full flex-1 flex-col items-start justify-center backdrop-blur-[2px] md:w-[655px]"
|
||||
id=""
|
||||
>
|
||||
{#each data.openIncidents as incident, i}
|
||||
@@ -70,17 +70,17 @@
|
||||
{/if}
|
||||
{#if data.monitors.length > 0}
|
||||
<section
|
||||
class="mx-auto mb-4 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center bg-transparent"
|
||||
class="mx-auto mb-2 flex w-full flex-1 flex-col items-start justify-center bg-transparent md:w-[655px]"
|
||||
id=""
|
||||
>
|
||||
<div class="grid w-full grid-cols-2 gap-4">
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-left">
|
||||
<Badge class="" variant="outline">
|
||||
<Badge class="border-0 pl-0" variant="outline">
|
||||
{l(data.lang, "root.availability_per_component")}
|
||||
</Badge>
|
||||
</div>
|
||||
<div class="col-span-2 text-center md:col-span-1 md:text-right">
|
||||
<Badge variant="outline">
|
||||
<Badge variant="outline" class="border-0 pr-0">
|
||||
<span class="bg-api-up mr-1 inline-flex h-[8px] w-[8px] rounded-full opacity-75"
|
||||
></span>
|
||||
<span class="mr-3">
|
||||
@@ -105,7 +105,7 @@
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx-auto mb-8 flex w-full max-w-[890px] flex-1 flex-col items-start justify-center backdrop-blur-[2px]"
|
||||
class="mx-auto mb-8 flex w-full flex-1 flex-col items-start justify-center backdrop-blur-[2px] md:w-[655px]"
|
||||
>
|
||||
<Card.Root class="w-full">
|
||||
<Card.Content class="monitors-card p-0">
|
||||
|
||||
Reference in New Issue
Block a user