add dashbord and right colomn right page

This commit is contained in:
bruno 2022-10-27 13:10:16 -04:00
parent ff3011de69
commit 9a7d23d24d
15 changed files with 763 additions and 463 deletions

0
.nimble Normal file
View File

View File

@ -26,11 +26,11 @@ proc generateDB*() =
# Load the connection details
let
dict = loadConfig("config/config.cfg")
db_user = dict.getSectionValue("Database","user")
db_pass = dict.getSectionValue("Database","pass")
db_name = dict.getSectionValue("Database","name")
db_host = dict.getSectionValue("Database","host")
db_folder = dict.getSectionValue("Database","folder")
db_user = dict.getSectionValue("Database", "user")
db_pass = dict.getSectionValue("Database", "pass")
db_name = dict.getSectionValue("Database", "name")
db_host = dict.getSectionValue("Database", "host")
db_folder = dict.getSectionValue("Database", "folder")
dbexists = if fileExists(db_host): true else: false
if dbexists:
@ -41,7 +41,8 @@ proc generateDB*() =
# Open DB
echo " - Opening database"
var db = open(connection=db_host, user=db_user, password=db_pass, database=db_name)
var db = open(connection = db_host, user = db_user, password = db_pass,
database = db_name)
# Person table contains information about the
# registrered users
@ -74,6 +75,20 @@ proc generateDB*() =
);""")):
echo " - Database: session table already exists"
# Sesion table contains information about the search
#
if not db.tryExec(sql("""
create table if not exists search(
id integer primary key,
search_title varchar(300) not null,
query varchar(300) not null,
search_type varchar(100) not null,
creation timestamp not null default (STRFTIME('%s', 'now')),
lastModified timestamp not null default (STRFTIME('%s', 'now')),
foreign key (userid) references person(id)
);""")):
echo " - Database: search table already exists"
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : Create Administrator User
@ -108,7 +123,8 @@ proc createAdminUser*(db: DbConn, args: seq[string]) =
let password = makePassword(iPwd, salt)
# Insert user into database
if insertID(db, sql"INSERT INTO person (name, email, password, salt, status) VALUES (?, ?, ?, ?, ?)", $iName, $iEmail, password, salt, "Admin") > 0:
if insertID(db, sql"INSERT INTO person (name, email, password, salt, status) VALUES (?, ?, ?, ?, ?)",
$iName, $iEmail, password, salt, "Admin") > 0:
echo "Admin user added"
else:
error("Something went wrong")

View File

@ -15,10 +15,13 @@ import std/json
import httpcore
import strutils
import strformat
import std/times
import std/options
import std/httpclient
import std/asyncdispatch
import utils # Joplin utils procedures and types
from os import sleep
from posix import read, write, fdatasync, close
@ -37,7 +40,8 @@ type
type
joplin_tags* = object
id*, parent_id*, title*: seq[string]
created_time*, updated_time*, user_created_time*, user_updated_time*, is_shared*: seq[int]
created_time*, updated_time*, user_created_time*, user_updated_time*,
is_shared*: seq[int]
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
@ -46,7 +50,8 @@ type
type
joplin_notebooks* = object
id*, parent_id*, title*, share_id*, icon*: seq[string]
created_time*, updated_time*, user_created_time*, user_updated_time*, is_shared*: seq[int]
created_time*, updated_time*, user_created_time*, user_updated_time*,
is_shared*: seq[int]
req*: Request
@ -55,9 +60,28 @@ type
# --==--==--==--==--==--==--==--==--==--==-- #
type
joplin_notes* = object
id*, parent_id*, title*, body*, author*, source_url*, source*, source_application*, application_data*, share_id*, conflict_original_id*, body_html*, base_url*: seq[string]
created_time*, updated_time*, is_conflict*, is_todo*, todo_due*, todo_completed*, user_created_time*, user_updated_time*, markup_language*, is_shared*: seq[int]
latitude*, longitude*, altitude*, order*:seq[float]
id*, parent_id*, title*, body*, author*, source_url*, source*,
source_application*, application_data*, share_id*,
conflict_original_id*, body_html*, base_url*: seq[string]
updated_time*, is_conflict*, is_todo*, todo_due*,
todo_completed*, user_created_time*, user_updated_time*,
markup_language*, is_shared*: seq[int]
latitude*, longitude*, altitude*, order*: seq[float]
created_time*: seq[string]
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Setup joplin_note data
# --==--==--==--==--==--==--==--==--==--==-- #
type
joplin_note* = object
id*, parent_id*, title*, body*, author*, source_url*, source*,
source_application*, application_data*, conflict_original_id*,
master_key_id*, share_id*, encryption_cipher_text * : string
created_time*, updated_time*, user_created_time*, user_updated_time*,
is_conflict*, is_todo*, todo_due*, todo_completed*, markup_language*,
is_shared*, encryption_applied*: int
latitude*, longitude*, altitude*, order*: float
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
@ -73,7 +97,7 @@ type
# DURATION : duration variables
# --==--==--==--==--==--==--==--==--==--==-- #
let
resetDuration = initDuration(seconds=2)
resetDuration = initDuration(seconds = 2)
deciSecondDuration* = initDuration(milliseconds = 100)
qtrsecondDuration* = initDuration(milliseconds = 250)
@ -99,12 +123,12 @@ proc resetHttpClient() =
except:
echo("Attempted to close clients. Probably do not exist.")
echo("Current exception: ", getCurrentExceptionMsg())
client = newHttpClient(timeout=500)
client = newHttpClient(timeout = 500)
# --==--==--==--==--==--==--==--==--==--==--==--==--==-==--==--==- #
# PROC : use the joplin API ping to validate service availibility
# --==--==--==--==--==--==--==--==--==--==--==--==--==-==--==--==- #
proc ping_joplin*(token:string): Future[joplin_ping] {.async.} =
proc ping_joplin*(token: string): Future[joplin_ping] {.async.} =
var j_p: joplin_ping
var client = newAsyncHttpClient()
@ -139,10 +163,10 @@ proc ping_joplin*(token:string): Future[joplin_ping] {.async.} =
#let joplin_notes_Json = parseJson(json)
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get all joplin NOTEBOOKS
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_notebooks*(token:string): Future[joplin_notebooks] {.async.} =
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get all joplin NOTEBOOKS
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_notebooks*(token: string): Future[joplin_notebooks] {.async.} =
# Variables
var j_nb: joplin_notebooks
@ -189,7 +213,7 @@ proc get_joplin_notebooks*(token:string): Future[joplin_notebooks] {.async.} =
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get all joplin NOTES
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_notes*(token:string): Future[joplin_notes] {.async.} =
proc get_joplin_notes*(token: string): Future[joplin_notes] {.async.} =
# Variables
var j_notes: joplin_notes
@ -207,7 +231,7 @@ proc get_joplin_notes*(token:string): Future[joplin_notes] {.async.} =
while has_more == true:
# request joplin API for Notes
url = fmt"http://localhost:41184/notes?page={page}&token={token}"
url = fmt"http://localhost:41184/notes?page={page}&fields=id,parent_id,title,created_time,updated_time&token={token}"
echo("URL notes : ", url)
var json = await client.getContent(url)
@ -218,12 +242,21 @@ proc get_joplin_notes*(token:string): Future[joplin_notes] {.async.} =
if not joplin_notes_Json["has_more"].getBool:
has_more = false
#echo joplin_notes_Json
# store json info into an object
var count: int = 1
var epochTime: int
var humanTime: Time
for nb in joplin_notes_Json["items"]:
j_notes.id.add(nb["id"].getstr)
j_notes.parent_id.add(nb["parent_id"].getstr)
j_notes.title.add(nb["title"].getstr)
#epochTime = nb["created_time"].getInt
#humanTime = fromUnix(convert(Milliseconds, Seconds, epochTime))
j_notes.created_time.add(convertEpochToHumanTime(nb[
"created_time"].getInt))
count += 1
# aller à la page suivante
@ -231,11 +264,72 @@ proc get_joplin_notes*(token:string): Future[joplin_notes] {.async.} =
return j_notes
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get joplin NOTE
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_note*(token: string, noteid: string): Future[
joplin_note] {.async.} =
# Variables
var j_note: joplin_note
var has_more: bool = true
var page: int = 1
var url: string
var client = newAsyncHttpClient()
# Check joplin connection availibility
var pingCheck: joplin_ping
pingCheck = waitFor ping_joplin(token)
# Query for a selected note
url = fmt"http://localhost:41184/notes/{noteid}?fields=id,parent_id,title,body,created_time,updated_time,is_conflict,latitude,longitude,altitude,author,source_url,is_todo,todo_due,todo_completed,source,source_application,application_data,order,user_created_time,user_updated_time,encryption_cipher_text,encryption_applied,markup_language,is_shared,share_id,conflict_original_id,master_key_id&token={token}"
echo("URL notes : ", url)
var jsonNote = await client.getContent(url)
# parse jason
let joplin_note_Json = parseJson(jsonNote)
# get all informations for a selected note
j_note.id = joplin_note_Json["id"].getstr
j_note.parent_id = joplin_note_Json["parent_id"].getstr
j_note.title = joplin_note_Json["title"].getstr
j_note.body = joplin_note_Json["body"].getstr
j_note.author = joplin_note_Json["author"].getstr
j_note.source_url = joplin_note_Json["source_url"].getstr
j_note.source = joplin_note_Json["source"].getstr
j_note.source_application = joplin_note_Json["source_application"].getstr
j_note.application_data = joplin_note_Json["application_data"].getstr
j_note.share_id = joplin_note_Json["share_id"].getstr
j_note.conflict_original_id = joplin_note_Json["conflict_original_id"].getstr
j_note.created_time = joplin_note_Json["created_time"].getInt
j_note.updated_time = joplin_note_Json["updated_time"].getInt
j_note.is_conflict = joplin_note_Json["is_conflict"].getInt
j_note.latitude = joplin_note_Json["latitude"].getFloat
j_note.longitude = joplin_note_Json["longitude"].getFloat
j_note.altitude = joplin_note_Json["altitude"].getFloat
j_note.is_todo = joplin_note_Json["is_todo"].getInt
j_note.todo_due = joplin_note_Json["todo_due"].getInt
j_note.todo_completed = joplin_note_Json["todo_completed"].getInt
j_note.order = joplin_note_Json["order"].getFloat
j_note.user_created_time = joplin_note_Json["user_created_time"].getInt
j_note.user_updated_time = joplin_note_Json["user_updated_time"].getInt
j_note.encryption_cipher_text = joplin_note_Json[
"encryption_cipher_text"].getstr
j_note.encryption_applied = joplin_note_Json["encryption_applied"].getInt
j_note.markup_language = joplin_note_Json["markup_language"].getInt
j_note.is_shared = joplin_note_Json["is_shared"].getInt
j_note.master_key_id = joplin_note_Json["master_key_id"].getstr
echo j_note
return j_note
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : get all joplin TAGS
# --==--==--==--==--==--==--==--==--==--==-- #
proc get_joplin_tags*(token:string): Future[joplin_tags] {.async.} =
proc get_joplin_tags*(token: string): Future[joplin_tags] {.async.} =
# Variables
var j_tags: joplin_tags
@ -287,42 +381,41 @@ proc get_joplin_cli_token*(): string =
var result = execCmdEx("joplin config api.token")
if result.exitCode == 0:
let param1 = result.output
let flagSplit = param1.split(" = ")
flagName = flagSplit[0]
flagValue = flagSplit[1]
let param1 = result.output
let flagSplit = param1.split(" = ")
flagName = flagSplit[0]
flagValue = flagSplit[1]
return flagValue
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : launch any program and get PID
# --==--==--==--==--==--==--==--==--==--==-- #
proc launchProgram(app:string = "", workingPath:string = "", arguments:array[2, string]):int {.thread.} =
proc launchProgram(app: string = "", workingPath: string = "", arguments: array[
2, string]): int {.thread.} =
var p = startProcess(joinPath(workingPath,app), workingPath, arguments)
let pid = p.processID()
var outhdl = outputHandle(p)
var inputhdl = inputHandle(p)
var errhdl = errorHandle(p)
return pid
var p = startProcess(joinPath(workingPath, app), workingPath, arguments)
let pid = p.processID()
var outhdl = outputHandle(p)
var inputhdl = inputHandle(p)
var errhdl = errorHandle(p)
return pid
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : Start joplin cli
# --==--==--==--==--==--==--==--==--==--==-- #
proc joplin_cli_start*():int {.thread.} =
proc joplin_cli_start*(): int {.thread.} =
let joplinProcessId = launchProgram("joplin","/usr/bin/",["server","start"])
return joplinProcessId
let joplinProcessId = launchProgram("joplin", "/usr/bin/", ["server", "start"])
return joplinProcessId
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : stop Joplin Terminal
# --==--==--==--==--==--==--==--==--==--==-- #
proc joplin_cli_stop*():int {.thread.} =
let joplinProcessId = launchProgram("joplin","/usr/bin/",["server","stop"])
return joplinProcessId
proc joplin_cli_stop*(): int {.thread.} =
let joplinProcessId = launchProgram("joplin", "/usr/bin/", ["server", "stop"])
return joplinProcessId
# --==--==--==--==--==--==--==--==--==--==-- #
@ -333,51 +426,43 @@ proc joplin_cli_status*(): bool =
var result = execCmdEx("joplin server status")
if result.exitCode == 0:
if "Server is not running" in result.output :
echo "Joplin Terminal cli status is down : ", result.output
rc = false
if "Server is not running" in result.output:
echo "Joplin Terminal cli status is down : ", result.output
rc = false
else:
echo "Joplin Terminal cli status is up : ", result.output
rc = true
echo "Joplin Terminal cli status is up : ", result.output
rc = true
else:
echo "Error validate joplin terminal status : ", result.output
echo "Error validate joplin terminal status : ", result.output
return rc
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : start Joplin Terminal
# PROC : start or stop Joplin Terminal
# --==--==--==--==--==--==--==--==--==--==-- #
# proc joplin_cli_start*(): bool =
# var rc = false
# startProcess("joplin","/usr/bin", @["server", "start"])
# #var result = execCmdEx("ls -l /usr/bin/joplin")
proc joplin_cli_start_stop*(): int =
var isStart: int = 0
var sleep_delay_frame: int = 50
var sleep_max: int = 5000
# if joplin_cli_status() == true:
# echo "Joplin Terminal started successfully : ",result.output
# rc = true
# else:
# echo "Joplin Terminal didn't start : ",result.output
# rc = false
# return rc
if joplin_cli_status() == false:
isStart = joplin_cli_start()
while joplin_cli_status() == false:
sleep(sleep_delay_frame)
echo "Joplin client Terminal started: ", isStart
else:
echo "Joplin client Terminal is alredy started !"
#if joplin_cli_status() == true:
isStart = joplin_cli_stop()
while joplin_cli_status() == true:
sleep(sleep_delay_frame)
echo "Joplin client Terminal stopped: ", isStart
return isStart
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC : stop Joplin Terminal
# --==--==--==--==--==--==--==--==--==--==-- #
# proc joplin_cli_stop*(): bool =
# var rc = false
# var result = execCmdEx("joplin server stop")
# if result.exitCode == 0:
# # echo result.output
# rc = true
# else:
# rc = false
# return rc
# --==--==--==--==--==--==--==--==--==--==-- #
# PROC :
# --==--==--==--==--==--==--==--==--==--==-- #

22
code/utils.nim Normal file
View File

@ -0,0 +1,22 @@
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# Bruno Charest
# 2022-10-25
#
# __ DESCRIPTIONS __
# utils : procedures generals utils
#
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
import std/times
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
# PROC : Convert epoch millisecond time to human readable time
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
proc convertEpochToHumanTime*(epochTime: int): string =
var humanTime: Time
var dateTime: string
humanTime = fromUnix(convert(Milliseconds, Seconds, epochTime))
dateTime = format(humanTime, "yyyy-MM-dd' 'HH:mm")
# echo dateTime
return dateTime

View File

@ -15,19 +15,34 @@ import joplin_utils
# --==--==--==--==--==--==--==--==--==--==-- #
type
selectedOption* = enum
newNote="New Note", search="Search", shortcuts="Shortcuts", notes="Notes", notebooks="Notesbooks", tags="Tags"
newNote = "New Note", search = "Search", shortcuts = "Shortcuts",
notes = "Notes", notebooks = "Notesbooks", tags = "Tags",
notes_selectednote = "Notes-SelectedNote", dashbord = "Dashboard"
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Data Informations for Left Colomn
# --==--==--==--==--==--==--==--==--==--==-- #
type ColomnLeftData* = ref object of RootObj
j_status*: bool
option*: selectedOption
j_notes*: joplin_notes
j_notebooks*: joplin_notebooks
j_tags*: joplin_tags
req*: Request
j_status*: bool
option*: selectedOption
j_notes*: joplin_notes
j_notes_nb*: int
j_notebooks*: joplin_notebooks
j_notebooks_nb*: int
j_tags*: joplin_tags
j_tags_nb*: int
req*: Request
# --==--==--==--==--==--==--==--==--==--==-- #
# TYPE : Data Informations for Right Colomn
# --==--==--==--==--==--==--==--==--==--==-- #
type ColomnRightData* = ref object of RootObj
j_status*: bool
option*: selectedOption
j_SelectedNote*: joplin_note
j_notebooksNote*: joplin_notebooks
j_tagsNote*: joplin_tags
req*: Request

View File

@ -3,3 +3,4 @@ switch("d","release")
# --threads:on
--opt:size
switch("passL","-s")
hint("Name",false)

View File

@ -26,7 +26,7 @@ port = "7000"
#Joplin DESKTOP token
#token = "e5f6644fbf6a97ddc55648dae72b11caecda6c6642d8ce0d3b20129b89b196385737eb908923542c3343649ebbf865b55bda031ab4c3a16edc7723ef2ad77d8f"
# Joplin CLI token
token = "5b05f489016ce8a001ec83a7968419368eb9206340a18f73119c79e2154ab267ddec424658920bb6f88961c170a2680cd07fbd83f38e1c0c8df907a9aed22427"
token = "76d06ec328466c872f3a944f8237fd96f18d2b953ff013c8689304b7384f2f2232b3aedff079902217760e8fa180d1b89d2650ee1819dd628678fccdc0a140a6"
joplin_server = "https://joplinlab.bcmaison.cf"
joplin_server_user = "joplinlab@zohomail.com"
joplin_server_pwd = "Chab30017405"

BIN
data/dashbord.xlsx Normal file

Binary file not shown.

1
data/toto.txt Normal file
View File

@ -0,0 +1 @@
SQLiteDatabase

View File

@ -19,3 +19,15 @@ joplin config locale en_US
# --==--==--==--==--==--==--==--==--==--==-- #
joplin config api.token
cat .config/joplin/settings.json
# --==--==--==--==--==--==--==--==--==--==-- #
# install nim module requirment
# --==--==--==--==--==--==--==--==--==--==-- #
nimble install jester
nimble install bcrypt
nimble install templates
# --==--==--==--==--==--==--==--==--==--==-- #
# install packages requirment
# --==--==--==--==--==--==--==--==--==--==-- #
sudo apt install libzip4

147
main.nim
View File

@ -16,20 +16,21 @@
# --==--==--==--==--==--==--==--==--==--==-- #
# Import section
# --==--==--==--==--==--==--==--==--==--==-- #
import os # Used to get arguments
import uri # We need to encode urls: encodeUrl()
import times # Time and date
import jester # Our webserver
import logging # Logging utils
import strutils # Basic functions
import parsecfg # Parse CFG (config) files
import std/json # json manipulation
import os # Used to get arguments
import uri # We need to encode urls: encodeUrl()
import xlsx # read dashbord.xlsx
import times # Time and date
import jester # Our webserver
import logging # Logging utils
import strutils # Basic functions
import parsecfg # Parse CFG (config) files
import std/json # json manipulation
import db_sqlite # SQLite
import code/database_utils # Utils used in the database
import code/password_utils # Our file with password utils
import code/joplin_utils # Joplin utils procedures and types
import code/web_utils # Web utils procedures and types
import code/joplin_utils # Joplin utils procedures and types
import code/web_utils # Web utils procedures and types
# --==--==--==--==--==--==--==--==--==--==-- #
# First we'll load config files
@ -41,14 +42,14 @@ let dict = loadConfig("config/config.cfg")
# --==--==--==--==--==--==--==--==--==--==-- #
# Database
let db_user = dict.getSectionValue("Database", "user")
let db_pass = dict.getSectionValue("Database", "pass")
let db_name = dict.getSectionValue("Database", "name")
let db_host = dict.getSectionValue("Database", "host")
let db_user = dict.getSectionValue("Database", "user")
let db_pass = dict.getSectionValue("Database", "pass")
let db_name = dict.getSectionValue("Database", "name")
let db_host = dict.getSectionValue("Database", "host")
# Website
let mainURL = dict.getSectionValue("Server", "url")
let mainPort = parseInt dict.getSectionValue("Server", "port")
let mainURL = dict.getSectionValue("Server", "url")
let mainPort = parseInt dict.getSectionValue("Server", "port")
let mainWebsite = dict.getSectionValue("Server", "website")
# Joplin
@ -79,18 +80,14 @@ type
# --==--==--==--==--==--==--==--==--==--==-- #
# proc init : initialisation variables
# --==--==--==--==--==--==--==--==--==--==-- #
proc init(c: var TData, cld: var ColomnLeftData) =
proc init(c: var TData, cld: var ColomnLeftData, crd: var ColomnRightData) =
## Empty out user session data
c.userpass = ""
c.username = ""
c.userid = ""
c.userid = ""
c.loggedIn = false
c.notification = 0
## default option
# cld.option = notes
# --==--==--==--==--==--==--==--==--==--==-- #
# function : loggedIn
# --==--==--==--==--==--==--==--==--==--==-- #
@ -113,21 +110,24 @@ proc checkLoggedIn(c: var TData) =
# Update the value lastModified for the user in the
# table session where the sid and IP match. If there's
# any results (above 0) assign values
if execAffectedRows(db, sql("UPDATE session SET lastModified = " & $toInt(epochTime()) & " " & "WHERE ip = ? AND key = ?"), c.req.ip, sid) > 0:
if execAffectedRows(db, sql("UPDATE session SET lastModified = " & $toInt(
epochTime()) & " " & "WHERE ip = ? AND key = ?"), c.req.ip, sid) > 0:
# Get user data based on userID from session table
# Assign values to user details - `c`
c.userid = getValue(db, sql"SELECT userid FROM session WHERE ip = ? AND key = ?", c.req.ip, sid)
c.userid = getValue(db, sql"SELECT userid FROM session WHERE ip = ? AND key = ?",
c.req.ip, sid)
# Get user data based on userID from person table
let row = getRow(db, sql"SELECT name, email, status FROM person WHERE id = ?", c.userid)
# Assign user data
c.username = row[0]
c.email = toLowerAscii(row[1])
c.username = row[0]
c.email = toLowerAscii(row[1])
# Update our session table with info about activity
discard tryExec(db, sql"UPDATE person SET lastOnline = ? WHERE id = ?", toInt(epochTime()), c.userid)
discard tryExec(db, sql"UPDATE person SET lastOnline = ? WHERE id = ?",
toInt(epochTime()), c.userid)
else:
# If the user is not found in the session table
@ -158,14 +158,15 @@ proc login(c: var TData, email, pass: string): tuple[b: bool, s: string] =
# and salt.
if row[2] == makePassword(pass, row[4], row[2]):
# Assign the values
c.userid = row[0]
c.userid = row[0]
c.username = row[1]
c.userpass = row[2]
c.email = toLowerAscii(row[3])
c.email = toLowerAscii(row[3])
# Generate session key and save it
let key = makeSessionKey()
exec(db, sql"INSERT INTO session (ip, key, userid) VALUES (?, ?, ?)", c.req.ip, key, row[0])
exec(db, sql"INSERT INTO session (ip, key, userid) VALUES (?, ?, ?)",
c.req.ip, key, row[0])
info("Login successful")
return (true, key)
@ -196,16 +197,19 @@ template createTFD() =
# Assign the c to TDATA
var cld {.inject.}: ColomnLeftData
var crd {.inject.}: ColomnRightData
# New instance of c
new(c)
new(cld)
new(crd)
# Set standard values
init(c,cld)
init(c, cld, crd)
# Get users request
c.req = request
cld.req = request
crd.req = request
# Check for cookies (we need the cookie named sid)
if cookies(request).len > 0:
@ -229,7 +233,8 @@ when isMainModule:
# Connect to DB
try:
# We are using the values which we assigned earlier
db = open(connection=db_host, user=db_user, password=db_pass, database=db_name)
db = open(connection = db_host, user = db_user, password = db_pass,
database = db_name)
info("Connection to DB is established.")
except:
fatal("Connection to DB could not be established.")
@ -274,20 +279,30 @@ routes:
get "/secret":
createTFD()
echo c.loggedIn
echo @"msg"
if c.loggedIn:
var isStart: int = 0
# Start joplin terminal cli if stropped
# if joplin_cli_status() == false:
# isStart = joplin_cli_start()
echo "MESSAGE :", @"msg"
echo "NOTE_ID :", @"noteid"
let selectedNoteId = @"noteid"
var url_note = "/secret?msg=notes"
# URL msg and note id if exist noteid
if selectedNoteId != "":
url_note = "/secret?msg=notes&noteid=" & selectedNoteId
if c.loggedIn:
# Start joplin terminal cli if stropped
if @"msg" == "startStopJoplin":
if joplin_cli_status() == false:
var isStart = joplin_cli_start()
echo "Joplin client Terminal started: ",isStart
# echo joplin_cli_status()
if joplin_cli_status() == true:
var isStart = joplin_cli_stop()
echo "Joplin client Terminal stopped: ",isStart
# echo joplin_cli_status()
redirect("/secret")
var isStart = joplin_cli_start_stop()
redirect(url_note)
# if Joplin application work
var checkJoplin = waitFor ping_joplin(joplin_token)
@ -299,51 +314,81 @@ routes:
# determine the section to uptade
if @"msg" == "newNote":
cld.option = newNote
echo "Todo"
echo "=> Section newNote"
elif @"msg" == "search":
cld.option = search
echo "Todo"
echo "=> Section search"
elif @"msg" == "shortcuts":
cld.option = shortcuts
echo "Todo"
echo "=> Section shortcuts"
elif @"msg" == "notebooks":
echo "=> Section notebooks"
cld.option = notebooks
cld.j_notebooks = waitFor get_joplin_notebooks(joplin_token)
elif @"msg" == "notes":
echo "=> Section notes"
cld.option = notes
cld.j_notes = waitFor get_joplin_notes(joplin_token)
cld.j_notes_nb = cld.j_notes.id.len()
# for i in 0 .. (cld.j_notes.id.len() - 1):
# echo cld.j_notes.id[i]
# echo cld.j_notes.created_time[i]
if selectedNoteId != "":
crd.j_SelectedNote = waitFor get_joplin_note(joplin_token, selectedNoteId)
elif @"msg" == "tags":
echo "=> Section tags"
cld.option = tags
cld.j_tags = waitFor get_joplin_tags(joplin_token)
elif @"msg" == "dashbord":
echo "=> Section dashbord"
#cld.option = dashbord
let
data = parseExcel("data/dashbord.xlsx", header = true)
sheetName = "dashbord"
echo data[sheetName]
let rows = data[sheetName].toSeq(true)
for row in rows:
echo "position: " & row[0]
echo "URL externe: " & row[1]
elif @"msg" == "sendFeedBack":
echo "Todo"
resp Http200, {"Access-Control-Allow-Origin": "http://127.0.0.1:7000"}, genSecret(c,cld)
resp Http200, {"Access-Control-Allow-Origin": "http://127.0.0.1:7000"},
genSecret(c, cld, crd)
# Login route
# --==--==--==--==--==--==--==--==--==--==-- #
get "/login":
createTFD()
resp Http200, {"Access-Control-Allow-Origin": "http://127.0.0.1:7000"}, genLogin(c, @"msg")
resp Http200, {"Access-Control-Allow-Origin": "http://127.0.0.1:7000"},
genLogin(c, @"msg")
# action route during login
# --==--==--==--==--==--==--==--==--==--==-- #
post "/dologin":
createTFD()
let (loginB, loginS) = login(c, replace(toLowerAscii(@"email"), " ", ""), replace(@"password", " ", ""))
let (loginB, loginS) = login(c, replace(toLowerAscii(@"email"), " ", ""),
replace(@"password", " ", ""))
if loginB:
when defined(dev):
jester.setCookie("sid", loginS, daysForward(7))
else:
jester.setCookie("sid", loginS, daysForward(7), samesite = Lax, secure = true, httpOnly = true)
jester.setCookie("sid", loginS, daysForward(7), samesite = Lax,
secure = true, httpOnly = true)
#jester.setCookie("sid", loginS, daysForward(7), samesite = Lax, secure = true, httpOnly = true)
redirect("/secret")

View File

@ -2,449 +2,493 @@
[ FONT ]*/
@font-face {
font-family: Poppins-Regular;
src: url('../fonts/poppins/Poppins-Regular.ttf');
font-family: Poppins-Regular;
src: url('../fonts/poppins/Poppins-Regular.ttf');
}
@font-face {
font-family: Poppins-Medium;
src: url('../fonts/poppins/Poppins-Medium.ttf');
font-family: Poppins-Medium;
src: url('../fonts/poppins/Poppins-Medium.ttf');
}
@font-face {
font-family: Poppins-Bold;
src: url('../fonts/poppins/Poppins-Bold.ttf');
font-family: Poppins-Bold;
src: url('../fonts/poppins/Poppins-Bold.ttf');
}
@font-face {
font-family: Poppins-SemiBold;
src: url('../fonts/poppins/Poppins-SemiBold.ttf');
font-family: Poppins-SemiBold;
src: url('../fonts/poppins/Poppins-SemiBold.ttf');
}
html, body {
margin: 0;
font-family: Poppins-Regular, sans-serif;
height:100%;
html,
body {
margin: 0;
font-family: Poppins-Regular, sans-serif;
height: 100%;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
a {
font-family: Poppins-Regular;
font-size: 14px;
line-height: 1.7;
color: #666666;
margin: 0px;
transition: all 0.4s;
-webkit-transition: all 0.4s;
-o-transition: all 0.4s;
-moz-transition: all 0.4s;
font-family: Poppins-Regular;
font-size: 14px;
line-height: 1.7;
color: #666666;
margin: 0px;
transition: all 0.4s;
-webkit-transition: all 0.4s;
-o-transition: all 0.4s;
-moz-transition: all 0.4s;
}
:root {
--accent-color: #0053b8;
--lightest-gray: rgb(244, 244, 244);
--light-gray: rgb(144, 144, 144);
--medium-gray: rgb(96, 96, 96);
--dark-gray: rgb(13, 13, 13);
--animation-duration: 200ms;
--animation-timing-curve: ease-in-out;
--blue-joplin-color: #0053b8;
--light-blue-joplin-color: rgb(237, 241, 243);
--header-height: 55px;
--accent-color: #0053b8;
--lightest-gray: rgb(244, 244, 244);
--light-gray: rgb(144, 144, 144);
--medium-gray: rgb(96, 96, 96);
--dark-gray: rgb(13, 13, 13);
--animation-duration: 200ms;
--animation-timing-curve: ease-in-out;
--blue-joplin-color: #0053b8;
/* --blue-joplin-color: #b83100; */
--light-blue-joplin-color: rgb(237, 241, 243);
--header-height: 55px;
}
.header {
display: flex;
align-items: center;
position: sticky;
top: 0;
background-color: white;
box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.4);
padding: 0 0.5rem;
height: var(--header-height);
display: flex;
align-items: center;
position: sticky;
top: 0;
background-color: white;
box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.4);
padding: 0 0.5rem;
height: var(--header-height);
}
.login {
font-size: large;
fill: var(--blue-joplin-color);
/* max-width: fit-content; */
position: absolute;
top: 30%;
left: 50%;
transform: translate(-52%, -50%);
font-size: large;
fill: var(--blue-joplin-color);
/* max-width: fit-content; */
position: absolute;
top: 30%;
left: 50%;
transform: translate(-52%, -50%);
}
/* Create two equal columns that floats next to each other */
.column {
float: left;
padding: 10px;
height: calc(100vh - var(--header-height));
/* height: auto; */
/* flex: 50%; */
width: 100%;
float: left;
padding: 10px;
height: calc(100vh - var(--header-height));
/* height: auto; */
/* flex: 50%; */
width: 100%;
}
.column .scrollbar {
/* margin-left: 30px; */
/* float: left; */
/* min-height: 100px; */
height: 800px;
background: #fff;
overflow-y: scroll;
/* margin-bottom: 25px; */
/* margin-left: 30px; */
/* float: left; */
/* min-height: 100px; */
height: 800px;
background: #fff;
overflow-y: scroll;
/* margin-bottom: 25px; */
}
.left {
width: 25%;
width: 25%;
}
.right {
width: 75%;
width: 75%;
}
.row {
display: flex;
width: 100%;
display: flex;
width: 100%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
content: "";
display: table;
clear: both;
}
.menu-icon-btn {
background: none;
border: none;
padding: 0;
background: none;
border: none;
padding: 0;
}
.notifBell-btn {
background: none;
border: none;
padding: 0;
background: none;
border: none;
padding: 0;
}
.menu-icon {
width: 25px;
height: 25px;
fill: var(--medium-gray);
cursor: pointer;
width: 25px;
height: 25px;
fill: var(--medium-gray);
cursor: pointer;
}
.menu-icon:hover {
fill: var(--dark-gray);
fill: var(--dark-gray);
}
.sidebar {
flex-shrink: 0;
overflow: hidden;
width: 75px;
border-right: 1px solid var(--light-gray);
display: flex;
flex-direction: column;
height: calc(100vh - var(--header-height));
padding-top: 1rem;
align-items: center;
justify-content: stretch;
transition: width var(--animation-duration) var(--animation-timing-curve);
position: sticky;
left: 0;
top: var(--header-height);
flex-shrink: 0;
overflow: hidden;
width: 75px;
border-right: 1px solid var(--light-gray);
display: flex;
flex-direction: column;
height: calc(100vh - var(--header-height));
padding-top: 1rem;
align-items: center;
justify-content: stretch;
transition: width var(--animation-duration) var(--animation-timing-curve);
position: sticky;
left: 0;
top: var(--header-height);
}
.sidebar .hidden-sidebar {
opacity: 0;
width: 0;
transition: opacity var(--animation-duration) var(--animation-timing-curve);
opacity: 0;
width: 0;
transition: opacity var(--animation-duration) var(--animation-timing-curve);
}
.sidebar.open .hidden-sidebar {
width: 100%;
height: auto;
opacity: 1;
width: 100%;
height: auto;
opacity: 1;
}
.sidebar .top-sidebar {
display: flex;
flex-direction: column;
align-items: center;
display: flex;
flex-direction: column;
align-items: center;
}
.sidebar .channel-logo {
display: block;
width: 30px;
height: 30px;
transition: var(--animation-duration) var(--animation-timing-curve);
display: block;
width: 30px;
height: 30px;
transition: var(--animation-duration) var(--animation-timing-curve);
}
.sidebar.open .channel-logo {
width: 90px;
height: 90px;
width: 90px;
height: 90px;
}
.sidebar .channel-logo>img {
width: 100%;
height: 100%;
width: 100%;
height: 100%;
}
.middle-sidebar {
overflow-y: auto;
overflow-x: hidden;
flex-grow: 1;
margin: 1rem 0;
overflow-y: auto;
overflow-x: hidden;
flex-grow: 1;
margin: 1rem 0;
}
.middle-sidebar,
.bottom-sidebar {
width: 100%;
width: 100%;
}
.container {
display: flex;
height: 94%;
display: flex;
height: 94%;
}
.vertical-center {
margin: 0;
position: absolute;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
/* border: 5px solid #FFFF00; */
text-align: center;
margin: 0;
position: absolute;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
/* border: 5px solid #FFFF00; */
text-align: center;
}
.content {
/* margin: 1rem; */
width: 1200px;
min-height: 100px;
height: auto;
margin: 80px auto 0px auto;
/* background-color: black; */
padding: 10px 10px;
display:table;
overflow:hidden;
height:100%;
/* margin: 1rem; */
width: 1200px;
min-height: 100px;
height: auto;
margin: 80px auto 0px auto;
/* background-color: black; */
padding: 10px 10px;
display: table;
overflow: hidden;
height: 100%;
}
.sidebar-list {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
list-style: none;
}
.sidebar.open .sidebar-link {
justify-content: flex-start;
justify-content: flex-start;
}
.svg-icon path,
.svg-icon polygon,
.svg-icon rect,
.sidebar-icon {
width: 25px;
height: 25px;
flex-shrink: 0;
fill: var(--blue-joplin-color);
width: 25px;
height: 25px;
flex-shrink: 0;
fill: var(--blue-joplin-color);
}
.svg-icon {
width: 25px;
height: 25px;
}
.svg-icon circle {
stroke: #4691f6;
stroke-width: 1;
}
.sidebar-list .hidden-sidebar {
margin-left: 1.5rem;
white-space: nowrap;
margin-left: 1.5rem;
white-space: nowrap;
}
.sidebar-link {
display: flex;
width: 100%;
padding: 0.5rem 0;
color: var(--light-gray);
text-decoration: none;
align-items: center;
padding-left: 25px;
display: flex;
width: 100%;
padding: 0.5rem 0;
color: var(--light-gray);
text-decoration: none;
align-items: center;
padding-left: 25px;
}
.sidebar-note-link {
display: flex;
width: 100%;
/* padding: 10px; */
color: var(--blue-joplin-color);
text-decoration: none;
font-size: 16px;
align-items: left;
padding-left: 15px;
}
.sidebar-note-date {
display: flex;
width: 100%;
/* padding: 0.1rem 0; */
color: var(--light-gray);
text-decoration: none;
font-size: 12px;
align-items: left;
padding-left: 15px;
padding-bottom: 10px;
}
.sidebar-list-item {
position: relative;
width: 100%;
fill: var(--light-gray);
position: relative;
width: 100%;
fill: var(--light-gray);
}
.sidebar-list-item.active {
fill: var(--accent-color);
background-color: var(--light-blue-joplin-color);
fill: var(--accent-color);
background-color: var(--light-blue-joplin-color);
}
.sidebar-list-item:hover {
background-color: var(--light-blue-joplin-color);
background-color: var(--light-blue-joplin-color);
}
.columnLeftJoplinNotes:hover {
background-color: var(--light-blue-joplin-color);
}
.sidebar-list-item.active::before {
content: "";
background-color: var(--accent-color);
height: 100%;
left: 0;
width: 3px;
position: absolute;
content: "";
background-color: var(--accent-color);
height: 100%;
left: 0;
width: 3px;
position: absolute;
}
.sidebar.open {
width: 200px;
width: 200px;
}
.your-channel {
color: var(--dark-gray);
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 0.15rem;
margin-top: 0.5rem;
color: var(--dark-gray);
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 0.15rem;
margin-top: 0.5rem;
}
.channel-name {
color: var(--medium-gray);
font-size: 1.0rem;
color: var(--medium-gray);
font-size: 1.0rem;
}
.sidebar .top-sidebar {
height: 30px;
transition: height var(--animation-duration) var(--animation-timing-curve);
height: 30px;
transition: height var(--animation-duration) var(--animation-timing-curve);
}
.sidebar.open .top-sidebar {
height: 150px;
height: 150px;
}
.sidebar .top-sidebar .hidden-sidebar {
text-align: center;
width: 100%;
text-align: center;
width: 100%;
}
.force-overflow {
min-height: 450px;
min-height: 450px;
}
.scrollbar-primary::-webkit-scrollbar {
width: 6px;
background-color: #F5F5F5;
width: 6px;
background-color: #F5F5F5;
}
.scrollbar-primary::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #4285F4;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #4285F4;
}
.scrollbar-danger::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
}
.scrollbar-danger::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
width: 12px;
background-color: #F5F5F5;
}
.scrollbar-danger::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #ff3547;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #ff3547;
}
.scrollbar-warning::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
}
.scrollbar-warning::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
width: 12px;
background-color: #F5F5F5;
}
.scrollbar-warning::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #FF8800;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #FF8800;
}
.scrollbar-success::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
}
.scrollbar-success::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
width: 12px;
background-color: #F5F5F5;
}
.scrollbar-success::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #00C851;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #00C851;
}
.scrollbar-info::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
}
.scrollbar-info::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
width: 12px;
background-color: #F5F5F5;
}
.scrollbar-info::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #33b5e5;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #33b5e5;
}
.scrollbar-default::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
}
.scrollbar-default::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
width: 12px;
background-color: #F5F5F5;
}
.scrollbar-default::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #2BBBAD;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #2BBBAD;
}
.scrollbar-secondary::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F5F5F5;
border-radius: 10px;
}
.scrollbar-secondary::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
width: 12px;
background-color: #F5F5F5;
}
.scrollbar-secondary::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #aa66cc;
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #aa66cc;
}
.fancytree-container {
outline: none;
outline: none;
}

View File

@ -3,7 +3,7 @@ import templates
# --==--==--==--==--==--==--==--==--==--==-- #
# SVG : Menu icon
# --==--==--==--==--==--==--==--==--==--==-- #
proc Menu_icon* (): string = tmpli html"""
proc Menu_icon*(): string = tmpli html"""
<svg class="menu-icon" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 297 297"
style="enable-background:new 0 0 297 297;" xml:space="preserve">
@ -119,7 +119,7 @@ proc Notebooks_icon*(): string = tmpli html"""
"""
# --==--==--==--==--==--==--==--==--==--==-- #
# SVG : All tags icon
# SVG : Tags icon
# --==--==--==--==--==--==--==--==--==--==-- #
proc Tags_icon*(): string = tmpli html"""
<svg class="sidebar-icon" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
@ -155,6 +155,26 @@ proc Tags_icon*(): string = tmpli html"""
</svg>
"""
# --==--==--==--==--==--==--==--==--==--==-- #
# SVG : Dashbord icon
# --==--==--==--==--==--==--==--==--==--==-- #
proc Dashbord_icon*(): string = tmpli html"""
<svg class="svg-icon" viewBox="0 0 20 20">
<path fill="none" d="M7.228,11.464H1.996c-0.723,0-1.308,0.587-1.308,1.309v5.232c0,0.722,0.585,1.308,1.308,1.308h5.232
c0.723,0,1.308-0.586,1.308-1.308v-5.232C8.536,12.051,7.95,11.464,7.228,11.464z M7.228,17.351c0,0.361-0.293,0.654-0.654,0.654
H2.649c-0.361,0-0.654-0.293-0.654-0.654v-3.924c0-0.361,0.292-0.654,0.654-0.654h3.924c0.361,0,0.654,0.293,0.654,0.654V17.351z
M17.692,11.464H12.46c-0.723,0-1.308,0.587-1.308,1.309v5.232c0,0.722,0.585,1.308,1.308,1.308h5.232
c0.722,0,1.308-0.586,1.308-1.308v-5.232C19,12.051,18.414,11.464,17.692,11.464z M17.692,17.351c0,0.361-0.293,0.654-0.654,0.654
h-3.924c-0.361,0-0.654-0.293-0.654-0.654v-3.924c0-0.361,0.293-0.654,0.654-0.654h3.924c0.361,0,0.654,0.293,0.654,0.654V17.351z
M7.228,1H1.996C1.273,1,0.688,1.585,0.688,2.308V7.54c0,0.723,0.585,1.308,1.308,1.308h5.232c0.723,0,1.308-0.585,1.308-1.308
V2.308C8.536,1.585,7.95,1,7.228,1z M7.228,6.886c0,0.361-0.293,0.654-0.654,0.654H2.649c-0.361,0-0.654-0.292-0.654-0.654V2.962
c0-0.361,0.292-0.654,0.654-0.654h3.924c0.361,0,0.654,0.292,0.654,0.654V6.886z M17.692,1H12.46c-0.723,0-1.308,0.585-1.308,1.308
V7.54c0,0.723,0.585,1.308,1.308,1.308h5.232C18.414,8.848,19,8.263,19,7.54V2.308C19,1.585,18.414,1,17.692,1z M17.692,6.886
c0,0.361-0.293,0.654-0.654,0.654h-3.924c-0.361,0-0.654-0.292-0.654-0.654V2.962c0-0.361,0.293-0.654,0.654-0.654h3.924
c0.361,0,0.654,0.292,0.654,0.654V6.886z"></path>
</svg>
"""
# --==--==--==--==--==--==--==--==--==--==-- #
# SVG : Settings icon
# --==--==--==--==--==--==--==--==--==--==-- #

View File

@ -13,7 +13,7 @@
#
# import snippet_html
# import snippet_icons
#proc genSecret(c: var TData, columnLeftInfo: var ColomnLeftData): string =
#proc genSecret(c: var TData, columnLeftInfo: var ColomnLeftData, ColomnRightInfo: var ColomnRightData): string =
# result = ""
<!DOCTYPE html>
<html lang="en">
@ -22,7 +22,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<title>Joplin-TheNewWeb</title>
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/notif-bell.css">
<script src="js/script.js" defer></script>
@ -63,6 +63,7 @@
# var active_notes: string = ""
# var active_notebooks: string = ""
# var active_tags: string = ""
# var active_dashbord: string = ""
# var active_settings: string = ""
# var active_sendFeedBack: string = ""
# if columnLeftInfo.option == newNote:
@ -77,6 +78,8 @@
# active_notebooks = "active"
# elif columnLeftInfo.option == tags:
# active_tags = "active"
# elif columnLeftInfo.option == dashbord:
# active_dashbord = "active"
# end if
<li class="sidebar-list-item ${active_newNote}">
@ -145,6 +148,18 @@
<div class="hidden-sidebar">Tags</div>
</a>
</li>
<!--Dashbord dans la bar de navigation -->
<li class="sidebar-list-item ${active_dashbord}">
<a href="/secret?msg=dashbord" class="sidebar-link">
# var icon_Dashbord = Dashbord_icon()
${icon_Dashbord}
<div class="hidden-sidebar">Dashbord</div>
</a>
</li>
</ul>
</div>
<div class="bottom-sidebar">
@ -225,14 +240,15 @@
</div>
</div>
# elif columnLeftInfo.option == notes:
<h2>Notes</h2>
<h2>Notes</h2> <h5>${columnLeftInfo.j_notes_nb}</h5>
<div class="scrollbar scrollbar-primary">
<div class="force-overflow">
<div class="ColomnLeftJoplinNotes">
# for i in columnLeftInfo.j_notes.title:
<p> ${i} </p>
# end for
# for i in 0 .. (columnLeftInfo.j_notes.id.len() - 1) :
<div class="columnLeftJoplinNotes">
<a href="/secret?msg=notes&noteid=${columnLeftInfo.j_notes.id[i]}" class="sidebar-note-link">${columnLeftInfo.j_notes.title[i]}</a>
<p class="sidebar-note-date">${columnLeftInfo.j_notes.created_time[i]} </p>
</div>
# end for
</div>
</div>
# elif columnLeftInfo.option == notebooks:
@ -254,14 +270,37 @@
# for i in columnLeftInfo.j_tags.title:
<p> ${i} </p>
# end for
</div>
</div>
</div>
# elif columnLeftInfo.option == dashbord:
<h2>Dashboard</h2>
<div class="scrollbar scrollbar-primary">
<div class="force-overflow">
<div class="ColomnLeftJoplinDashboard">
<p>DASHBORD</p>
</div>
</div>
</div>
# end if
</div>
<div class="column right" style="background-color:#bbb;">
<h2>Column 2</h2>
<p>Some text..</p>
<div class="column right" >
# if columnLeftInfo.option == newNote:
<h2>New Note !!</h2>
<p>Some text..</p>
# elif columnLeftInfo.option == notes:
# if ColomnRightInfo.j_SelectedNote.id != "":
<h2> ${ColomnRightInfo.j_SelectedNote.title}</h2>
<hr width="65%"></hr>
<br>
<p>${ColomnRightInfo.j_SelectedNote.body}</p>
# else :
<h2>Click on note to see it !!</h2>
# end if
# end if
</div>
</div>
</div>