Kasianov Nikolai Alekseevich
1 year ago
commit
4cde747404
64 changed files with 60493 additions and 0 deletions
@ -0,0 +1,14 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
|
@ -0,0 +1,13 @@
|
||||
server_binary:=gohst
|
||||
|
||||
all: |
||||
mkdir -p bin && \
|
||||
cd src && CGO_ENABLED=0 go build && mv $(server_binary) ../bin && \
|
||||
cd .. && \
|
||||
cp -r pages bin && \
|
||||
cp -r scripts bin && \
|
||||
cp -r static bin
|
||||
|
||||
clean: |
||||
rm -rf bin
|
||||
|
@ -0,0 +1,23 @@
|
||||
# GoHST |
||||
## Go HTTP Server Template |
||||
|
||||
This is the usual template I follow when all I need is to have a quick "just works" web server with the ability to extend it further when needed. |
||||
|
||||
Your code goes to the `src`; your HTML pages go the `pages`; your JS files go to the `scripts`; your static content goes to `static`. |
||||
|
||||
Code directories to consider: |
||||
|
||||
- `conf` is a configuration file for the server to use. You can specify a port to work on, base directory where to look pages in and paths to the SSL keys. In larger projects it is bound to contain much more. |
||||
- `db` is where the database logic resides, base structures and helper functions to extract/add them from/to the database. |
||||
- `encryption` is just a bunch of helper functions to deal with BASE64 or SHA |
||||
- `logger` is for as-basic-as-it-gets logger usage |
||||
- `server/api` is where I usually write API|Page-specific handlers |
||||
- `server/page` contains a helper function to merge `pages/base.html` and any other page together |
||||
- `server/server` is a glue between everything there is. The actual server stuff is happening there |
||||
|
||||
With some work it's possible to strip everything unneeded and to just have a static web server. |
||||
|
||||
There is a `modernc.org/sqlite` dependency which is there only for "compile, run and see" ability. Otherwise, even if you don't use a database it won't launch. It is up to you to replace it with another driver or if you don't need it, strip `src/db` completely. |
||||
|
||||
# License |
||||
Do What The Fuck You Want To Public License for all files except for, obviously, bootstrap, as well as for src/logger which is under MIT |
@ -0,0 +1,40 @@
|
||||
{{ define "base" }} |
||||
|
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
|
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<title>dela</title> |
||||
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> |
||||
<script src="/static/bootstrap/js/bootstrap.min.js"></script> |
||||
<link rel="shortcut icon" href="/static/images/favicon.ico" type="image/x-icon"> |
||||
</head> |
||||
|
||||
<body class="d-flex flex-column h-100"> |
||||
<header class="d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom"> |
||||
<div class="col-md-3 mb-2 mb-md-0"> |
||||
<a href="/" class="d-inline-flex link-body-emphasis text-decoration-none"> |
||||
<svg class="bi" width="40" height="32" role="img" aria-label="Bootstrap"><use xlink:href="#bootstrap"></use></svg> |
||||
</a> |
||||
</div> |
||||
|
||||
<div class="col-md-3 text-end" id="bar-auth"> |
||||
<a href="/otherpage" class="btn btn-outline-primary me-2">Other page</a> |
||||
</div> |
||||
</header> |
||||
|
||||
<div style="margin: auto; |
||||
margin-top: 5ch; |
||||
margin-bottom: 10ch; |
||||
max-width: 120ch;"> |
||||
{{ template "content" . }} |
||||
</div> |
||||
</body> |
||||
|
||||
</html> |
||||
|
||||
<script src="/scripts/someScript.js"></script> |
||||
|
||||
{{ end }} |
@ -0,0 +1,11 @@
|
||||
{{ template "base" . }} |
||||
|
||||
{{ define "content" }} |
||||
|
||||
<h3>Index page</h3> |
||||
|
||||
<p> |
||||
This is an index page |
||||
</p> |
||||
|
||||
{{ end }} |
@ -0,0 +1,11 @@
|
||||
{{ template "base" . }} |
||||
|
||||
{{ define "content" }} |
||||
|
||||
<h3>Other page</h3> |
||||
|
||||
<p> |
||||
This is a some other page |
||||
</p> |
||||
|
||||
{{ end }} |
@ -0,0 +1 @@
|
||||
alert("This is coming from \"someScript.js\" in scripts folder and is loaded via base.html template"); |
@ -0,0 +1,87 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
// Kasyanov N.A. (Unbewohnte), 2023
|
||||
|
||||
package conf |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"io" |
||||
"os" |
||||
) |
||||
|
||||
type Conf struct { |
||||
Port uint16 `json:"port"` |
||||
CertFilePath string `json:"cert_file_path"` |
||||
KeyFilePath string `json:"key_file_path"` |
||||
BaseContentDir string `json:"base_content_dir"` |
||||
ProdDBName string `json:"production_db"` |
||||
} |
||||
|
||||
// Creates a default server configuration
|
||||
func Default() Conf { |
||||
return Conf{ |
||||
Port: 8080, |
||||
CertFilePath: "", |
||||
KeyFilePath: "", |
||||
BaseContentDir: ".", |
||||
ProdDBName: "database.db", |
||||
} |
||||
} |
||||
|
||||
// Tries to retrieve configuration from given json file
|
||||
func FromFile(path string) (Conf, error) { |
||||
configFile, err := os.Open(path) |
||||
if err != nil { |
||||
return Default(), err |
||||
} |
||||
defer configFile.Close() |
||||
|
||||
confBytes, err := io.ReadAll(configFile) |
||||
if err != nil { |
||||
return Default(), err |
||||
} |
||||
|
||||
var config Conf |
||||
err = json.Unmarshal(confBytes, &config) |
||||
if err != nil { |
||||
return Default(), err |
||||
} |
||||
|
||||
return config, nil |
||||
} |
||||
|
||||
// Create empty configuration file
|
||||
func Create(path string, conf Conf) (Conf, error) { |
||||
configFile, err := os.Create(path) |
||||
if err != nil { |
||||
return Default(), err |
||||
} |
||||
defer configFile.Close() |
||||
|
||||
configJsonBytes, err := json.MarshalIndent(conf, "", " ") |
||||
if err != nil { |
||||
return conf, err |
||||
} |
||||
|
||||
_, err = configFile.Write(configJsonBytes) |
||||
if err != nil { |
||||
return conf, nil |
||||
} |
||||
|
||||
return conf, nil |
||||
} |
@ -0,0 +1,79 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
// Kasyanov N.A. (Unbewohnte), 2023
|
||||
|
||||
package db |
||||
|
||||
import ( |
||||
"database/sql" |
||||
"os" |
||||
|
||||
_ "modernc.org/sqlite" // For example this one
|
||||
) |
||||
|
||||
// Database wrapper
|
||||
type DB struct { |
||||
*sql.DB |
||||
} |
||||
|
||||
func setUpTables(db *DB) error { |
||||
// Table for test entities to be stored in
|
||||
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, data TEXT NOT NULL)`) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// Open database
|
||||
func FromFile(path string) (*DB, error) { |
||||
driver, err := sql.Open("sqlite", path) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
dbase := &DB{driver} |
||||
|
||||
err = setUpTables(dbase) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return dbase, nil |
||||
} |
||||
|
||||
// Create database file
|
||||
func Create(path string) (*DB, error) { |
||||
dbFile, err := os.Create(path) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
dbFile.Close() |
||||
|
||||
driver, err := sql.Open("sqlite", path) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
dbase := &DB{driver} |
||||
|
||||
err = setUpTables(dbase) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return dbase, nil |
||||
} |
@ -0,0 +1,72 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
// Kasyanov N.A. (Unbewohnte), 2023
|
||||
|
||||
package db |
||||
|
||||
import "database/sql" |
||||
|
||||
type TestEntity struct { |
||||
Text string `json:"text"` |
||||
} |
||||
|
||||
func scanTestEntity(rows *sql.Rows) (*TestEntity, error) { |
||||
rows.Next() |
||||
var entity TestEntity |
||||
err := rows.Scan(&entity.Text) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &entity, nil |
||||
} |
||||
|
||||
// Searches for TestEntity with text and returns it
|
||||
func (db *DB) GetTestEntity(text string) (*TestEntity, error) { |
||||
rows, err := db.Query("SELECT * FROM test WHERE text=?", text) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer rows.Close() |
||||
|
||||
TestEntity, err := scanTestEntity(rows) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return TestEntity, nil |
||||
} |
||||
|
||||
// Creates a new TestEntity in the database
|
||||
func (db *DB) CreateTestEntity(newTestEntity TestEntity) error { |
||||
_, err := db.Exec( |
||||
"INSERT INTO test(text) VALUES(?)", |
||||
newTestEntity.Text, |
||||
) |
||||
|
||||
return err |
||||
} |
||||
|
||||
// Deletes TestEntity with given text
|
||||
func (db *DB) DeleteTestEntity(text string) error { |
||||
_, err := db.Exec( |
||||
"DELETE FROM test WHERE text=?", |
||||
text, |
||||
) |
||||
|
||||
return err |
||||
} |
@ -0,0 +1,43 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
// Kasyanov N.A. (Unbewohnte), 2023
|
||||
|
||||
package encryption |
||||
|
||||
import ( |
||||
"crypto/sha256" |
||||
"encoding/base64" |
||||
"fmt" |
||||
) |
||||
|
||||
// Encodes given string via Base64
|
||||
func EncodeStringBase64(str string) string { |
||||
return base64.StdEncoding.EncodeToString([]byte(str)) |
||||
} |
||||
|
||||
// Decodes given string via Base64
|
||||
func DecodeStringBase64(encodedStr string) string { |
||||
decodedBytes, _ := base64.StdEncoding.DecodeString(encodedStr) |
||||
return string(decodedBytes) |
||||
} |
||||
|
||||
// Returns HEX string of SHA256'd data
|
||||
func SHA256Hex(data []byte) string { |
||||
hash := sha256.New() |
||||
hash.Write(data) |
||||
return fmt.Sprintf("%x", hash.Sum(nil)) |
||||
} |
@ -0,0 +1,25 @@
|
||||
module Unbewohnte/gohst |
||||
|
||||
go 1.18 |
||||
|
||||
require ( |
||||
github.com/dustin/go-humanize v1.0.1 // indirect |
||||
github.com/google/uuid v1.3.0 // indirect |
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect |
||||
github.com/mattn/go-isatty v0.0.16 // indirect |
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect |
||||
golang.org/x/mod v0.3.0 // indirect |
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect |
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 // indirect |
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect |
||||
lukechampine.com/uint128 v1.2.0 // indirect |
||||
modernc.org/cc/v3 v3.40.0 // indirect |
||||
modernc.org/ccgo/v3 v3.16.13 // indirect |
||||
modernc.org/libc v1.24.1 // indirect |
||||
modernc.org/mathutil v1.5.0 // indirect |
||||
modernc.org/memory v1.6.0 // indirect |
||||
modernc.org/opt v0.1.3 // indirect |
||||
modernc.org/sqlite v1.25.0 // indirect |
||||
modernc.org/strutil v1.1.3 // indirect |
||||
modernc.org/token v1.0.1 // indirect |
||||
) |
@ -0,0 +1,57 @@
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= |
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= |
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= |
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= |
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= |
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= |
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= |
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= |
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= |
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= |
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= |
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 h1:M8tBwCtWD/cZV9DZpFYRUgaymAYAr+aIUTWzDaM3uPs= |
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= |
||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= |
||||
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= |
||||
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= |
||||
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= |
||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= |
||||
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= |
||||
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= |
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= |
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= |
||||
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= |
||||
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= |
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= |
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= |
||||
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= |
||||
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= |
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= |
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= |
||||
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= |
||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= |
@ -0,0 +1,54 @@
|
||||
/* |
||||
The MIT License (MIT) |
||||
|
||||
Copyright © 2022 Kasyanov Nikolay Alexeyevich (Unbewohnte) |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
package logger |
||||
|
||||
import ( |
||||
"io" |
||||
"log" |
||||
"os" |
||||
) |
||||
|
||||
// 3 basic loggers in global space
|
||||
var ( |
||||
// neutral information logger
|
||||
infoLog *log.Logger |
||||
// warning-level information logger
|
||||
warningLog *log.Logger |
||||
// errors information logger
|
||||
errorLog *log.Logger |
||||
) |
||||
|
||||
func init() { |
||||
infoLog = log.New(os.Stdout, "[INFO] ", log.Ldate|log.Ltime) |
||||
warningLog = log.New(os.Stdout, "[WARNING] ", log.Ldate|log.Ltime) |
||||
errorLog = log.New(os.Stdout, "[ERROR] ", log.Ldate|log.Ltime) |
||||
} |
||||
|
||||
// Set up loggers to write to the given writer
|
||||
func SetOutput(writer io.Writer) { |
||||
if writer == nil { |
||||
writer = io.Discard |
||||
} |
||||
infoLog.SetOutput(writer) |
||||
warningLog.SetOutput(writer) |
||||
errorLog.SetOutput(writer) |
||||
} |
||||
func Info(format string, a ...interface{}) { |
||||
infoLog.Printf(format, a...) |
||||
} |
||||
func Warning(format string, a ...interface{}) { |
||||
warningLog.Printf(format, a...) |
||||
} |
||||
func Error(format string, a ...interface{}) { |
||||
errorLog.Printf(format, a...) |
||||
} |
@ -0,0 +1,79 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"Unbewohnte/gohst/conf" |
||||
"Unbewohnte/gohst/logger" |
||||
"Unbewohnte/gohst/server" |
||||
"os" |
||||
"path/filepath" |
||||
) |
||||
|
||||
const ConfName string = "conf.json" |
||||
|
||||
var ( |
||||
WDir string |
||||
Conf conf.Conf |
||||
) |
||||
|
||||
func init() { |
||||
// Initialize logging
|
||||
logger.SetOutput(os.Stdout) |
||||
|
||||
// Work out the working directory
|
||||
exePath, err := os.Executable() |
||||
if err != nil { |
||||
logger.Error("[Init] Failed to retrieve executable's path: %s", err) |
||||
os.Exit(1) |
||||
} |
||||
WDir = filepath.Dir(exePath) |
||||
logger.Info("[Init] Working in \"%s\"", WDir) |
||||
|
||||
// Open configuration, create if does not exist
|
||||
Conf, err = conf.FromFile(filepath.Join(WDir, ConfName)) |
||||
if err != nil { |
||||
_, err = conf.Create(filepath.Join(WDir, ConfName), conf.Default()) |
||||
if err != nil { |
||||
logger.Error("[Init] Failed to create a new configuration file: %s", err) |
||||
os.Exit(1) |
||||
} |
||||
logger.Info("[Init] Created a new configuration file") |
||||
os.Exit(0) |
||||
} |
||||
logger.Info("[Init] Opened existing configuration file") |
||||
if Conf.BaseContentDir == "." { |
||||
Conf.BaseContentDir = WDir |
||||
} |
||||
|
||||
logger.Info("[Init] Successful initializaion!") |
||||
} |
||||
|
||||
func main() { |
||||
server, err := server.New(Conf) |
||||
if err != nil { |
||||
logger.Error("[Main] Failed to initialize a new server with conf (%+v): %s", Conf, err) |
||||
return |
||||
} |
||||
logger.Info("[Main] Successfully initialized a new server instance with conf (%+v)", Conf) |
||||
|
||||
err = server.Start() |
||||
if err != nil { |
||||
logger.Error("[Main] Fatal server failure: %s. Exiting...", err) |
||||
return |
||||
} |
||||
} |
@ -0,0 +1,96 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
// Kasyanov N.A. (Unbewohnte), 2023
|
||||
|
||||
package server |
||||
|
||||
import ( |
||||
"Unbewohnte/gohst/db" |
||||
"Unbewohnte/gohst/logger" |
||||
"encoding/json" |
||||
"io" |
||||
"net/http" |
||||
) |
||||
|
||||
func (s *Server) entityEndpoint(w http.ResponseWriter, req *http.Request) { |
||||
switch req.Method { |
||||
case http.MethodDelete: |
||||
// Delete an already existing entity
|
||||
defer req.Body.Close() |
||||
|
||||
// Read body
|
||||
body, err := io.ReadAll(req.Body) |
||||
if err != nil { |
||||
logger.Warning("[Server] Failed to read request body to delete an entity: %s", err) |
||||
http.Error(w, "Failed to read body", http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
// Unmarshal JSON
|
||||
var entity db.TestEntity |
||||
err = json.Unmarshal(body, &entity) |
||||
if err != nil { |
||||
logger.Warning("[Server] Received invalid entity JSON for deletion: %s", err) |
||||
http.Error(w, "Invalid entity JSON", http.StatusBadRequest) |
||||
return |
||||
} |
||||
|
||||
err = s.db.DeleteTestEntity(entity.Text) |
||||
if err != nil { |
||||
logger.Error("[Server] Failed to delete %s: %s", entity.Text, err) |
||||
http.Error(w, "Failed to delete entity or TODO contents", http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
// Success!
|
||||
w.WriteHeader(http.StatusOK) |
||||
|
||||
case http.MethodPost: |
||||
// Create a new entity
|
||||
defer req.Body.Close() |
||||
// Read body
|
||||
body, err := io.ReadAll(req.Body) |
||||
if err != nil { |
||||
logger.Warning("[Server] Failed to read request body to create a new entity: %s", err) |
||||
http.Error(w, "Failed to read body", http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
// Unmarshal JSON
|
||||
var newEntity db.TestEntity |
||||
err = json.Unmarshal(body, &newEntity) |
||||
if err != nil { |
||||
logger.Warning("[Server] Received invalid entity JSON for creation: %s", err) |
||||
http.Error(w, "Invalid entity JSON", http.StatusBadRequest) |
||||
return |
||||
} |
||||
|
||||
// Add entity to the database
|
||||
err = s.db.CreateTestEntity(newEntity) |
||||
if err != nil { |
||||
http.Error(w, "Failed to create a new entity", http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
// Success!
|
||||
w.WriteHeader(http.StatusOK) |
||||
logger.Info("[Server] Created a new entity \"%s\"", newEntity.Text) |
||||
|
||||
default: |
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
// Kasyanov N.A. (Unbewohnte), 2023
|
||||
|
||||
package server |
||||
|
||||
import ( |
||||
"Unbewohnte/gohst/logger" |
||||
"html/template" |
||||
"path/filepath" |
||||
) |
||||
|
||||
// Constructs a pageName template via inserting basePageName in pagesDir
|
||||
func getPage(pagesDir string, basePageName string, pageName string) (*template.Template, error) { |
||||
page, err := template.ParseFiles( |
||||
filepath.Join(pagesDir, basePageName), |
||||
filepath.Join(pagesDir, pageName), |
||||
) |
||||
if err != nil { |
||||
logger.Error("Failed to parse page files (pagename is \"%s\"): %s", pageName, err) |
||||
return nil, err |
||||
} |
||||
|
||||
return page, nil |
||||
} |
@ -0,0 +1,179 @@
|
||||
/* |
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
Version 2, December 2004 |
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> |
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified |
||||
copies of this license document, and changing it is allowed as long |
||||
as the name is changed. |
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO. |
||||
*/ |
||||
|
||||
// Kasyanov N.A. (Unbewohnte), 2023
|
||||
|
||||
package server |
||||
|
||||
import ( |
||||
"Unbewohnte/gohst/conf" |
||||
"Unbewohnte/gohst/db" |
||||
"Unbewohnte/gohst/logger" |
||||
"context" |
||||
"fmt" |
||||
"net/http" |
||||
"os" |
||||
"path/filepath" |
||||
"time" |
||||
) |
||||
|
||||
const ( |
||||
PagesDirName string = "pages" |
||||
StaticDirName string = "static" |
||||
ScriptsDirName string = "scripts" |
||||
) |
||||
|
||||
type Server struct { |
||||
config conf.Conf |
||||
db *db.DB |
||||
http http.Server |
||||
} |
||||
|
||||
// Creates a new server instance with provided config
|
||||
func New(config conf.Conf) (*Server, error) { |
||||
var server Server = Server{} |
||||
server.config = config |
||||
|
||||
// Check if required directories are present
|
||||
_, err := os.Stat(filepath.Join(config.BaseContentDir, PagesDirName)) |
||||
if err != nil { |
||||
logger.Error("[Server] A directory with HTML pages is not available: %s", err) |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = os.Stat(filepath.Join(config.BaseContentDir, ScriptsDirName)) |
||||
if err != nil { |
||||
logger.Error("[Server] A directory with scripts is not available: %s", err) |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = os.Stat(filepath.Join(config.BaseContentDir, StaticDirName)) |
||||
if err != nil { |
||||
logger.Error("[Server] A directory with static content is not available: %s", err) |
||||
return nil, err |
||||
} |
||||
|
||||
// Get database working
|
||||
serverDB, err := db.FromFile(filepath.Join(config.BaseContentDir, config.ProdDBName)) |
||||
if err != nil { |
||||
// Create one then
|
||||
serverDB, err = db.Create(filepath.Join(config.BaseContentDir, config.ProdDBName)) |
||||
if err != nil { |
||||
logger.Error("Failed to create a new database: %s", err) |
||||
return nil, err |
||||
} |
||||
} |
||||
server.db = serverDB |
||||
logger.Info("Opened a database successfully") |
||||
|
||||
// Start constructing an http server configuration
|
||||
server.http = http.Server{ |
||||
Addr: fmt.Sprintf(":%d", server.config.Port), |
||||
} |
||||
|
||||
// Configure paths' callbacks
|
||||
mux := http.NewServeMux() |
||||
mux.Handle( |
||||
"/static/", |
||||
http.StripPrefix("/static/", http.FileServer( |
||||
http.Dir(filepath.Join(server.config.BaseContentDir, StaticDirName))), |
||||
), |
||||
) |
||||
|
||||
mux.Handle( |
||||
"/scripts/", |
||||
http.StripPrefix("/scripts/", http.FileServer( |
||||
http.Dir(filepath.Join(server.config.BaseContentDir, ScriptsDirName))), |
||||
), |
||||
) |
||||
|
||||
// Handle page requests
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { |
||||
switch req.URL.Path { |
||||
case "/": |
||||
requestedPage, err := getPage( |
||||
filepath.Join(server.config.BaseContentDir, PagesDirName), "base.html", "index.html", |
||||
) |
||||
if err != nil { |
||||
http.Error(w, "Internal server error", http.StatusInternalServerError) |
||||
} |
||||
|
||||
requestedPage.ExecuteTemplate(w, "index.html", nil) |
||||
|
||||
default: |
||||
requestedPage, err := getPage( |
||||
filepath.Join(server.config.BaseContentDir, PagesDirName), |
||||
"base.html", |
||||
req.URL.Path[1:]+".html", |
||||
) |
||||
if err == nil { |
||||
requestedPage.ExecuteTemplate(w, req.URL.Path[1:]+".html", nil) |
||||
} else { |
||||
// Redirect to the index
|
||||
index, err := getPage( |
||||
filepath.Join(server.config.BaseContentDir, PagesDirName), |
||||
"base.html", |
||||
req.URL.Path[1:]+".html", |
||||
) |
||||
if err != nil { |
||||
http.Error(w, "Internal server error", http.StatusInternalServerError) |
||||
} |
||||
|
||||
index.ExecuteTemplate(w, "index.html", nil) |
||||
} |
||||
} |
||||
}) |
||||
|
||||
// Paths which need to be handled differently come here
|
||||
mux.HandleFunc("/api/test_entity", server.entityEndpoint) |
||||
|
||||
server.http.Handler = mux |
||||
logger.Info("[Server] Created an HTTP server instance") |
||||
|
||||
return &server, nil |
||||
} |
||||
|
||||
// Launches server instance
|
||||
func (s *Server) Start() error { |
||||
if s.config.CertFilePath != "" && s.config.KeyFilePath != "" { |
||||
logger.Info("[Server] Using TLS") |
||||
logger.Info("[Server] HTTP server is going live on port %d!", s.config.Port) |
||||
|
||||
err := s.http.ListenAndServeTLS(s.config.CertFilePath, s.config.KeyFilePath) |
||||
if err != nil && err != http.ErrServerClosed { |
||||
logger.Error("[Server] Fatal server error: %s", err) |
||||
return err |
||||
} |
||||
} else { |
||||
logger.Info("[Server] Not using TLS") |
||||
logger.Info("[Server] HTTP server is going live on port %d!", s.config.Port) |
||||
|
||||
err := s.http.ListenAndServe() |
||||
if err != nil && err != http.ErrServerClosed { |
||||
logger.Error("[Server] Fatal server error: %s", err) |
||||
return err |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// Stops the server immediately
|
||||
func (s *Server) Stop() { |
||||
ctx, cfunc := context.WithDeadline(context.Background(), time.Now().Add(time.Second*10)) |
||||
s.http.Shutdown(ctx) |
||||
cfunc() |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,593 @@
|
||||
/*! |
||||
* Bootstrap Reboot v5.3.0 (https://getbootstrap.com/) |
||||
* Copyright 2011-2023 The Bootstrap Authors |
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
||||
*/ |
||||
:root, |
||||
[data-bs-theme=light] { |
||||
--bs-blue: #0d6efd; |
||||
--bs-indigo: #6610f2; |
||||
--bs-purple: #6f42c1; |
||||
--bs-pink: #d63384; |
||||
--bs-red: #dc3545; |
||||
--bs-orange: #fd7e14; |
||||
--bs-yellow: #ffc107; |
||||
--bs-green: #198754; |
||||
--bs-teal: #20c997; |
||||
--bs-cyan: #0dcaf0; |
||||
--bs-black: #000; |
||||
--bs-white: #fff; |
||||
--bs-gray: #6c757d; |
||||
--bs-gray-dark: #343a40; |
||||
--bs-gray-100: #f8f9fa; |
||||
--bs-gray-200: #e9ecef; |
||||
--bs-gray-300: #dee2e6; |
||||
--bs-gray-400: #ced4da; |
||||
--bs-gray-500: #adb5bd; |
||||
--bs-gray-600: #6c757d; |
||||
--bs-gray-700: #495057; |
||||
--bs-gray-800: #343a40; |
||||
--bs-gray-900: #212529; |
||||
--bs-primary: #0d6efd; |
||||
--bs-secondary: #6c757d; |
||||
--bs-success: #198754; |
||||
--bs-info: #0dcaf0; |
||||
--bs-warning: #ffc107; |
||||
--bs-danger: #dc3545; |
||||
--bs-light: #f8f9fa; |
||||
--bs-dark: #212529; |
||||
--bs-primary-rgb: 13, 110, 253; |
||||
--bs-secondary-rgb: 108, 117, 125; |
||||
--bs-success-rgb: 25, 135, 84; |
||||
--bs-info-rgb: 13, 202, 240; |
||||
--bs-warning-rgb: 255, 193, 7; |
||||
--bs-danger-rgb: 220, 53, 69; |
||||
--bs-light-rgb: 248, 249, 250; |
||||
--bs-dark-rgb: 33, 37, 41; |
||||
--bs-primary-text-emphasis: #052c65; |
||||
--bs-secondary-text-emphasis: #2b2f32; |
||||
--bs-success-text-emphasis: #0a3622; |
||||
--bs-info-text-emphasis: #055160; |
||||
--bs-warning-text-emphasis: #664d03; |
||||
--bs-danger-text-emphasis: #58151c; |
||||
--bs-light-text-emphasis: #495057; |
||||
--bs-dark-text-emphasis: #495057; |
||||
--bs-primary-bg-subtle: #cfe2ff; |
||||
--bs-secondary-bg-subtle: #e2e3e5; |
||||
--bs-success-bg-subtle: #d1e7dd; |
||||
--bs-info-bg-subtle: #cff4fc; |
||||
--bs-warning-bg-subtle: #fff3cd; |
||||
--bs-danger-bg-subtle: #f8d7da; |
||||
--bs-light-bg-subtle: #fcfcfd; |
||||
--bs-dark-bg-subtle: #ced4da; |
||||
--bs-primary-border-subtle: #9ec5fe; |
||||
--bs-secondary-border-subtle: #c4c8cb; |
||||
--bs-success-border-subtle: #a3cfbb; |
||||
--bs-info-border-subtle: #9eeaf9; |
||||
--bs-warning-border-subtle: #ffe69c; |
||||
--bs-danger-border-subtle: #f1aeb5; |
||||
--bs-light-border-subtle: #e9ecef; |
||||
--bs-dark-border-subtle: #adb5bd; |
||||
--bs-white-rgb: 255, 255, 255; |
||||
--bs-black-rgb: 0, 0, 0; |
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; |
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; |
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); |
||||
--bs-body-font-family: var(--bs-font-sans-serif); |
||||
--bs-body-font-size: 1rem; |
||||
--bs-body-font-weight: 400; |
||||
--bs-body-line-height: 1.5; |
||||
--bs-body-color: #212529; |
||||
--bs-body-color-rgb: 33, 37, 41; |
||||
--bs-body-bg: #fff; |
||||
--bs-body-bg-rgb: 255, 255, 255; |
||||
--bs-emphasis-color: #000; |
||||
--bs-emphasis-color-rgb: 0, 0, 0; |
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75); |
||||
--bs-secondary-color-rgb: 33, 37, 41; |
||||
--bs-secondary-bg: #e9ecef; |
||||
--bs-secondary-bg-rgb: 233, 236, 239; |
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5); |
||||
--bs-tertiary-color-rgb: 33, 37, 41; |
||||
--bs-tertiary-bg: #f8f9fa; |
||||
--bs-tertiary-bg-rgb: 248, 249, 250; |
||||
--bs-heading-color: inherit; |
||||
--bs-link-color: #0d6efd; |
||||
--bs-link-color-rgb: 13, 110, 253; |
||||
--bs-link-decoration: underline; |
||||
--bs-link-hover-color: #0a58ca; |
||||
--bs-link-hover-color-rgb: 10, 88, 202; |
||||
--bs-code-color: #d63384; |
||||
--bs-highlight-bg: #fff3cd; |
||||
--bs-border-width: 1px; |
||||
--bs-border-style: solid; |
||||
--bs-border-color: #dee2e6; |
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175); |
||||
--bs-border-radius: 0.375rem; |
||||
--bs-border-radius-sm: 0.25rem; |
||||
--bs-border-radius-lg: 0.5rem; |
||||
--bs-border-radius-xl: 1rem; |
||||
--bs-border-radius-xxl: 2rem; |
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl); |
||||
--bs-border-radius-pill: 50rem; |
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); |
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); |
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); |
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075); |
||||
--bs-focus-ring-width: 0.25rem; |
||||
--bs-focus-ring-opacity: 0.25; |
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25); |
||||
--bs-form-valid-color: #198754; |
||||
--bs-form-valid-border-color: #198754; |
||||
--bs-form-invalid-color: #dc3545; |
||||
--bs-form-invalid-border-color: #dc3545; |
||||
} |
||||
|
||||
[data-bs-theme=dark] { |
||||
color-scheme: dark; |
||||
--bs-body-color: #adb5bd; |
||||
--bs-body-color-rgb: 173, 181, 189; |
||||
--bs-body-bg: #212529; |
||||
--bs-body-bg-rgb: 33, 37, 41; |
||||
--bs-emphasis-color: #fff; |
||||
--bs-emphasis-color-rgb: 255, 255, 255; |
||||
--bs-secondary-color: rgba(173, 181, 189, 0.75); |
||||
--bs-secondary-color-rgb: 173, 181, 189; |
||||
--bs-secondary-bg: #343a40; |
||||
--bs-secondary-bg-rgb: 52, 58, 64; |
||||
--bs-tertiary-color: rgba(173, 181, 189, 0.5); |
||||
--bs-tertiary-color-rgb: 173, 181, 189; |
||||
--bs-tertiary-bg: #2b3035; |
||||
--bs-tertiary-bg-rgb: 43, 48, 53; |
||||
--bs-primary-text-emphasis: #6ea8fe; |
||||
--bs-secondary-text-emphasis: #a7acb1; |
||||
--bs-success-text-emphasis: #75b798; |
||||
--bs-info-text-emphasis: #6edff6; |
||||
--bs-warning-text-emphasis: #ffda6a; |
||||
--bs-danger-text-emphasis: #ea868f; |
||||
--bs-light-text-emphasis: #f8f9fa; |
||||
--bs-dark-text-emphasis: #dee2e6; |
||||
--bs-primary-bg-subtle: #031633; |
||||
--bs-secondary-bg-subtle: #161719; |
||||
--bs-success-bg-subtle: #051b11; |
||||
--bs-info-bg-subtle: #032830; |
||||
--bs-warning-bg-subtle: #332701; |
||||
--bs-danger-bg-subtle: #2c0b0e; |
||||
--bs-light-bg-subtle: #343a40; |
||||
--bs-dark-bg-subtle: #1a1d20; |
||||
--bs-primary-border-subtle: #084298; |
||||
--bs-secondary-border-subtle: #41464b; |
||||
--bs-success-border-subtle: #0f5132; |
||||
--bs-info-border-subtle: #087990; |
||||
--bs-warning-border-subtle: #997404; |
||||
--bs-danger-border-subtle: #842029; |
||||
--bs-light-border-subtle: #495057; |
||||
--bs-dark-border-subtle: #343a40; |
||||
--bs-heading-color: inherit; |
||||
--bs-link-color: #6ea8fe; |
||||
--bs-link-hover-color: #8bb9fe; |
||||
--bs-link-color-rgb: 110, 168, 254; |
||||
--bs-link-hover-color-rgb: 139, 185, 254; |
||||
--bs-code-color: #e685b5; |
||||
--bs-border-color: #495057; |
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15); |
||||
--bs-form-valid-color: #75b798; |
||||
--bs-form-valid-border-color: #75b798; |
||||
--bs-form-invalid-color: #ea868f; |
||||
--bs-form-invalid-border-color: #ea868f; |
||||
} |
||||
|
||||
*, |
||||
*::before, |
||||
*::after { |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
@media (prefers-reduced-motion: no-preference) { |
||||
:root { |
||||
scroll-behavior: smooth; |
||||
} |
||||
} |
||||
|
||||
body { |
||||
margin: 0; |
||||
font-family: var(--bs-body-font-family); |
||||
font-size: var(--bs-body-font-size); |
||||
font-weight: var(--bs-body-font-weight); |
||||
line-height: var(--bs-body-line-height); |
||||
color: var(--bs-body-color); |
||||
text-align: var(--bs-body-text-align); |
||||
background-color: var(--bs-body-bg); |
||||
-webkit-text-size-adjust: 100%; |
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
||||
} |
||||
|
||||
hr { |
||||
margin: 1rem 0; |
||||
color: inherit; |
||||
border: 0; |
||||
border-top: var(--bs-border-width) solid; |
||||
opacity: 0.25; |
||||
} |
||||
|
||||
h6, h5, h4, h3, h2, h1 { |
||||
margin-top: 0; |
||||
margin-bottom: 0.5rem; |
||||
font-weight: 500; |
||||
line-height: 1.2; |
||||
color: var(--bs-heading-color); |
||||
} |
||||
|
||||
h1 { |
||||
font-size: calc(1.375rem + 1.5vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h1 { |
||||
font-size: 2.5rem; |
||||
} |
||||
} |
||||
|
||||
h2 { |
||||
font-size: calc(1.325rem + 0.9vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h2 { |
||||
font-size: 2rem; |
||||
} |
||||
} |
||||
|
||||
h3 { |
||||
font-size: calc(1.3rem + 0.6vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h3 { |
||||
font-size: 1.75rem; |
||||
} |
||||
} |
||||
|
||||
h4 { |
||||
font-size: calc(1.275rem + 0.3vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h4 { |
||||
font-size: 1.5rem; |
||||
} |
||||
} |
||||
|
||||
h5 { |
||||
font-size: 1.25rem; |
||||
} |
||||
|
||||
h6 { |
||||
font-size: 1rem; |
||||
} |
||||
|
||||
p { |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
} |
||||
|
||||
abbr[title] { |
||||
-webkit-text-decoration: underline dotted; |
||||
text-decoration: underline dotted; |
||||
cursor: help; |
||||
-webkit-text-decoration-skip-ink: none; |
||||
text-decoration-skip-ink: none; |
||||
} |
||||
|
||||
address { |
||||
margin-bottom: 1rem; |
||||
font-style: normal; |
||||
line-height: inherit; |
||||
} |
||||
|
||||
ol, |
||||
ul { |
||||
padding-left: 2rem; |
||||
} |
||||
|
||||
ol, |
||||
ul, |
||||
dl { |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
} |
||||
|
||||
ol ol, |
||||
ul ul, |
||||
ol ul, |
||||
ul ol { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
dt { |
||||
font-weight: 700; |
||||
} |
||||
|
||||
dd { |
||||
margin-bottom: 0.5rem; |
||||
margin-left: 0; |
||||
} |
||||
|
||||
blockquote { |
||||
margin: 0 0 1rem; |
||||
} |
||||
|
||||
b, |
||||
strong { |
||||
font-weight: bolder; |
||||
} |
||||
|
||||
small { |
||||
font-size: 0.875em; |
||||
} |
||||
|
||||
mark { |
||||
padding: 0.1875em; |
||||
background-color: var(--bs-highlight-bg); |
||||
} |
||||
|
||||
sub, |
||||
sup { |
||||
position: relative; |
||||
font-size: 0.75em; |
||||
line-height: 0; |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
sub { |
||||
bottom: -0.25em; |
||||
} |
||||
|
||||
sup { |
||||
top: -0.5em; |
||||
} |
||||
|
||||
a { |
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)); |
||||
text-decoration: underline; |
||||
} |
||||
a:hover { |
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb); |
||||
} |
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover { |
||||
color: inherit; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
pre, |
||||
code, |
||||
kbd, |
||||
samp { |
||||
font-family: var(--bs-font-monospace); |
||||
font-size: 1em; |
||||
} |
||||
|
||||
pre { |
||||
display: block; |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
overflow: auto; |
||||
font-size: 0.875em; |
||||
} |
||||
pre code { |
||||
font-size: inherit; |
||||
color: inherit; |
||||
word-break: normal; |
||||
} |
||||
|
||||
code { |
||||
font-size: 0.875em; |
||||
color: var(--bs-code-color); |
||||
word-wrap: break-word; |
||||
} |
||||
a > code { |
||||
color: inherit; |
||||
} |
||||
|
||||
kbd { |
||||
padding: 0.1875rem 0.375rem; |
||||
font-size: 0.875em; |
||||
color: var(--bs-body-bg); |
||||
background-color: var(--bs-body-color); |
||||
border-radius: 0.25rem; |
||||
} |
||||
kbd kbd { |
||||
padding: 0; |
||||
font-size: 1em; |
||||
} |
||||
|
||||
figure { |
||||
margin: 0 0 1rem; |
||||
} |
||||
|
||||
img, |
||||
svg { |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
table { |
||||
caption-side: bottom; |
||||
border-collapse: collapse; |
||||
} |
||||
|
||||
caption { |
||||
padding-top: 0.5rem; |
||||
padding-bottom: 0.5rem; |
||||
color: var(--bs-secondary-color); |
||||
text-align: left; |
||||
} |
||||
|
||||
th { |
||||
text-align: inherit; |
||||
text-align: -webkit-match-parent; |
||||
} |
||||
|
||||
thead, |
||||
tbody, |
||||
tfoot, |
||||
tr, |
||||
td, |
||||
th { |
||||
border-color: inherit; |
||||
border-style: solid; |
||||
border-width: 0; |
||||
} |
||||
|
||||
label { |
||||
display: inline-block; |
||||
} |
||||
|
||||
button { |
||||
border-radius: 0; |
||||
} |
||||
|
||||
button:focus:not(:focus-visible) { |
||||
outline: 0; |
||||
} |
||||
|
||||
input, |
||||
button, |
||||
select, |
||||
optgroup, |
||||
textarea { |
||||
margin: 0; |
||||
font-family: inherit; |
||||
font-size: inherit; |
||||
line-height: inherit; |
||||
} |
||||
|
||||
button, |
||||
select { |
||||
text-transform: none; |
||||
} |
||||
|
||||
[role=button] { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
select { |
||||
word-wrap: normal; |
||||
} |
||||
select:disabled { |
||||
opacity: 1; |
||||
} |
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator { |
||||
display: none !important; |
||||
} |
||||
|
||||
button, |
||||
[type=button], |
||||
[type=reset], |
||||
[type=submit] { |
||||
-webkit-appearance: button; |
||||
} |
||||
button:not(:disabled), |
||||
[type=button]:not(:disabled), |
||||
[type=reset]:not(:disabled), |
||||
[type=submit]:not(:disabled) { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
::-moz-focus-inner { |
||||
padding: 0; |
||||
border-style: none; |
||||
} |
||||
|
||||
textarea { |
||||
resize: vertical; |
||||
} |
||||
|
||||
fieldset { |
||||
min-width: 0; |
||||
padding: 0; |
||||
margin: 0; |
||||
border: 0; |
||||
} |
||||
|
||||
legend { |
||||
float: left; |
||||
width: 100%; |
||||
padding: 0; |
||||
margin-bottom: 0.5rem; |
||||
font-size: calc(1.275rem + 0.3vw); |
||||
line-height: inherit; |
||||
} |
||||
@media (min-width: 1200px) { |
||||
legend { |
||||
font-size: 1.5rem; |
||||
} |
||||
} |
||||
legend + * { |
||||
clear: left; |
||||
} |
||||
|
||||
::-webkit-datetime-edit-fields-wrapper, |
||||
::-webkit-datetime-edit-text, |
||||
::-webkit-datetime-edit-minute, |
||||
::-webkit-datetime-edit-hour-field, |
||||
::-webkit-datetime-edit-day-field, |
||||
::-webkit-datetime-edit-month-field, |
||||
::-webkit-datetime-edit-year-field { |
||||
padding: 0; |
||||
} |
||||
|
||||
::-webkit-inner-spin-button { |
||||
height: auto; |
||||
} |
||||
|
||||
[type=search] { |
||||
outline-offset: -2px; |
||||
-webkit-appearance: textfield; |
||||
} |
||||
|
||||
/* rtl:raw: |
||||
[type="tel"], |
||||
[type="url"], |
||||
[type="email"], |
||||
[type="number"] { |
||||
direction: ltr; |
||||
} |
||||
*/ |
||||
::-webkit-search-decoration { |
||||
-webkit-appearance: none; |
||||
} |
||||
|
||||
::-webkit-color-swatch-wrapper { |
||||
padding: 0; |
||||
} |
||||
|
||||
::-webkit-file-upload-button { |
||||
font: inherit; |
||||
-webkit-appearance: button; |
||||
} |
||||
|
||||
::file-selector-button { |
||||
font: inherit; |
||||
-webkit-appearance: button; |
||||
} |
||||
|
||||
output { |
||||
display: inline-block; |
||||
} |
||||
|
||||
iframe { |
||||
border: 0; |
||||
} |
||||
|
||||
summary { |
||||
display: list-item; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
progress { |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
[hidden] { |
||||
display: none !important; |
||||
} |
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */ |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,590 @@
|
||||
/*! |
||||
* Bootstrap Reboot v5.3.0 (https://getbootstrap.com/) |
||||
* Copyright 2011-2023 The Bootstrap Authors |
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
||||
*/ |
||||
:root, |
||||
[data-bs-theme=light] { |
||||
--bs-blue: #0d6efd; |
||||
--bs-indigo: #6610f2; |
||||
--bs-purple: #6f42c1; |
||||
--bs-pink: #d63384; |
||||
--bs-red: #dc3545; |
||||
--bs-orange: #fd7e14; |
||||
--bs-yellow: #ffc107; |
||||
--bs-green: #198754; |
||||
--bs-teal: #20c997; |
||||
--bs-cyan: #0dcaf0; |
||||
--bs-black: #000; |
||||
--bs-white: #fff; |
||||
--bs-gray: #6c757d; |
||||
--bs-gray-dark: #343a40; |
||||
--bs-gray-100: #f8f9fa; |
||||
--bs-gray-200: #e9ecef; |
||||
--bs-gray-300: #dee2e6; |
||||
--bs-gray-400: #ced4da; |
||||
--bs-gray-500: #adb5bd; |
||||
--bs-gray-600: #6c757d; |
||||
--bs-gray-700: #495057; |
||||
--bs-gray-800: #343a40; |
||||
--bs-gray-900: #212529; |
||||
--bs-primary: #0d6efd; |
||||
--bs-secondary: #6c757d; |
||||
--bs-success: #198754; |
||||
--bs-info: #0dcaf0; |
||||
--bs-warning: #ffc107; |
||||
--bs-danger: #dc3545; |
||||
--bs-light: #f8f9fa; |
||||
--bs-dark: #212529; |
||||
--bs-primary-rgb: 13, 110, 253; |
||||
--bs-secondary-rgb: 108, 117, 125; |
||||
--bs-success-rgb: 25, 135, 84; |
||||
--bs-info-rgb: 13, 202, 240; |
||||
--bs-warning-rgb: 255, 193, 7; |
||||
--bs-danger-rgb: 220, 53, 69; |
||||
--bs-light-rgb: 248, 249, 250; |
||||
--bs-dark-rgb: 33, 37, 41; |
||||
--bs-primary-text-emphasis: #052c65; |
||||
--bs-secondary-text-emphasis: #2b2f32; |
||||
--bs-success-text-emphasis: #0a3622; |
||||
--bs-info-text-emphasis: #055160; |
||||
--bs-warning-text-emphasis: #664d03; |
||||
--bs-danger-text-emphasis: #58151c; |
||||
--bs-light-text-emphasis: #495057; |
||||
--bs-dark-text-emphasis: #495057; |
||||
--bs-primary-bg-subtle: #cfe2ff; |
||||
--bs-secondary-bg-subtle: #e2e3e5; |
||||
--bs-success-bg-subtle: #d1e7dd; |
||||
--bs-info-bg-subtle: #cff4fc; |
||||
--bs-warning-bg-subtle: #fff3cd; |
||||
--bs-danger-bg-subtle: #f8d7da; |
||||
--bs-light-bg-subtle: #fcfcfd; |
||||
--bs-dark-bg-subtle: #ced4da; |
||||
--bs-primary-border-subtle: #9ec5fe; |
||||
--bs-secondary-border-subtle: #c4c8cb; |
||||
--bs-success-border-subtle: #a3cfbb; |
||||
--bs-info-border-subtle: #9eeaf9; |
||||
--bs-warning-border-subtle: #ffe69c; |
||||
--bs-danger-border-subtle: #f1aeb5; |
||||
--bs-light-border-subtle: #e9ecef; |
||||
--bs-dark-border-subtle: #adb5bd; |
||||
--bs-white-rgb: 255, 255, 255; |
||||
--bs-black-rgb: 0, 0, 0; |
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; |
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; |
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); |
||||
--bs-body-font-family: var(--bs-font-sans-serif); |
||||
--bs-body-font-size: 1rem; |
||||
--bs-body-font-weight: 400; |
||||
--bs-body-line-height: 1.5; |
||||
--bs-body-color: #212529; |
||||
--bs-body-color-rgb: 33, 37, 41; |
||||
--bs-body-bg: #fff; |
||||
--bs-body-bg-rgb: 255, 255, 255; |
||||
--bs-emphasis-color: #000; |
||||
--bs-emphasis-color-rgb: 0, 0, 0; |
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75); |
||||
--bs-secondary-color-rgb: 33, 37, 41; |
||||
--bs-secondary-bg: #e9ecef; |
||||
--bs-secondary-bg-rgb: 233, 236, 239; |
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5); |
||||
--bs-tertiary-color-rgb: 33, 37, 41; |
||||
--bs-tertiary-bg: #f8f9fa; |
||||
--bs-tertiary-bg-rgb: 248, 249, 250; |
||||
--bs-heading-color: inherit; |
||||
--bs-link-color: #0d6efd; |
||||
--bs-link-color-rgb: 13, 110, 253; |
||||
--bs-link-decoration: underline; |
||||
--bs-link-hover-color: #0a58ca; |
||||
--bs-link-hover-color-rgb: 10, 88, 202; |
||||
--bs-code-color: #d63384; |
||||
--bs-highlight-bg: #fff3cd; |
||||
--bs-border-width: 1px; |
||||
--bs-border-style: solid; |
||||
--bs-border-color: #dee2e6; |
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175); |
||||
--bs-border-radius: 0.375rem; |
||||
--bs-border-radius-sm: 0.25rem; |
||||
--bs-border-radius-lg: 0.5rem; |
||||
--bs-border-radius-xl: 1rem; |
||||
--bs-border-radius-xxl: 2rem; |
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl); |
||||
--bs-border-radius-pill: 50rem; |
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); |
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); |
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175); |
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075); |
||||
--bs-focus-ring-width: 0.25rem; |
||||
--bs-focus-ring-opacity: 0.25; |
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25); |
||||
--bs-form-valid-color: #198754; |
||||
--bs-form-valid-border-color: #198754; |
||||
--bs-form-invalid-color: #dc3545; |
||||
--bs-form-invalid-border-color: #dc3545; |
||||
} |
||||
|
||||
[data-bs-theme=dark] { |
||||
color-scheme: dark; |
||||
--bs-body-color: #adb5bd; |
||||
--bs-body-color-rgb: 173, 181, 189; |
||||
--bs-body-bg: #212529; |
||||
--bs-body-bg-rgb: 33, 37, 41; |
||||
--bs-emphasis-color: #fff; |
||||
--bs-emphasis-color-rgb: 255, 255, 255; |
||||
--bs-secondary-color: rgba(173, 181, 189, 0.75); |
||||
--bs-secondary-color-rgb: 173, 181, 189; |
||||
--bs-secondary-bg: #343a40; |
||||
--bs-secondary-bg-rgb: 52, 58, 64; |
||||
--bs-tertiary-color: rgba(173, 181, 189, 0.5); |
||||
--bs-tertiary-color-rgb: 173, 181, 189; |
||||
--bs-tertiary-bg: #2b3035; |
||||
--bs-tertiary-bg-rgb: 43, 48, 53; |
||||
--bs-primary-text-emphasis: #6ea8fe; |
||||
--bs-secondary-text-emphasis: #a7acb1; |
||||
--bs-success-text-emphasis: #75b798; |
||||
--bs-info-text-emphasis: #6edff6; |
||||
--bs-warning-text-emphasis: #ffda6a; |
||||
--bs-danger-text-emphasis: #ea868f; |
||||
--bs-light-text-emphasis: #f8f9fa; |
||||
--bs-dark-text-emphasis: #dee2e6; |
||||
--bs-primary-bg-subtle: #031633; |
||||
--bs-secondary-bg-subtle: #161719; |
||||
--bs-success-bg-subtle: #051b11; |
||||
--bs-info-bg-subtle: #032830; |
||||
--bs-warning-bg-subtle: #332701; |
||||
--bs-danger-bg-subtle: #2c0b0e; |
||||
--bs-light-bg-subtle: #343a40; |
||||
--bs-dark-bg-subtle: #1a1d20; |
||||
--bs-primary-border-subtle: #084298; |
||||
--bs-secondary-border-subtle: #41464b; |
||||
--bs-success-border-subtle: #0f5132; |
||||
--bs-info-border-subtle: #087990; |
||||
--bs-warning-border-subtle: #997404; |
||||
--bs-danger-border-subtle: #842029; |
||||
--bs-light-border-subtle: #495057; |
||||
--bs-dark-border-subtle: #343a40; |
||||
--bs-heading-color: inherit; |
||||
--bs-link-color: #6ea8fe; |
||||
--bs-link-hover-color: #8bb9fe; |
||||
--bs-link-color-rgb: 110, 168, 254; |
||||
--bs-link-hover-color-rgb: 139, 185, 254; |
||||
--bs-code-color: #e685b5; |
||||
--bs-border-color: #495057; |
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15); |
||||
--bs-form-valid-color: #75b798; |
||||
--bs-form-valid-border-color: #75b798; |
||||
--bs-form-invalid-color: #ea868f; |
||||
--bs-form-invalid-border-color: #ea868f; |
||||
} |
||||
|
||||
*, |
||||
*::before, |
||||
*::after { |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
@media (prefers-reduced-motion: no-preference) { |
||||
:root { |
||||
scroll-behavior: smooth; |
||||
} |
||||
} |
||||
|
||||
body { |
||||
margin: 0; |
||||
font-family: var(--bs-body-font-family); |
||||
font-size: var(--bs-body-font-size); |
||||
font-weight: var(--bs-body-font-weight); |
||||
line-height: var(--bs-body-line-height); |
||||
color: var(--bs-body-color); |
||||
text-align: var(--bs-body-text-align); |
||||
background-color: var(--bs-body-bg); |
||||
-webkit-text-size-adjust: 100%; |
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
||||
} |
||||
|
||||
hr { |
||||
margin: 1rem 0; |
||||
color: inherit; |
||||
border: 0; |
||||
border-top: var(--bs-border-width) solid; |
||||
opacity: 0.25; |
||||
} |
||||
|
||||
h6, h5, h4, h3, h2, h1 { |
||||
margin-top: 0; |
||||
margin-bottom: 0.5rem; |
||||
font-weight: 500; |
||||
line-height: 1.2; |
||||
color: var(--bs-heading-color); |
||||
} |
||||
|
||||
h1 { |
||||
font-size: calc(1.375rem + 1.5vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h1 { |
||||
font-size: 2.5rem; |
||||
} |
||||
} |
||||
|
||||
h2 { |
||||
font-size: calc(1.325rem + 0.9vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h2 { |
||||
font-size: 2rem; |
||||
} |
||||
} |
||||
|
||||
h3 { |
||||
font-size: calc(1.3rem + 0.6vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h3 { |
||||
font-size: 1.75rem; |
||||
} |
||||
} |
||||
|
||||
h4 { |
||||
font-size: calc(1.275rem + 0.3vw); |
||||
} |
||||
@media (min-width: 1200px) { |
||||
h4 { |
||||
font-size: 1.5rem; |
||||
} |
||||
} |
||||
|
||||
h5 { |
||||
font-size: 1.25rem; |
||||
} |
||||
|
||||
h6 { |
||||
font-size: 1rem; |
||||
} |
||||
|
||||
p { |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
} |
||||
|
||||
abbr[title] { |
||||
-webkit-text-decoration: underline dotted; |
||||
text-decoration: underline dotted; |
||||
cursor: help; |
||||
-webkit-text-decoration-skip-ink: none; |
||||
text-decoration-skip-ink: none; |
||||
} |
||||
|
||||
address { |
||||
margin-bottom: 1rem; |
||||
font-style: normal; |
||||
line-height: inherit; |
||||
} |
||||
|
||||
ol, |
||||
ul { |
||||
padding-right: 2rem; |
||||
} |
||||
|
||||
ol, |
||||
ul, |
||||
dl { |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
} |
||||
|
||||
ol ol, |
||||
ul ul, |
||||
ol ul, |
||||
ul ol { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
dt { |
||||
font-weight: 700; |
||||
} |
||||
|
||||
dd { |
||||
margin-bottom: 0.5rem; |
||||
margin-right: 0; |
||||
} |
||||
|
||||
blockquote { |
||||
margin: 0 0 1rem; |
||||
} |
||||
|
||||
b, |
||||
strong { |
||||
font-weight: bolder; |
||||
} |
||||
|
||||
small { |
||||
font-size: 0.875em; |
||||
} |
||||
|
||||
mark { |
||||
padding: 0.1875em; |
||||
background-color: var(--bs-highlight-bg); |
||||
} |
||||
|
||||
sub, |
||||
sup { |
||||
position: relative; |
||||
font-size: 0.75em; |
||||
line-height: 0; |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
sub { |
||||
bottom: -0.25em; |
||||
} |
||||
|
||||
sup { |
||||
top: -0.5em; |
||||
} |
||||
|
||||
a { |
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)); |
||||
text-decoration: underline; |
||||
} |
||||
a:hover { |
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb); |
||||
} |
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover { |
||||
color: inherit; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
pre, |
||||
code, |
||||
kbd, |
||||
samp { |
||||
font-family: var(--bs-font-monospace); |
||||
font-size: 1em; |
||||
} |
||||
|
||||
pre { |
||||
display: block; |
||||
margin-top: 0; |
||||
margin-bottom: 1rem; |
||||
overflow: auto; |
||||
font-size: 0.875em; |
||||
} |
||||
pre code { |
||||
font-size: inherit; |
||||
color: inherit; |
||||
word-break: normal; |
||||
} |
||||
|
||||
code { |
||||
font-size: 0.875em; |
||||
color: var(--bs-code-color); |
||||
word-wrap: break-word; |
||||
} |
||||
a > code { |
||||
color: inherit; |
||||
} |
||||
|
||||
kbd { |
||||
padding: 0.1875rem 0.375rem; |
||||
font-size: 0.875em; |
||||
color: var(--bs-body-bg); |
||||
background-color: var(--bs-body-color); |
||||
border-radius: 0.25rem; |
||||
} |
||||
kbd kbd { |
||||
padding: 0; |
||||
font-size: 1em; |
||||
} |
||||
|
||||
figure { |
||||
margin: 0 0 1rem; |
||||
} |
||||
|
||||
img, |
||||
svg { |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
table { |
||||
caption-side: bottom; |
||||
border-collapse: collapse; |
||||
} |
||||
|
||||
caption { |
||||
padding-top: 0.5rem; |
||||
padding-bottom: 0.5rem; |
||||
color: var(--bs-secondary-color); |
||||
text-align: right; |
||||
} |
||||
|
||||
th { |
||||
text-align: inherit; |
||||
text-align: -webkit-match-parent; |
||||
} |
||||
|
||||
thead, |
||||
tbody, |
||||
tfoot, |
||||
tr, |
||||
td, |
||||
th { |
||||
border-color: inherit; |
||||
border-style: solid; |
||||
border-width: 0; |
||||
} |
||||
|
||||
label { |
||||
display: inline-block; |
||||
} |
||||
|
||||
button { |
||||
border-radius: 0; |
||||
} |
||||
|
||||
button:focus:not(:focus-visible) { |
||||
outline: 0; |
||||
} |
||||
|
||||
input, |
||||
button, |
||||
select, |
||||
optgroup, |
||||
textarea { |
||||
margin: 0; |
||||
font-family: inherit; |
||||
font-size: inherit; |
||||
line-height: inherit; |
||||
} |
||||
|
||||
button, |
||||
select { |
||||
text-transform: none; |
||||
} |
||||
|
||||
[role=button] { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
select { |
||||
word-wrap: normal; |
||||
} |
||||
select:disabled { |
||||
opacity: 1; |
||||
} |
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator { |
||||
display: none !important; |
||||
} |
||||
|
||||
button, |
||||
[type=button], |
||||
[type=reset], |
||||
[type=submit] { |
||||
-webkit-appearance: button; |
||||
} |
||||
button:not(:disabled), |
||||
[type=button]:not(:disabled), |
||||
[type=reset]:not(:disabled), |
||||
[type=submit]:not(:disabled) { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
::-moz-focus-inner { |
||||
padding: 0; |
||||
border-style: none; |
||||
} |
||||
|
||||
textarea { |
||||
resize: vertical; |
||||
} |
||||
|
||||
fieldset { |
||||
min-width: 0; |
||||
padding: 0; |
||||
margin: 0; |
||||
border: 0; |
||||
} |
||||
|
||||
legend { |
||||
float: right; |
||||
width: 100%; |
||||
padding: 0; |
||||
margin-bottom: 0.5rem; |
||||
font-size: calc(1.275rem + 0.3vw); |
||||
line-height: inherit; |
||||
} |
||||
@media (min-width: 1200px) { |
||||
legend { |
||||
font-size: 1.5rem; |
||||
} |
||||
} |
||||
legend + * { |
||||
clear: right; |
||||
} |
||||
|
||||
::-webkit-datetime-edit-fields-wrapper, |
||||
::-webkit-datetime-edit-text, |
||||
::-webkit-datetime-edit-minute, |
||||
::-webkit-datetime-edit-hour-field, |
||||
::-webkit-datetime-edit-day-field, |
||||
::-webkit-datetime-edit-month-field, |
||||
::-webkit-datetime-edit-year-field { |
||||
padding: 0; |
||||
} |
||||
|
||||
::-webkit-inner-spin-button { |
||||
height: auto; |
||||
} |
||||
|
||||
[type=search] { |
||||
outline-offset: -2px; |
||||
-webkit-appearance: textfield; |
||||
} |
||||
|
||||
[type="tel"], |
||||
[type="url"], |
||||
[type="email"], |
||||
[type="number"] { |
||||
direction: ltr; |
||||
} |
||||
::-webkit-search-decoration { |
||||
-webkit-appearance: none; |
||||
} |
||||
|
||||
::-webkit-color-swatch-wrapper { |
||||
padding: 0; |
||||
} |
||||
|
||||
::-webkit-file-upload-button { |
||||
font: inherit; |
||||
-webkit-appearance: button; |
||||
} |
||||
|
||||
::file-selector-button { |
||||
font: inherit; |
||||
-webkit-appearance: button; |
||||
} |
||||
|
||||
output { |
||||
display: inline-block; |
||||
} |
||||
|
||||
iframe { |
||||
border: 0; |
||||
} |
||||
|
||||
summary { |
||||
display: list-item; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
progress { |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
[hidden] { |
||||
display: none !important; |
||||
} |
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */ |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 15 KiB |
Loading…
Reference in new issue