Compare commits
20 Commits
feature/st
...
bugfix/tim
| Author | SHA1 | Date | |
|---|---|---|---|
| 0dc21100f8 | |||
| a898e5eaa2 | |||
| 85faf31bc6 | |||
| a96bcff2df | |||
| 0a289eb59d | |||
| a2f47ac3eb | |||
| 1de84979ee | |||
| 4e88b2c4de | |||
| 0d02f3cbda | |||
| ebf9a83b60 | |||
| 9035ca48a7 | |||
| 1d55325501 | |||
| 462d0bb66e | |||
| fda7f34b99 | |||
| 56b79e1ecf | |||
| 72cb91f865 | |||
| 3833f2f978 | |||
| 5e0b59bacf | |||
| 55f5a663fe | |||
| 8197a0796c |
@@ -2,9 +2,11 @@
|
|||||||
package de.srsoftware.umbrella.core;
|
package de.srsoftware.umbrella.core;
|
||||||
|
|
||||||
import static de.srsoftware.tools.Optionals.nullable;
|
import static de.srsoftware.tools.Optionals.nullable;
|
||||||
|
import static de.srsoftware.umbrella.core.ModuleRegistry.translator;
|
||||||
import static java.lang.System.Logger.Level.DEBUG;
|
import static java.lang.System.Logger.Level.DEBUG;
|
||||||
import static java.lang.System.Logger.Level.WARNING;
|
import static java.lang.System.Logger.Level.WARNING;
|
||||||
import static java.net.HttpURLConnection.*;
|
import static java.net.HttpURLConnection.*;
|
||||||
|
import static java.text.MessageFormat.format;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import de.srsoftware.tools.Path;
|
import de.srsoftware.tools.Path;
|
||||||
@@ -72,7 +74,9 @@ public abstract class BaseHandler extends PathHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean send(HttpExchange ex, UmbrellaException e) throws IOException {
|
public boolean send(HttpExchange ex, UmbrellaException e) throws IOException {
|
||||||
return sendContent(ex,e.statusCode(),e.getMessage());
|
String lang = languages(ex).stream().findFirst().orElse(null);
|
||||||
|
var translatedMessage = translator().translate(lang,e.getMessage());
|
||||||
|
return sendContent(ex,e.statusCode(),format(translatedMessage,e.fills()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean unauthorized(HttpExchange ex) throws IOException {
|
public boolean unauthorized(HttpExchange ex) throws IOException {
|
||||||
|
|||||||
@@ -13,13 +13,15 @@ import static java.text.MessageFormat.format;
|
|||||||
|
|
||||||
public class UmbrellaException extends RuntimeException{
|
public class UmbrellaException extends RuntimeException{
|
||||||
private final int statusCode;
|
private final int statusCode;
|
||||||
|
private Object[] fills;
|
||||||
|
|
||||||
public UmbrellaException(String message, Object ... fills){
|
public UmbrellaException(String message, Object ... fills){
|
||||||
this(HTTP_SERVER_ERROR,message,fills);
|
this(HTTP_SERVER_ERROR,message,fills);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UmbrellaException(int statusCode, String message, Object ... fills){
|
public UmbrellaException(int statusCode, String message, Object ... fills){
|
||||||
super(fills == null || fills.length<1 ? message : format(message,fills));
|
super(message);
|
||||||
|
this.fills = fills;
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +36,10 @@ public class UmbrellaException extends RuntimeException{
|
|||||||
return new UmbrellaException(message,fills);
|
return new UmbrellaException(message,fills);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object[] fills(){
|
||||||
|
return fills;
|
||||||
|
}
|
||||||
|
|
||||||
public static UmbrellaException forbidden(String message, Object... fills) {
|
public static UmbrellaException forbidden(String message, Object... fills) {
|
||||||
return new UmbrellaException(HTTP_FORBIDDEN,message,fills);
|
return new UmbrellaException(HTTP_FORBIDDEN,message,fills);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,12 @@
|
|||||||
async function applyEdit(){
|
async function applyEdit(){
|
||||||
let success = await onSet(editValue);
|
let success = await onSet(editValue);
|
||||||
if (success) {
|
if (success) {
|
||||||
value = editValue;
|
if (success == 'reset'){
|
||||||
editing=false;
|
editValue = value;
|
||||||
|
} else {
|
||||||
|
value = editValue;
|
||||||
|
}
|
||||||
|
editing = false;
|
||||||
} else {
|
} else {
|
||||||
editValue = value;
|
editValue = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import TimeRecorder from './TimeRecorder.svelte';
|
|||||||
let key = $state(null);
|
let key = $state(null);
|
||||||
const router = useTinyRouter();
|
const router = useTinyRouter();
|
||||||
const modules = $state([]);
|
const modules = $state([]);
|
||||||
|
let expand = $state(false);
|
||||||
|
|
||||||
async function fetchModules(){
|
async function fetchModules(){
|
||||||
const url = `${location.protocol}//${location.host.replace('5173','8080')}/legacy/user/modules`;
|
const url = `${location.protocol}//${location.host.replace('5173','8080')}/legacy/user/modules`;
|
||||||
@@ -27,6 +28,7 @@ async function fetchModules(){
|
|||||||
|
|
||||||
function onclick(e){
|
function onclick(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
expand = false;
|
||||||
let href = e.target.getAttribute('href');
|
let href = e.target.getAttribute('href');
|
||||||
if (href) router.navigate(href);
|
if (href) router.navigate(href);
|
||||||
return false;
|
return false;
|
||||||
@@ -34,6 +36,7 @@ function onclick(e){
|
|||||||
|
|
||||||
async function search(e){
|
async function search(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
expand = false;
|
||||||
router.navigate(`/search?key=${key}`);
|
router.navigate(`/search?key=${key}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -47,11 +50,12 @@ onMount(fetchModules);
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<nav>
|
<nav class={expand?"expanded":"collapsed"}>
|
||||||
<form onsubmit={search}>
|
<form onsubmit={search}>
|
||||||
<input type="text" bind:value={key} />
|
<input type="text" bind:value={key} />
|
||||||
<button type="submit">{t('search')}</button>
|
<button type="submit">{t('search')}</button>
|
||||||
</form>
|
</form>
|
||||||
|
<button class="symbol" onclick={e => expand = !expand}></button>
|
||||||
<a href="/user" {onclick} class="user">{t('users')}</a>
|
<a href="/user" {onclick} class="user">{t('users')}</a>
|
||||||
<a href="/company" {onclick} class="company">{t('companies')}</a>
|
<a href="/company" {onclick} class="company">{t('companies')}</a>
|
||||||
<a href="/project" {onclick} class="project">{t('projects')}</a>
|
<a href="/project" {onclick} class="project">{t('projects')}</a>
|
||||||
@@ -72,7 +76,7 @@ onMount(fetchModules);
|
|||||||
{#if module.name.trim()}<a href={module.url}>{module.name}</a>{/if}
|
{#if module.name.trim()}<a href={module.url}>{module.name}</a>{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{#if user.name }
|
{#if user.name }
|
||||||
<a onclick={logout}>{t('logout_user',{user:user.name})}</a>
|
<a class="logout" onclick={logout}>{t('logout_user',{user:user.name})}</a>
|
||||||
{/if}
|
{/if}
|
||||||
<TimeRecorder />
|
<TimeRecorder />
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -14,6 +14,23 @@
|
|||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
let editable = $derived(document.state == 1);
|
let editable = $derived(document.state == 1);
|
||||||
|
let sums = $derived.by(calcSums);
|
||||||
|
|
||||||
|
function calcSums(){
|
||||||
|
let data = {}
|
||||||
|
let net = 0;
|
||||||
|
let gross = 0;
|
||||||
|
for (let pos of Object.values(document.positions)){
|
||||||
|
let net_price = pos.unit_price * pos.amount;
|
||||||
|
let tax = +pos.tax;
|
||||||
|
data[tax] = net_price + (data[tax] ? data[tax] : 0);
|
||||||
|
net += net_price;
|
||||||
|
}
|
||||||
|
for (let [tax, price] of Object.entries(data)) gross += price * (+tax+100)/100;
|
||||||
|
data['net'] = net/100;
|
||||||
|
data['gross'] = (gross/100).toFixed(2);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
async function updatePositions(resp){
|
async function updatePositions(resp){
|
||||||
let json = await resp.json();
|
let json = await resp.json();
|
||||||
@@ -22,7 +39,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function movePos(number,step){
|
async function movePos(number,step){
|
||||||
const url = api(`document/${document.id}/position`);
|
const url = api(`document/${document.id}/position`);
|
||||||
const resp = await fetch(url,{
|
const resp = await fetch(url,{
|
||||||
method : 'PATCH',
|
method : 'PATCH',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
@@ -38,7 +55,7 @@
|
|||||||
async function drop(number){
|
async function drop(number){
|
||||||
let confirmed = confirm(t('confirm_deletion').replace('{pos}',document.positions[number].item));
|
let confirmed = confirm(t('confirm_deletion').replace('{pos}',document.positions[number].item));
|
||||||
if (!confirmed) return;
|
if (!confirmed) return;
|
||||||
const url = api(`document/${document.id}/position`);
|
const url = api(`document/${document.id}/position`);
|
||||||
const resp = await fetch(url,{
|
const resp = await fetch(url,{
|
||||||
method : 'DELETE',
|
method : 'DELETE',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
@@ -73,9 +90,9 @@
|
|||||||
<tr class="sums">
|
<tr class="sums">
|
||||||
<td colspan="2"></td>
|
<td colspan="2"></td>
|
||||||
<td>{t('net_sum')}</td>
|
<td>{t('net_sum')}</td>
|
||||||
<td>{document.net_sum/100} {document.currency}</td>
|
<td>{sums['net']} {document.currency}</td>
|
||||||
<td colspan="2">{t('gross_sum')}</td>
|
<td colspan="2">{t('gross_sum')}</td>
|
||||||
<td>{document.gross_sum/100} {document.currency}</td>
|
<td>{sums['gross']} {document.currency}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -78,8 +78,10 @@
|
|||||||
if (!tasks[user_id][state]) tasks[user_id][state] = {};
|
if (!tasks[user_id][state]) tasks[user_id][state] = {};
|
||||||
tasks[user_id][state][task.id] = task;
|
tasks[user_id][state][task.id] = task;
|
||||||
yikes();
|
yikes();
|
||||||
|
return 'reset';
|
||||||
} else {
|
} else {
|
||||||
error(resp);
|
error(resp);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +257,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
<div class="add_task">
|
<div class="add_task">
|
||||||
<LineEditor value={t('add_object',{object:t('task')})} editable={true} onSet={(name) => create(name,uid,state)}/>
|
<LineEditor value={t('add_object',{object:t('task')})} editable={true} onSet={(name) => create(name,u.id,state)}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function measured(evt,duration,d){
|
function measured(evt,duration,d){
|
||||||
if (d > 100) return;
|
if (d > 10) return;
|
||||||
if (duration < 500){
|
if (duration < 500){
|
||||||
onclick(evt);
|
onclick(evt);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ CREATE TABLE IF NOT EXISTS {0} (
|
|||||||
if (rs.next()) project = Project.of(rs);
|
if (rs.next()) project = Project.of(rs);
|
||||||
rs.close();
|
rs.close();
|
||||||
|
|
||||||
if (project == null) throw UmbrellaException.notFound("No project found for id {0}",projectId);
|
if (project == null) throw UmbrellaException.notFound("no_project_for_id",projectId);
|
||||||
|
|
||||||
rs = select(ALL).from(TABLE_CUSTOM_STATES).where(PROJECT_ID,equal(projectId)).exec(db);
|
rs = select(ALL).from(TABLE_CUSTOM_STATES).where(PROJECT_ID,equal(projectId)).exec(db);
|
||||||
var states = project.allowedStates();
|
var states = project.allowedStates();
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ CREATE TABLE IF NOT EXISTS {0} (
|
|||||||
public Task load(long taskId) throws UmbrellaException {
|
public Task load(long taskId) throws UmbrellaException {
|
||||||
var map = load(List.of(taskId));
|
var map = load(List.of(taskId));
|
||||||
var task = map.get(taskId);
|
var task = map.get(taskId);
|
||||||
if (task == null) throw UmbrellaException.notFound("No task found for id {0}",taskId);
|
if (task == null) throw UmbrellaException.notFound("no_task_for_id",taskId);
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,6 +183,8 @@
|
|||||||
"new_password": "neues Passwort",
|
"new_password": "neues Passwort",
|
||||||
"new_property": "neue Eigenschaft",
|
"new_property": "neue Eigenschaft",
|
||||||
"no_company": "keine Firma",
|
"no_company": "keine Firma",
|
||||||
|
"no_project_for_id": "Kein Projekt mit ID {0} gefunden!",
|
||||||
|
"no_task_for_id": "Keine Aufgabe mit ID {0} gefunden!",
|
||||||
"note": "Notiz",
|
"note": "Notiz",
|
||||||
"notes": "Notizen",
|
"notes": "Notizen",
|
||||||
"not_recent_version": "Die ist nicht die neuste Version dieser Seite!",
|
"not_recent_version": "Die ist nicht die neuste Version dieser Seite!",
|
||||||
|
|||||||
@@ -183,6 +183,8 @@
|
|||||||
"new_password": "new password",
|
"new_password": "new password",
|
||||||
"new_property": "new property",
|
"new_property": "new property",
|
||||||
"no_company": "no company",
|
"no_company": "no company",
|
||||||
|
"no_project_for_id": "No project found for id {0}",
|
||||||
|
"no_task_for_id": "No task found for id {0}",
|
||||||
"note": "note",
|
"note": "note",
|
||||||
"notes": "notes",
|
"notes": "notes",
|
||||||
"not_recent_version": "This is not the current version of this page!",
|
"not_recent_version": "This is not the current version of this page!",
|
||||||
@@ -322,4 +324,4 @@
|
|||||||
"year": "year",
|
"year": "year",
|
||||||
"your_password_reset_token" : "Your token to create a new password",
|
"your_password_reset_token" : "Your token to create a new password",
|
||||||
"your_profile": "your profile"
|
"your_profile": "your profile"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,4 +307,11 @@ tr:hover .taglist .tag button {
|
|||||||
|
|
||||||
.easylist .filter{
|
.easylist .filter{
|
||||||
background: black;
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
#app nav a{
|
||||||
|
background: black;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -426,6 +426,58 @@ a.wikilink{
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 900px) {
|
||||||
|
#app nav > button.symbol{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
body{
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
#app nav{
|
||||||
|
grid-template-columns: 33% 34% 33%;
|
||||||
|
display: grid;
|
||||||
|
padding: 0 10px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
#app nav form{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
|
#app nav .logout{
|
||||||
|
grid-column-end: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav.collapsed a{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav a {
|
||||||
|
font-size: 19px !important;
|
||||||
|
display: grid;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid;
|
||||||
|
margin: 5px;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav a::before {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
#app nav .timetracking{
|
||||||
|
grid-column-end: span 3;
|
||||||
|
font-size: 19px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#app nav.expanded .timetracking{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
.grid2{
|
.grid2{
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -455,6 +507,18 @@ a.wikilink{
|
|||||||
.easylist input{
|
.easylist input{
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
#app nav{
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
#app nav form{
|
||||||
|
grid-column-end: span 1;
|
||||||
|
}
|
||||||
|
#app nav .logout{
|
||||||
|
grid-column-end: 3;
|
||||||
|
}
|
||||||
|
#app nav.expanded .timetracking{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.vcard{
|
fieldset.vcard{
|
||||||
|
|||||||
@@ -297,4 +297,11 @@ tr:hover .taglist .tag button {
|
|||||||
|
|
||||||
.easylist .filter{
|
.easylist .filter{
|
||||||
background: black;
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
#app nav a{
|
||||||
|
background: black;
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -504,8 +504,83 @@ a.wikilink{
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 900px) {
|
||||||
|
#app nav > button.symbol{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
body{
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
#app nav{
|
||||||
|
grid-template-columns: 33% 34% 33%;
|
||||||
|
display: grid;
|
||||||
|
padding: 0 10px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
#app nav form{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
|
#app nav .logout{
|
||||||
|
grid-column-end: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav.collapsed a{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav a {
|
||||||
|
font-size: 19px !important;
|
||||||
|
display: grid;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid;
|
||||||
|
margin: 5px;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav a::before {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
#app nav .timetracking{
|
||||||
|
grid-column-end: span 3;
|
||||||
|
font-size: 19px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#app nav.expanded .timetracking{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.grid3 {
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid3 .properties{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
.grid3 .tags{
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
.grid3 .notes{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
order: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid3 .locations{
|
||||||
|
order: 5;
|
||||||
|
}
|
||||||
|
.grid3 .items{
|
||||||
|
order: 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
.grid2{
|
.grid2,
|
||||||
|
.grid3{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto;
|
grid-template-columns: auto;
|
||||||
}
|
}
|
||||||
@@ -533,6 +608,21 @@ a.wikilink{
|
|||||||
.easylist input{
|
.easylist input{
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
#app nav{
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
#app nav form,
|
||||||
|
.grid3 .notes,
|
||||||
|
.grid3 .tags,
|
||||||
|
.grid3 .properties{
|
||||||
|
grid-column-end: span 1;
|
||||||
|
}
|
||||||
|
#app nav .logout{
|
||||||
|
grid-column-end: 3;
|
||||||
|
}
|
||||||
|
#app nav.expanded .timetracking{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.vcard{
|
fieldset.vcard{
|
||||||
|
|||||||
@@ -282,4 +282,11 @@ tr:hover .taglist .tag button {
|
|||||||
.easylist fieldset {
|
.easylist fieldset {
|
||||||
border-color: blue;
|
border-color: blue;
|
||||||
color: blue;
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
#app nav a{
|
||||||
|
background: white;
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -426,6 +426,58 @@ a.wikilink{
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 900px) {
|
||||||
|
#app nav > button.symbol{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
body{
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
#app nav{
|
||||||
|
grid-template-columns: 33% 34% 33%;
|
||||||
|
display: grid;
|
||||||
|
padding: 0 10px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
#app nav form{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
|
#app nav .logout{
|
||||||
|
grid-column-end: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav.collapsed a{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav a {
|
||||||
|
font-size: 19px !important;
|
||||||
|
display: grid;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid;
|
||||||
|
margin: 5px;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app nav a::before {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
#app nav .timetracking{
|
||||||
|
grid-column-end: span 3;
|
||||||
|
font-size: 19px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#app nav.expanded .timetracking{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
.grid2{
|
.grid2{
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -455,6 +507,18 @@ a.wikilink{
|
|||||||
.easylist input{
|
.easylist input{
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
#app nav{
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
#app nav form{
|
||||||
|
grid-column-end: span 1;
|
||||||
|
}
|
||||||
|
#app nav .logout{
|
||||||
|
grid-column-end: 3;
|
||||||
|
}
|
||||||
|
#app nav.expanded .timetracking{
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset.vcard{
|
fieldset.vcard{
|
||||||
|
|||||||
Reference in New Issue
Block a user