Compare commits
No commits in common. "5b1f20c5bcf157990d5ec2fa15b28311889f31b9" and "d0c566f8df147cb6a827bcde76fb9a76577f40f3" have entirely different histories.
5b1f20c5bc
...
d0c566f8df
@ -5,10 +5,8 @@ tmp_dir = "tmp"
|
|||||||
[build]
|
[build]
|
||||||
args_bin = [
|
args_bin = [
|
||||||
"-articles tmp/articles",
|
"-articles tmp/articles",
|
||||||
"-config tmp/config.toml",
|
|
||||||
"-desc 'Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität'",
|
"-desc 'Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität'",
|
||||||
"-domain localhost",
|
"-domain localhost",
|
||||||
"-firebase tmp/firebase.json",
|
|
||||||
"-key tmp/key.gob",
|
"-key tmp/key.gob",
|
||||||
"-link https://distrikt-ni-st.de",
|
"-link https://distrikt-ni-st.de",
|
||||||
"-log tmp/cpolis.log",
|
"-log tmp/cpolis.log",
|
||||||
|
@ -3,7 +3,6 @@ package backend
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -13,7 +12,6 @@ import (
|
|||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ArticleDir string
|
ArticleDir string
|
||||||
ConfigFile string
|
|
||||||
DBName string
|
DBName string
|
||||||
Description string
|
Description string
|
||||||
Domain string
|
Domain string
|
||||||
@ -32,72 +30,56 @@ type Config struct {
|
|||||||
func newConfig() *Config {
|
func newConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
ArticleDir: "/var/www/cpolis/articles",
|
ArticleDir: "/var/www/cpolis/articles",
|
||||||
ConfigFile: "/etc/cpolis/config.toml",
|
|
||||||
DBName: "cpolis",
|
DBName: "cpolis",
|
||||||
FirebaseKey: "/var/www/cpolis/serviceAccountKey.json",
|
FirebaseKey: "/var/www/cpolis/serviceAccountKey.json",
|
||||||
KeyFile: "/var/www/cpolis/cpolis.key",
|
KeyFile: "/var/www/cpolis/cpolis.key",
|
||||||
LogFile: "/var/log/cpolis.log",
|
LogFile: "/var/log/cpolis.log",
|
||||||
PDFDir: "/var/www/cpolis/pdfs",
|
PDFDir: "/var/www/cpolis/pdfs",
|
||||||
Port: ":8080",
|
|
||||||
PicsDir: "/var/www/cpolis/pics",
|
PicsDir: "/var/www/cpolis/pics",
|
||||||
RSSFile: "/var/www/cpolis/cpolis.rss",
|
RSSFile: "/var/www/cpolis/cpolis.rss",
|
||||||
WebDir: "/var/www/cpolis/web",
|
WebDir: "/var/www/cpolis/web",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkDir(path string, perm fs.FileMode) (string, error) {
|
func (c *Config) readFile() error {
|
||||||
var err error
|
cfgFile, err := filepath.Abs(os.Getenv("HOME") + "/.config/cpolis/config.toml")
|
||||||
|
|
||||||
stringSlice := strings.Split(path, "/")
|
|
||||||
name := stringSlice[len(stringSlice)-1]
|
|
||||||
|
|
||||||
path, err = filepath.Abs(path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error finding absolute path for %v directory: %v", name, err)
|
return fmt.Errorf("error getting absolute path for config file: %v", err)
|
||||||
}
|
|
||||||
if err = os.MkdirAll(path, perm); err != nil {
|
|
||||||
return "", fmt.Errorf("error creating %v directory: %v", name, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return path, nil
|
_, err = os.Stat(cfgFile)
|
||||||
}
|
|
||||||
|
|
||||||
func mkFile(path string, filePerm, dirPerm fs.FileMode) (string, error) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
path, err = filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("error finding absolute path for %v: %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
stringSlice := strings.Split(path, "/")
|
|
||||||
_, err = os.Stat(path)
|
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
dir := strings.Join(stringSlice[:len(stringSlice)-1], "/")
|
fileStrings := strings.Split(cfgFile, "/")
|
||||||
if err = os.MkdirAll(dir, dirPerm); err != nil {
|
|
||||||
return "", fmt.Errorf("error creating %v: %v", dir, err)
|
dir := strings.Join(fileStrings[0:len(fileStrings)-1], "/")
|
||||||
|
if err = os.MkdirAll(dir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("error creating config directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName := stringSlice[len(stringSlice)-1]
|
fileName := fileStrings[len(fileStrings)-1]
|
||||||
file, err := os.Create(dir + "/" + fileName)
|
file, err := os.Create(dir + "/" + fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error creating %v: %v", fileName, err)
|
return fmt.Errorf("error creating config file: %v", err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
if err = file.Chmod(filePerm); err != nil {
|
if err = file.Chmod(0644); err != nil {
|
||||||
return "", fmt.Errorf("error setting permissions for %v: %v", fileName, err)
|
return fmt.Errorf("error setting permissions for config file: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err = toml.DecodeFile(cfgFile, c)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error reading config file: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return path, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) handleCliArgs() error {
|
func (c *Config) handleCliArgs() error {
|
||||||
var port int
|
|
||||||
var err error
|
var err error
|
||||||
|
port := 8080
|
||||||
|
|
||||||
flag.StringVar(&c.ArticleDir, "articles", c.ArticleDir, "articles directory")
|
flag.StringVar(&c.ArticleDir, "articles", c.ArticleDir, "articles directory")
|
||||||
flag.StringVar(&c.ConfigFile, "config", c.ConfigFile, "config file")
|
|
||||||
flag.StringVar(&c.DBName, "db", c.DBName, "DB name")
|
flag.StringVar(&c.DBName, "db", c.DBName, "DB name")
|
||||||
flag.StringVar(&c.Description, "desc", c.Description, "channel description")
|
flag.StringVar(&c.Description, "desc", c.Description, "channel description")
|
||||||
flag.StringVar(&c.Domain, "domain", c.Domain, "domain name")
|
flag.StringVar(&c.Domain, "domain", c.Domain, "domain name")
|
||||||
@ -113,114 +95,58 @@ func (c *Config) handleCliArgs() error {
|
|||||||
flag.IntVar(&port, "port", port, "port")
|
flag.IntVar(&port, "port", port, "port")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
c.ArticleDir, err = filepath.Abs(c.ArticleDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error finding absolute path for articles directory: %v", err)
|
||||||
|
}
|
||||||
|
if err = os.MkdirAll(c.ArticleDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("error creating articles directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.FirebaseKey, err = filepath.Abs(c.FirebaseKey)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error finding absolute path for Firebase service account key file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.KeyFile, err = filepath.Abs(c.KeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error finding absolute path for key file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.LogFile, err = filepath.Abs(c.LogFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error finding absolute path for log file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.PDFDir, err = filepath.Abs(c.PDFDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error finding absolute path for pdfs directory: %v", err)
|
||||||
|
}
|
||||||
|
if err = os.MkdirAll(c.PDFDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("error creating pdfs directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.PicsDir, err = filepath.Abs(c.PicsDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error finding absolute path for pics directory: %v", err)
|
||||||
|
}
|
||||||
|
if err = os.MkdirAll(c.PicsDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("error creating pics directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
c.Port = fmt.Sprint(":", port)
|
c.Port = fmt.Sprint(":", port)
|
||||||
c.ConfigFile, err = mkFile(c.ConfigFile, 0600, 0700)
|
|
||||||
|
c.RSSFile, err = filepath.Abs(c.RSSFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error setting up file: %v", err)
|
return fmt.Errorf("error finding absolute path for RSS file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
c.WebDir, err = filepath.Abs(c.WebDir)
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) handleFile(configFile string) error {
|
|
||||||
_, err := toml.DecodeFile(configFile, c)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error reading config file: %v", err)
|
return fmt.Errorf("error finding absolute path for web directory: %v", err)
|
||||||
}
|
}
|
||||||
|
if err = os.MkdirAll(c.WebDir, 0755); err != nil {
|
||||||
return nil
|
return fmt.Errorf("error creating web directory: %v", err)
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) setupConfig(cliConfig *Config) error {
|
|
||||||
var err error
|
|
||||||
defaultConfig := newConfig()
|
|
||||||
|
|
||||||
if cliConfig.ArticleDir != defaultConfig.ArticleDir {
|
|
||||||
c.ArticleDir = cliConfig.ArticleDir
|
|
||||||
}
|
|
||||||
c.ArticleDir, err = mkDir(c.ArticleDir, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.DBName != defaultConfig.DBName {
|
|
||||||
c.DBName = cliConfig.DBName
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.Description != defaultConfig.Description {
|
|
||||||
c.Description = cliConfig.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.Domain != defaultConfig.Domain {
|
|
||||||
c.Domain = cliConfig.Domain
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.FirebaseKey != defaultConfig.FirebaseKey {
|
|
||||||
c.FirebaseKey = cliConfig.FirebaseKey
|
|
||||||
}
|
|
||||||
c.FirebaseKey, err = mkFile(c.FirebaseKey, 0600, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.KeyFile != defaultConfig.KeyFile {
|
|
||||||
c.KeyFile = cliConfig.KeyFile
|
|
||||||
}
|
|
||||||
c.KeyFile, err = mkFile(c.KeyFile, 0600, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.Link != defaultConfig.Link {
|
|
||||||
c.Link = cliConfig.Link
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.LogFile != defaultConfig.LogFile {
|
|
||||||
c.LogFile = cliConfig.LogFile
|
|
||||||
}
|
|
||||||
c.LogFile, err = mkFile(c.LogFile, 0600, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.PDFDir != defaultConfig.PDFDir {
|
|
||||||
c.PDFDir = cliConfig.PDFDir
|
|
||||||
}
|
|
||||||
c.PDFDir, err = mkDir(c.PDFDir, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.PicsDir != defaultConfig.PicsDir {
|
|
||||||
c.PicsDir = cliConfig.PicsDir
|
|
||||||
}
|
|
||||||
c.PicsDir, err = mkDir(c.PicsDir, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.Port != defaultConfig.Port {
|
|
||||||
c.Port = cliConfig.Port
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.RSSFile != defaultConfig.RSSFile {
|
|
||||||
c.RSSFile = cliConfig.RSSFile
|
|
||||||
}
|
|
||||||
c.RSSFile, err = mkFile(c.RSSFile, 0600, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.Title != defaultConfig.Title {
|
|
||||||
c.Title = cliConfig.Title
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliConfig.WebDir != defaultConfig.WebDir {
|
|
||||||
c.WebDir = cliConfig.WebDir
|
|
||||||
}
|
|
||||||
c.WebDir, err = mkDir(c.WebDir, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting up directory: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -228,20 +154,14 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
|||||||
|
|
||||||
func HandleConfig() (*Config, error) {
|
func HandleConfig() (*Config, error) {
|
||||||
config := newConfig()
|
config := newConfig()
|
||||||
cliConfig := newConfig()
|
|
||||||
|
|
||||||
if err := cliConfig.handleCliArgs(); err != nil {
|
if err := config.readFile(); err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading config file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.handleCliArgs(); err != nil {
|
||||||
return nil, fmt.Errorf("error handling cli arguments: %v", err)
|
return nil, fmt.Errorf("error handling cli arguments: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := config.handleFile(cliConfig.ConfigFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error reading configuration file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = config.setupConfig(cliConfig); err != nil {
|
|
||||||
return nil, fmt.Errorf("error setting up files: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,4 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
require('@tailwindcss/typography')
|
require('@tailwindcss/typography')
|
||||||
],
|
],
|
||||||
darkMode: 'selector',
|
|
||||||
}
|
}
|
||||||
|
@ -2,21 +2,30 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 800px;
|
||||||
|
@apply mx-auto text-slate-900;
|
||||||
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@apply font-bold mb-2 text-2xl;
|
@apply font-bold mb-2 text-2xl;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
form {
|
||||||
@apply font-bold mb-2 text-xl;
|
@apply flex flex-col gap-y-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="file"] {
|
||||||
|
@apply border rounded-md w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="password"],
|
input[type="password"],
|
||||||
input[type="text"] {
|
input[type="text"] {
|
||||||
@apply bg-slate-50 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 h-8 rounded-md;
|
@apply border h-8 rounded-md;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
@apply bg-slate-50 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 h-32 rounded-md;
|
@apply border h-32 rounded-md;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-area {
|
.btn-area {
|
||||||
@ -24,41 +33,9 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
@apply bg-slate-200 dark:bg-slate-800 hover:bg-slate-100 dark:hover:bg-slate-900 border border-slate-200 dark:border-slate-800 my-2 px-3 py-2 rounded-md w-full;
|
@apply bg-slate-200 border my-2 px-3 py-2 rounded-md w-full hover:bg-slate-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
@apply bg-slate-800 dark:bg-slate-200 hover:bg-slate-700 dark:hover:bg-slate-300 my-2 px-3 py-2 rounded-md text-slate-50 dark:text-slate-950 w-full;
|
@apply bg-slate-800 border my-2 px-3 py-2 rounded-md text-slate-50 w-full hover:bg-slate-700;
|
||||||
}
|
|
||||||
|
|
||||||
.EasyMDEContainer .CodeMirror {
|
|
||||||
@apply bg-slate-50 dark:bg-slate-950 border-slate-200 dark:border-slate-800 text-slate-900 dark:text-slate-100
|
|
||||||
}
|
|
||||||
|
|
||||||
.EasyMDEContainer .cm-s-easymde .CodeMirror-cursor {
|
|
||||||
@apply border-slate-900 dark:border-slate-100
|
|
||||||
}
|
|
||||||
|
|
||||||
.EasyMDEContainer .editor-toolbar > * {
|
|
||||||
@apply text-slate-900 dark:text-slate-100
|
|
||||||
}
|
|
||||||
|
|
||||||
.EasyMDEContainer .editor-toolbar > .active, .editor-toolbar > button:hover, .editor-preview pre, .cm-s-easymde .cm-comment {
|
|
||||||
@apply bg-slate-100 dark:bg-slate-900
|
|
||||||
}
|
|
||||||
|
|
||||||
.EasyMDEContainer .CodeMirror-fullscreen {
|
|
||||||
@apply bg-slate-50 dark:bg-slate-950
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-toolbar {
|
|
||||||
@apply border border-slate-200
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-toolbar.fullscreen {
|
|
||||||
@apply bg-slate-50 dark:bg-slate-950
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-preview {
|
|
||||||
@apply bg-slate-50 dark:bg-slate-950
|
|
||||||
}
|
}
|
||||||
|
@ -4,49 +4,49 @@
|
|||||||
|
|
||||||
{{if lt . 4}}
|
{{if lt . 4}}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h2>Artikel</h2>
|
<h2>Autor</h2>
|
||||||
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
|
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||||
<button class="btn" hx-get="/article/write" hx-target="#page-content">Artikel schreiben</button>
|
<button class="btn" hx-get="/article/write" hx-target="#page-content">Artikel schreiben</button>
|
||||||
<button class="btn" hx-get="/article/all-rejected" hx-target="#page-content">Abgelehnte Artikel</button>
|
<button class="btn" hx-get="/article/all-rejected" hx-target="#page-content">Abgelehnte Artikel</button>
|
||||||
{{if lt . 3}}<button class="btn" hx-get="/article/all-unpublished" hx-target="#page-content">
|
<button class="btn" hx-get="/user/edit/self" hx-target="#page-content">Profil bearbeiten</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if lt . 3}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<h2>Redakteur</h2>
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||||
|
<button class="btn" hx-get="/article/all-unpublished" hx-target="#page-content">
|
||||||
Unveröffentlichte Artikel
|
Unveröffentlichte Artikel
|
||||||
</button>{{end}}
|
</button>
|
||||||
{{if lt . 2}}<button class="btn" hx-get="/article/all-published" hx-target="#page-content">
|
<button class="btn" hx-get="/tag/create" hx-target="#page-content">Neuer Tag</button>
|
||||||
Artikel löschen
|
|
||||||
</button>{{end}}
|
|
||||||
{{if lt . 3}}<button class="btn" hx-get="/tag/create" hx-target="#page-content">Neuer Tag</button>{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if lt . 2}}
|
{{if lt . 2}}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h2>Ausgabe</h2>
|
<h2>Herausgeber</h2>
|
||||||
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
|
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||||
<button class="btn" hx-get="/issue/this" hx-target="#page-content">Diese Ausgabe</button>
|
<button class="btn" hx-get="/issue/this" hx-target="#page-content">Diese Ausgabe</button>
|
||||||
|
<button class="btn" hx-get="/article/all-published" hx-target="#page-content">Artikel löschen</button>
|
||||||
<form class="flex" hx-encoding="multipart/form-data">
|
<form class="flex" hx-encoding="multipart/form-data">
|
||||||
<label class="btn text-center" for="pdf-upload">PDF hochladen</label>
|
<label class="btn text-center" for="pdf-upload">PDF hochladen</label>
|
||||||
<input accept=".pdf" class="hidden" id="pdf-upload" name="pdf-upload" type="file"
|
<input accept=".pdf" class="hidden" id="pdf-upload" name="pdf-upload" type="file"
|
||||||
hx-post="/pdf/upload" />
|
hx-post="/pdf/upload" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if lt . 4}}
|
{{if eq . 0}}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h2>Benutzer</h2>
|
<h2>Administrator</h2>
|
||||||
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
|
<div class="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||||
<button class="btn" hx-get="/user/edit/self" hx-target="#page-content">Mein Profil bearbeiten</button>
|
<button class="btn" hx-get="/user/create" hx-target="#page-content">Benutzer hinzufügen</button>
|
||||||
{{if eq . 0}}<button class="btn" hx-get="/user/create" hx-target="#page-content">
|
<button class="btn" hx-get="/user/show-all/edit" hx-target="#page-content">Benutzer bearbeiten</button>
|
||||||
Benutzer hinzufügen
|
<button class="btn" hx-get="/user/show-all/delete" hx-target="#page-content">Benutzer löschen</button>
|
||||||
</button>{{end}}
|
|
||||||
{{if eq . 0}}<button class="btn" hx-get="/user/show-all/edit" hx-target="#page-content">
|
|
||||||
Benutzer bearbeiten
|
|
||||||
</button>{{end}}
|
|
||||||
{{if eq . 0}}<button class="btn" hx-get="/user/show-all/delete" hx-target="#page-content">
|
|
||||||
Benutzer löschen
|
|
||||||
</button>{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -5,26 +5,13 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Orient Editor</title>
|
<title>Orient Editor</title>
|
||||||
|
|
||||||
<link href="/web/static/css/style.css" rel="stylesheet">
|
<link href="/web/static/css/style.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css">
|
<link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="width: 800px;"
|
<body class="flex flex-col justify-between min-h-screen bg-slate-50">
|
||||||
class="bg-slate-50 dark:bg-slate-950 flex flex-col justify-between min-h-screen mx-auto text-slate-900 dark:text-slate-100">
|
|
||||||
<header class="my-8">
|
<header class="my-8">
|
||||||
<h1 class="font-bold text-4xl text-center">Orient Editor</h1>
|
<h1 class="font-bold text-4xl text-center">Orient Editor</h1>
|
||||||
|
|
||||||
<div class="ml-4">
|
|
||||||
<label class="cursor-pointer flex items-center relative" for="theme-toggle">
|
|
||||||
<div class="bg-slate-200 dark:bg-slate-800 block h-6 w-12 rounded-full"></div>
|
|
||||||
<div
|
|
||||||
class="absolute bg-slate-800 dark:bg-slate-50 dot left-1 top-1 h-4 w-4 rounded-full transform transition">
|
|
||||||
</div>
|
|
||||||
<span class="ml-2">Dunkel</span>
|
|
||||||
</label>
|
|
||||||
<input type="checkbox" id="theme-toggle" class="sr-only">
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="mx-4">
|
<main class="mx-4">
|
||||||
@ -33,44 +20,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="text-center text-gray-500 my-8">
|
<footer class="text-center text-gray-500 dark:text-gray-400 my-8">
|
||||||
<p>
|
<p>
|
||||||
© 2024 Jason Streifling. Alle Rechte vorbehalten.
|
© 2024 Jason Streifling. Alle Rechte vorbehalten.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
v0.9.0 - <strong>Hinweis:</strong> Diese Software befindet sich noch in der Entwicklung und kann Fehler
|
v0.8.3 - <strong>Hinweis:</strong> Diese Software befindet sich noch in der Entwicklung und kann Fehler
|
||||||
enthalten.
|
enthalten.
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="https://unpkg.com/htmx.org@2.0.2"></script>
|
<script src="https://unpkg.com/htmx.org@2.0.2"></script>
|
||||||
<script src="https://unpkg.com/easymde/dist/easymde.min.js"></script>
|
<script src="https://unpkg.com/easymde/dist/easymde.min.js"></script>
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const toggleSwitch = document.getElementById('theme-toggle');
|
|
||||||
const dot = document.querySelector('.dot');
|
|
||||||
|
|
||||||
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
|
||||||
document.documentElement.classList.add('dark')
|
|
||||||
toggleSwitch.checked = true;
|
|
||||||
dot.classList.add('translate-x-6');
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.remove('dark')
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSwitch.addEventListener('change', () => {
|
|
||||||
if (toggleSwitch.checked) {
|
|
||||||
document.documentElement.classList.add('dark');
|
|
||||||
localStorage.theme = 'dark';
|
|
||||||
dot.classList.add('translate-x-6');
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.remove('dark');
|
|
||||||
localStorage.theme = 'light';
|
|
||||||
dot.classList.remove('translate-x-6');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user