feat: refactorer interface création/édition notes avec input Google Keep-like (expand on focus, formatting toolbar avec boutons B/I/U/H1-H3/liste/lien, textarea auto-resize), modal édition unifiée avec textarea source éditable, styles dark mode optimisés (backgrounds #202124, shadows rgba), hover actions repositionnés (gap 2px, margin-left -6px, opacity 0.7→1), note cards avec transitions cubic-bezier et border-color transparent au hover, et amélioration générale UX avec animations fade

This commit is contained in:
Bruno Charest 2026-02-22 09:28:37 -05:00
parent 73d3a968a8
commit 8b62046fa7
3 changed files with 1091 additions and 119 deletions

View File

@ -229,8 +229,15 @@ body.view-notes .content-container {
align-items: flex-start; align-items: flex-start;
margin-bottom: 2rem; margin-bottom: 2rem;
position: relative; position: relative;
padding-right: 60px; padding-right: 0;
/* Space for toggle */ }
.notes-top-bar-inner {
width: 600px;
max-width: 100%;
display: flex;
align-items: flex-start;
gap: 12px;
} }
.note-input-container { .note-input-container {
@ -243,10 +250,14 @@ body.view-notes .content-container {
overflow: hidden; overflow: hidden;
} }
.note-input-container.is-editing {
max-height: 72vh;
}
[data-theme="dark"] .note-input-container { [data-theme="dark"] .note-input-container {
background-color: var(--bg-sidebar); background-color: #202124;
border: 1px solid var(--border); border: none;
box-shadow: none; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.6), 0 2px 6px 2px rgba(0, 0, 0, 0.4);
} }
.note-input-collapsed { .note-input-collapsed {
@ -259,6 +270,188 @@ body.view-notes .content-container {
font-size: 1rem; font-size: 1rem;
} }
.note-input-container.is-editing {
cursor: default;
}
.note-input-expanded {
display: flex;
flex-direction: column;
gap: 10px;
padding: 12px 16px 10px;
max-height: 72vh;
}
.note-input-title {
width: 100%;
border: 0;
outline: none;
background: transparent;
color: inherit;
font-size: 1.05rem;
font-weight: 500;
padding: 0;
}
.note-input-description-source {
width: 100%;
border: none;
background: transparent;
color: inherit;
padding: 0;
resize: none;
min-height: 120px;
max-height: 44vh;
overflow: auto;
outline: none;
display: block;
font-size: 0.95rem;
line-height: 1.5;
}
.note-input-description-source:focus {
outline: none;
}
[data-theme="dark"] .note-input-description-source {
border: none;
}
.note-input-container.is-enhanced .note-input-description-source {
display: none;
}
.note-formatting-bar {
display: none;
align-items: center;
gap: 4px;
padding: 6px 12px;
border-radius: 24px;
background: rgba(0, 0, 0, 0.04);
border: 1px solid rgba(0, 0, 0, 0.08);
width: fit-content;
max-width: 100%;
overflow-x: auto;
margin: 4px 0;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
[data-theme="dark"] .note-formatting-bar {
background: rgba(255, 255, 255, 0.06);
border-color: rgba(255, 255, 255, 0.12);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.note-formatting-bar.open {
display: inline-flex;
animation: fadeIn 0.15s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.note-format-btn {
appearance: none;
background: transparent;
border: none;
color: inherit;
height: 32px;
min-width: 32px;
padding: 0 8px;
border-radius: 16px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 0.85rem;
opacity: 0.85;
flex: 0 0 auto;
transition: all 0.15s ease;
}
.note-format-btn:hover {
opacity: 1;
background: rgba(0, 0, 0, 0.08);
transform: scale(1.05);
}
[data-theme="dark"] .note-format-btn:hover {
background: rgba(255, 255, 255, 0.14);
}
.note-format-btn:active {
transform: scale(0.95);
}
.note-format-sep {
width: 1px;
height: 16px;
background: rgba(0, 0, 0, 0.12);
margin: 0 4px;
flex: 0 0 auto;
}
[data-theme="dark"] .note-format-sep {
background: rgba(255, 255, 255, 0.15);
}
.note-input-actions-left {
display: flex;
align-items: center;
gap: 2px;
flex-wrap: wrap;
}
.note-input-actions-left > button {
background: transparent;
border: none;
color: inherit;
opacity: 0.9;
width: 32px;
height: 32px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 0;
}
.note-input-actions-left > button:disabled {
cursor: default;
opacity: 0.35;
}
.note-input-actions-left > button:hover:not(:disabled) {
opacity: 1;
background: rgba(0, 0, 0, 0.08);
}
[data-theme="dark"] .note-input-actions-left > button:hover:not(:disabled) {
background: rgba(255, 255, 255, 0.14);
}
.note-input-close-btn {
background: transparent;
border: none;
color: inherit;
font-weight: 600;
border-radius: 8px;
padding: 6px 10px;
cursor: pointer;
}
.note-input-close-btn:hover {
background: rgba(136, 136, 136, 0.1);
}
[data-theme="dark"] .note-input-close-btn:hover {
background: rgba(255, 255, 255, 0.14);
}
.note-input-placeholder { .note-input-placeholder {
flex: 1; flex: 1;
} }
@ -329,7 +522,6 @@ body.view-notes .content-container {
color: #e8eaed; color: #e8eaed;
} }
/* --- LOGIC: Masonry vs List --- */ /* --- LOGIC: Masonry vs List --- */
/* Masonry Grid */ /* Masonry Grid */
@ -391,17 +583,23 @@ body.view-notes .content-container {
width: min(720px, 92vw); width: min(720px, 92vw);
max-height: 86vh; max-height: 86vh;
overflow: hidden; overflow: hidden;
border-radius: 12px; border-radius: 8px;
background: var(--background-secondary, #ffffff); background: var(--background-secondary, #ffffff);
border: 1px solid rgba(0, 0, 0, 0.12); border: 1px solid rgba(0, 0, 0, 0.12);
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
color: inherit; color: inherit;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
body.note-modal-open {
overflow: hidden;
}
[data-theme="dark"] .note-modal { [data-theme="dark"] .note-modal {
background: #202124; background: #202124;
border-color: rgba(255, 255, 255, 0.12); border-color: transparent;
box-shadow: 0 14px 28px rgba(0,0,0,0.5), 0 10px 10px rgba(0,0,0,0.4);
} }
.note-modal-header { .note-modal-header {
@ -421,22 +619,47 @@ body.view-notes .content-container {
font-weight: 500; font-weight: 500;
} }
.note-modal-title-input {
width: 100%;
border: 0;
outline: none;
background: transparent;
color: inherit;
padding: 0;
}
.note-modal-content { .note-modal-content {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 0 20px 18px; padding: 0;
} }
.note-modal .note-body { .note-modal-description-source {
font-size: 1rem; width: 100%;
line-height: 1.75; border: none;
display: block; background: transparent;
-webkit-line-clamp: initial;
line-clamp: initial;
-webkit-box-orient: initial;
max-height: none;
overflow: visible;
color: inherit; color: inherit;
padding: 0;
resize: none;
min-height: 200px;
max-height: 58vh;
overflow: auto;
outline: none;
display: block;
font-size: 0.95rem;
line-height: 1.5;
}
.note-modal-description-source:focus {
outline: none;
}
[data-theme="dark"] .note-modal-description-source {
border: none;
}
.note-modal-overlay.is-enhanced .note-modal-description-source {
display: none;
} }
.note-modal .note-body * { .note-modal .note-body * {
@ -447,15 +670,10 @@ body.view-notes .content-container {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 8px;
padding: 10px 20px 12px; padding: 0 20px 12px;
border-top: 1px solid rgba(0, 0, 0, 0.12);
flex-shrink: 0; flex-shrink: 0;
} }
[data-theme="dark"] .note-modal-tags {
border-top-color: rgba(255, 255, 255, 0.12);
}
.note-modal-tags.is-empty { .note-modal-tags.is-empty {
display: none; display: none;
} }
@ -501,16 +719,14 @@ body.view-notes .content-container {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 6px; gap: 6px;
padding: 8px 12px; padding: 8px 16px 16px;
border-top: 1px solid rgba(0, 0, 0, 0.12); background: transparent;
background: rgba(0, 0, 0, 0.03);
flex-shrink: 0; flex-shrink: 0;
flex-wrap: wrap; flex-wrap: wrap;
} }
[data-theme="dark"] .note-modal-actions { [data-theme="dark"] .note-modal-actions {
border-top-color: rgba(255, 255, 255, 0.12); background: transparent;
background: rgba(255, 255, 255, 0.06);
} }
.note-modal-actions-left { .note-modal-actions-left {
@ -597,28 +813,31 @@ body.view-notes .content-container {
/* --- CARD STYLING --- */ /* --- CARD STYLING --- */
.note-card { .note-card {
background-color: var(--background-secondary, #ffffff); background-color: var(--background-secondary, #ffffff);
border: 1px solid #e0e0e0; border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 8px; border-radius: 8px;
margin-bottom: 16px; margin-bottom: 16px;
break-inside: avoid; break-inside: avoid;
position: relative; position: relative;
transition: box-shadow 0.2s, transform 0.2s, background-color 0.2s; transition: box-shadow 0.2s cubic-bezier(0.4, 0.0, 0.2, 1), transform 0.2s cubic-bezier(0.4, 0.0, 0.2, 1), border-color 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
overflow: visible; overflow: visible;
color: var(--note-card-fg, #202124); color: var(--note-card-fg, #202124);
} }
[data-theme="dark"] .note-card { [data-theme="dark"] .note-card {
background-color: #202124; background-color: #202124;
border: 1px solid #5f6368; border-color: #5f6368;
color: #e8eaed; color: #e8eaed;
} }
.note-card:hover { .note-card:hover {
box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15); box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);
border-color: transparent;
} }
[data-theme="dark"] .note-card:hover { [data-theme="dark"] .note-card:hover {
background-color: #202124; background-color: #202124;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.6), 0 1px 3px 1px rgba(0, 0, 0, 0.4);
border-color: transparent;
} }
/* Cover Image */ /* Cover Image */
@ -687,17 +906,17 @@ body.view-notes .content-container {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.25rem; gap: 0.25rem;
background: var(--tag-bg); background: var(--tag-bg, #f1f3f4);
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
border-radius: 999px; border-radius: 999px;
font-size: 0.75rem; font-size: 0.75rem;
font-weight: 500; font-weight: 500;
color: var(--tag-text); color: var(--tag-text, #3c4043);
} }
[data-theme="dark"] .note-tag { [data-theme="dark"] .note-tag {
background: var(--tag-bg); background: var(--tag-bg, #3c4043);
color: var(--tag-text); color: var(--tag-text, #e8eaed);
} }
.note-tag-text { .note-tag-text {
@ -738,18 +957,15 @@ body.view-notes .content-container {
.note-hover-actions { .note-hover-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0px; gap: 2px;
/* evenly spaced */ margin-top: 12px;
margin-top: 8px; margin-left: -6px;
margin-left: -8px;
/* Alignment fix */
color: var(--text-light, #5f6368); color: var(--text-light, #5f6368);
opacity: 0; opacity: 0;
/* Hidden by default */ transition: opacity 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
transition: opacity 0.2s;
position: relative; position: relative;
/* For palette popup */
z-index: 2; z-index: 2;
min-height: 34px;
} }
[data-theme="dark"] .note-hover-actions { [data-theme="dark"] .note-hover-actions {
@ -771,27 +987,35 @@ body.view-notes .content-container {
.note-hover-actions > button, .note-hover-actions > button,
.note-hover-actions > a, .note-hover-actions > a,
.note-hover-actions > div > button { .note-hover-actions > div > button {
background: none; background: transparent;
border: none; border: none;
width: 34px; width: 32px;
/* Touch target */ height: 32px;
height: 34px;
border-radius: 50%; border-radius: 50%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: inherit; color: inherit;
cursor: pointer; cursor: pointer;
font-size: 1.1rem; font-size: 1.15rem;
transition: background-color 0.2s, color 0.2s; transition: background-color 0.15s, color 0.15s, opacity 0.15s;
text-decoration: none; text-decoration: none;
opacity: 0.7;
} }
.note-hover-actions > button:hover, .note-hover-actions > button:hover,
.note-hover-actions > a:hover, .note-hover-actions > a:hover,
.note-hover-actions > div > button:hover { .note-hover-actions > div > button:hover {
background-color: rgba(136, 136, 136, 0.2); background-color: rgba(0, 0, 0, 0.08);
color: var(--text-color); color: var(--text-color, #202124);
opacity: 1;
}
[data-theme="dark"] .note-hover-actions > button:hover,
[data-theme="dark"] .note-hover-actions > a:hover,
[data-theme="dark"] .note-hover-actions > div > button:hover {
background-color: rgba(255, 255, 255, 0.14);
color: #e8eaed;
} }
.bookmark-palette { .bookmark-palette {
@ -1487,6 +1711,7 @@ body.view-notes .content-container {
.note-card.note-has-bg, .note-card.note-has-bg,
.note-modal.note-has-bg, .note-modal.note-has-bg,
.note-input-container.note-has-bg,
.link-outer.note-has-bg { .link-outer.note-has-bg {
background-image: linear-gradient(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.16)), var(--note-bg-image); background-image: linear-gradient(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.16)), var(--note-bg-image);
background-size: cover; background-size: cover;
@ -1496,6 +1721,8 @@ body.view-notes .content-container {
.note-card.todo-card.note-has-bg[data-font-color="auto"] { .note-card.todo-card.note-has-bg[data-font-color="auto"] {
--note-card-fg: rgba(255, 255, 255, 0.92); --note-card-fg: rgba(255, 255, 255, 0.92);
color: var(--note-card-fg); color: var(--note-card-fg);
background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), var(--note-bg-image);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), var(--note-bg-image); background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), var(--note-bg-image);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
} }

View File

@ -24,13 +24,13 @@
<!-- Professional Theme CSS --> <!-- Professional Theme CSS -->
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/css/style.css?v=1.0.4" /> <link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/css/style.css?v=1.0.4" />
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/css/custom_views.css?v=1.0.4" /> <link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/css/custom_views.css?v=1.0.5" />
{if="$pageName=='editlink' || $pageName=='addlink' || $pageName=='editlinkbatch'"} {if="$pageName=='editlink' || $pageName=='addlink' || $pageName=='editlinkbatch'"}
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/css/awesomplete.css?v=1.0.4" /> <link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/css/awesomplete.css?v=1.0.4" />
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/awesomplete.min.js?v=1.0.4" defer></script> <script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/awesomplete.min.js?v=1.0.4" defer></script>
{/if} {/if}
{if="$pageName=='editlink' || $pageName=='editlinkbatch'"} {if="$pageName=='editlink' || $pageName=='editlinkbatch' || ($pageName=='linklist' && isset($search_tags) && preg_match('/(^|[\s,])note([\s,]|$)/i', (string) $search_tags))"}
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" /> <link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/theme/toastui-editor-dark.min.css" /> <link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/theme/toastui-editor-dark.min.css" />
<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js" defer></script> <script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js" defer></script>
@ -61,14 +61,14 @@ var shaarli = {
basePath: '{$base_path}', basePath: '{$base_path}',
rootPath: '{$root_path}', rootPath: '{$root_path}',
assetPath: '{$base_path}{$asset_path}', assetPath: '{$base_path}{$asset_path}',
isAuth: {if="$is_logged_in"}true{else}false{/if}, isAuth: (function(){/*{if="$is_logged_in"}*/return true;/*{else}*/return false;/*{/if}*/})(),
pageName: '{$pageName}', pageName: '{$pageName}',
visibility: '{$visibility}', visibility: '{$visibility}',
untaggedonly: {if="$untaggedonly"}true{else}false{/if} untaggedonly: (function(){/*{if="$untaggedonly"}*/return true;/*{else}*/return false;/*{/if}*/})()
}; };
</script> </script>
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/script.js?v=1.0.5" defer></script> <script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/script.js?v=1.0.5" defer></script>
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/custom_views.js?v=1.0.5" defer></script> <script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/custom_views.js?v=1.0.6" defer></script>
{if="file_exists('tpl/shaarli-pro/extra.html')"} {if="file_exists('tpl/shaarli-pro/extra.html')"}
{include="extra"} {include="extra"}

File diff suppressed because it is too large Load Diff