summaryrefslogtreecommitdiff
path: root/src/style.chat.css
diff options
context:
space:
mode:
Diffstat (limited to 'src/style.chat.css')
-rw-r--r--src/style.chat.css710
1 files changed, 710 insertions, 0 deletions
diff --git a/src/style.chat.css b/src/style.chat.css
new file mode 100644
index 0000000..e251887
--- /dev/null
+++ b/src/style.chat.css
@@ -0,0 +1,710 @@
+/* Chat-related */
+body.chat span.at-name { /* for @USERNAME references */
+ text-decoration: underline;
+ font-weight: bold;
+}
+/* A wrapper for a single single chat message (one row of the UI) */
+body.chat .message-widget {
+ margin-bottom: 0.75em;
+ border: none;
+ display: flex;
+ flex-direction: column;
+ border: none;
+ align-items: flex-start;
+}
+body.chat button,
+body.chat input[type=button] {
+ line-height: inherit/*undo skin-specific funkiness*/;
+}
+body.chat .message-widget:last-of-type {
+ /* Latest message: reduce bottom gap */
+ margin-bottom: 0.1em;
+}
+body.chat.my-messages-right .message-widget.mine {
+ /* Right-aligns a user's own chat messages, similar to how
+ most/some mobile messaging apps do it. */
+ align-items: flex-end;
+}
+body.chat.my-messages-right .message-widget.notification {
+ /* Center-aligns a system-level notification message. */
+ align-items: center;
+}
+/* The content area of a message. */
+body.chat .message-widget-content {
+ border-radius: 0.25em;
+ border: 1px solid rgba(0,0,0,0.2);
+ box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
+ padding: 0.25em 0.5em;
+ margin-top: 0;
+ min-width: 9em /*avoid unsightly "underlap" with the neighboring
+ .message-widget-tab element*/;
+ white-space: normal;
+ word-break: break-word /* so that full hashes wrap on narrow screens */;
+}
+
+body.chat .message-widget-content.wide {
+ /* Special case for when embedding content which we really want to
+ expand, namely iframes. */
+ width: 98%;
+}
+body.chat .message-widget-content label[for] {
+ margin-left: 0.25em;
+ cursor: pointer;
+}
+body.chat .message-widget-content > .attachment-link {
+ display: flex;
+ flex-direction: row;
+}
+body.chat .message-widget-content > .attachment-link > a {
+ margin-right: 1em;
+}
+body.chat .message-widget-content > iframe {
+ width: 100%;
+ max-width: 100%;
+ resize: both;
+}
+body.chat .message-widget-content> a {
+ /* Cosmetic: keep skin-induced on-hover underlining from shifting
+ content placed below this. */
+ border-bottom: 1px transparent;
+}
+body.chat.monospace-messages .message-widget-content,
+body.chat.monospace-messages .chat-input-field{
+ font-family: monospace;
+}
+body.chat .message-widget-content > * {
+ margin: 0;
+ padding: 0;
+}
+body.chat .message-widget-content > pre {
+ white-space: pre-wrap;
+}
+body.chat .message-widget-content > .markdown > *:first-child {
+ margin-top: 0;
+}
+body.chat .message-widget-content > .markdown > *:last-child {
+ margin-bottom: 0;
+}
+body.chat .message-widget-content.error .buttons {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ flex-wrap: wrap;
+}
+body.chat .message-widget-content.error .buttons > button {
+ margin: 0.25em;
+}
+
+body.chat .message-widget-content.error a {
+ color: inherit;
+}
+body.chat .message-widget-content.error .failed-message {
+ display: flex;
+ flex-direction: column;
+}
+body.chat .message-widget-content.error .failed-message textarea {
+ min-height: 5rem;
+}
+
+/* User name and timestamp (a LEGEND-like element) */
+body.chat .message-widget .message-widget-tab {
+ border-radius: 0.25em 0.25em 0 0;
+ margin: 0 0.25em 0em 0.15em;
+ padding: 0 0.5em 0.15em 0.5em;
+ cursor: pointer;
+ white-space: nowrap;
+}
+body.chat .fossil-tooltip.help-buttonlet-content {
+ font-size: 80%;
+}
+
+body.chat .message-widget .message-widget-tab {
+ /* Element which renders the main metadata for a given message. */
+}
+body.chat .message-widget .message-widget-tab .xfrom {
+ /* xfrom part of the message tab */
+ font-style: italic;
+ font-weight: bold;
+}
+
+body.chat .message-widget .message-widget-tab .mtime {
+ /* mtime part of the message tab */
+}
+
+body.chat .message-widget .message-widget-tab .msgid {
+ /* msgid part of the message tab */
+}
+
+body.chat .message-widget .match {
+ font-weight: bold;
+ background-color: yellow;
+}
+
+body.chat.fossil-dark-style .message-widget .match {
+ background-color: #ff4800;
+}
+
+/* The popup element for displaying message timestamps
+ and deletion controls. */
+body.chat .chat-message-popup {
+ font-family: monospace;
+ font-size: 0.9em;
+ text-align: left;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ padding: 0.25em;
+ margin-top: 0.25em;
+ border: 1px outset;
+ border-radius: 0.5em;
+}
+/* Full message timestamps. */
+body.chat .chat-message-popup > span { white-space: nowrap; }
+/* Container for the message deletion buttons. */
+body.chat .chat-message-popup > .toolbar {
+ padding: 0;
+ margin: 0;
+ border: 2px inset rgba(0,0,0,0.3);
+ border-radius: 0.25em;
+ display: flex;
+ flex-direction: row;
+ justify-content: stretch;
+ flex-wrap: wrap;
+ align-items: center;
+}
+body.chat .chat-message-popup > .toolbar > * {
+ margin: 0.35em;
+}
+body.chat .chat-message-popup > .toolbar > button {
+ flex: 1 1 auto;
+}
+/* The widget for loading more/older chat messages. */
+body.chat #load-msg-toolbar {
+ border-radius: 0.25em;
+ padding: 0.1em 0.2em;
+ margin-bottom: 1em;
+}
+/* .all-done is set when chat has loaded all of the available
+ historical messages */
+body.chat #load-msg-toolbar.all-done {
+ opacity: 0.5;
+}
+body.chat #load-msg-toolbar > div {
+ display: flex;
+ flex-direction: row;
+ justify-content: stretch;
+ flex-wrap: wrap;
+}
+body.chat #load-msg-toolbar > div > button {
+ flex: 1 1 auto;
+}
+/* "Chat-only mode" hides the site header/footer, showing only
+ the chat app. */
+body.chat.chat-only-mode{
+ padding: 0;
+ margin: 0 auto;
+}
+body.chat #chat-button-settings {}
+
+/** Container for the list of /chat messages. */
+body.chat #chat-messages-wrapper {
+ overflow: auto;
+ padding: 0 0.25em;
+}
+body.chat #chat-messages-wrapper.loading > * {
+ /* An attempt at reducing flicker when loading lots of messages. */
+ visibility: hidden;
+}
+
+/* Provide a visual cue when polling is offline. */
+body.chat.connection-error #chat-input-line-wrapper {
+ border-top: medium dotted red;
+}
+body.chat.fossil-dark-style.connection-error #chat-input-line-wrapper {
+ border-color: yellow;
+}
+
+body.chat div.content {
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column-reverse;
+ /* ^^^^ In order to get good automatic scrolling of new messages on
+ the BOTTOM in bottom-up chat mode, such that they scroll up
+ instead of down, we have to use column-reverse layout, which
+ changes #chat-messages-wrapper's "gravity" for purposes of
+ scrolling! If we instead use flex-direction:column then each new
+ message pushes #chat-input-area down further off the screen!
+ */
+ align-items: stretch;
+}
+/* Wrapper for /chat user input controls */
+body.chat #chat-input-area {
+ display: flex;
+ flex-direction: column;
+ padding: 0;
+ margin: 0;
+ flex: 0 1 auto;
+}
+body.chat:not(.chat-only-mode) #chat-input-area{
+ /* Safari user reports that 2em is necessary to keep the file selection
+ widget from overlapping the page footer, whereas a margin of 0 is fine
+ for FF/Chrome (and 2em is a *huge* waste of space for those). */
+ margin-bottom: 0;
+}
+
+body.chat .chat-input-field {
+ flex: 10 1 auto;
+ margin: 0;
+}
+body.chat #chat-input-field-x,
+body.chat #chat-input-field-multi {
+ overflow: auto;
+ resize: vertical;
+}
+body.chat #chat-input-field-x {
+ display: inline-block/*supposed workaround for Chrome weirdness*/;
+ padding: 0.2em;
+ background-color: rgba(156,156,156,0.3);
+ white-space: pre-wrap;
+ /* ^^^ Firefox, when pasting plain text into a contenteditable field,
+ loses all newlines unless we explicitly set this. Chrome does not. */
+ cursor: text;
+ /* ^^^ In some browsers the cursor may not change for a contenteditable
+ element until it has focus, causing potential confusion. */
+}
+body.chat #chat-input-field-x:empty::before {
+ content: attr(data-placeholder);
+ opacity: 0.6;
+}
+body.chat .chat-input-field:not(:focus){
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 0.25em;
+}
+body.chat .chat-input-field:focus{
+ /* This transparent border helps avoid the text shifting around
+ when the contenteditable attribute causes a border (which we
+ apparently cannot style) to be added. */
+ border-width: 1px;
+ border-style: solid;
+ border-color: transparent;
+ border-radius: 0.25em;
+}
+/* Widget holding the chat message input field, send button, and
+ settings button. */
+body.chat #chat-input-line-wrapper {
+ display: flex;
+ flex-direction: row;
+ align-items: stretch;
+ flex-wrap: nowrap;
+}
+body.chat.chat-only-mode #chat-input-line-wrapper {
+ padding: 0 0.25em;
+}
+
+/*body.chat #chat-input-line-wrapper:not(.compact) {
+ flex-wrap: nowrap;
+}*/
+body.chat #chat-input-line-wrapper.compact {
+ /* "The problem" with wrapping, together with a contenteditable input
+ field, is that the latter grows as the user types, so causes
+ wrapping to happen while they type, then to unwrap as soon as the
+ input field is cleared (when the message is sent). When we stay
+ wrapped in compact mode, the wrapped buttons simply take up too
+ much space. */
+ /*flex-wrap: wrap;
+ justify-content: flex-end;*/
+ flex-direction: column;
+ /**
+ We "really do" need column orientation here because it's the
+ only way to eliminate the possibility that (A) the buttons
+ get truncated in very narrow windows and (B) that they keep
+ stable positions.
+ */
+}
+body.chat #chat-input-line-wrapper.compact #chat-input-field-x {
+}
+
+body.chat #chat-buttons-wrapper {
+ flex: 0 1 auto;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-width: 4em;
+ min-height: 1.5em;
+ align-self: flex-end
+ /*keep buttons stable at bottom/right even when input field
+ resizes */;
+}
+body.chat #chat-input-line-wrapper.compact #chat-buttons-wrapper {
+ flex-direction: row;
+ flex: 1 1 auto;
+ align-self: stretch;
+ justify-content: flex-end;
+ /*flex-wrap: wrap;*/
+ /* Wrapping would be ideal except that the edit widget
+ grows in width as the user types, moving the buttons
+ around */
+}
+body.chat #chat-buttons-wrapper > .cbutton {
+ padding: 0;
+ display: inline-block;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 0.25em;
+ min-width: 4ex;
+ max-width: 4ex;
+ min-height: 3ex;
+ max-height: 3ex;
+ margin: 0.125em;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ font-size: 130%;
+}
+body.chat #chat-buttons-wrapper > .cbutton:hover {
+ background-color: rgba(200,200,200,0.3);
+}
+body.chat #chat-input-line-wrapper.compact #chat-buttons-wrapper > .cbutton {
+ margin: 2px 0.125em 0 0.125em;
+ min-width: 4.5ex;
+ max-width: 4.5ex;
+ min-height: 2.3ex;
+ max-height: 2.3ex;
+ font-size: 120%;
+}
+body.chat #chat-input-line-wrapper.compact #chat-buttons-wrapper #chat-button-submit {
+ min-width: 10ex;
+}
+.chat-input-field {
+ font-family: inherit
+}
+body.chat #chat-input-line-wrapper:not(.compact) #chat-input-field-multi,
+body.chat #chat-input-line-wrapper:not(.compact) #chat-input-field-x {
+ min-height: 4rem;
+/*
+ Problems related to max-height:
+
+ - If we do NOT set a max-height then pasting/typing a large amount
+ of text can cause this element to grow without bounds, larger than
+ the window, and there's no way to navigate it sensibly. In this
+ case, manually resizing the element (desktop only - mobile doesn't
+ offer that) will force it to stay at the selected size even if more
+ content is added to it later.
+
+ - If we DO set a max-height then its growth is bounded but it also
+ cannot manually expanded by the user.
+
+ The lesser of the two evils seems to be to rely on the browser
+ feature that a manual resize of the element will pin its size.
+*/
+}
+
+body.chat #chat-input-line-wrapper > #chat-button-settings{
+ margin: 0 0 0 0.25em;
+ max-width: 2em;
+}
+body.chat #chat-input-line-wrapper > input[type=text],
+body.chat #chat-input-line-wrapper > textarea {
+ flex: 20 1 auto;
+ max-width: revert;
+ min-width: 20em;
+}
+body.chat #chat-input-line-wrapper.compact > input[type=text] {
+ margin: 0 0 0.25em 0/* gap for if/when buttons wrap*/;
+}
+/* Widget holding the file selection control and preview */
+body.chat #chat-input-file-area {
+ display: flex;
+ flex-direction: row;
+ margin: 0;
+}
+body.chat #chat-input-file-area > .file-selection-wrapper {
+ align-self: flex-start;
+ margin-right: 0.5em;
+ flex: 0 1 auto;
+ padding: 0.25em 0.5em;
+ white-space: nowrap;
+}
+body.chat #chat-input-file {
+ border:1px solid rgba(0,0,0,0);/*avoid UI shift during drop-targeting*/
+ border-radius: 0.25em;
+ padding: 0.25em;
+}
+body.chat #chat-input-file > input {
+ flex: 1 0 auto;
+}
+/* Indicator when a drag/drop is in progress */
+body.chat #chat-input-file.dragover {
+ border: 1px dashed green;
+}
+/* Widget holding the details of a selected/dropped file/image. */
+body.chat #chat-drop-details {
+ padding: 0 1em;
+ white-space: pre;
+ font-family: monospace;
+ margin: auto;
+ flex: 0;
+}
+body.chat #chat-drop-details:empty {
+ padding: 0;
+ margin: 0;
+}
+body.chat #chat-drop-details img {
+ max-width: 45%;
+ max-height: 45%;
+}
+body.chat .chat-view {
+ flex: 20 1 auto
+ /*ensure that these grow more than the non-.chat-view elements.
+ Note that setting flex shrink to 0 breaks/disables scrolling!*/;
+ margin-bottom: 0.2em;
+}
+body.chat #chat-config,
+body.chat #chat-search,
+body.chat #chat-preview,
+body.chat #chat-zoom {
+ /* /chat configuration widget */
+ display: flex;
+ flex-direction: column;
+ overflow: auto;
+ padding: 0;
+ margin: 0;
+ align-items: stretch;
+ min-height: 6em;
+}
+body.chat #chat-zoom {
+ justify-content: space-between;
+}
+body.chat #chat-zoom-content {
+ display: flex;
+ overflow: auto;
+}
+body.chat #chat-zoom-content > .message-widget {
+ flex-grow: 1;
+}
+body.chat #chat-zoom-content > .message-widget > .message-widget-content {
+ width: 99%;
+}
+body.chat #chat-zoom-content > .message-widget .toolbar.hide-in-zoom {
+ /* The various Delete buttons misinteract with zoom mode's moving-around
+ of message widgets, so hide them in zoom mode. */
+ position: absolute !important;
+ opacity: 0 !important;
+ pointer-events: none !important;
+ display: none !important;
+}
+body.chat #chat-config #chat-config-options {
+ /* /chat config options go here */
+ flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
+ overflow: auto;
+ align-items: stretch;
+}
+body.chat #chat-config #chat-config-options .menu-entry {
+ display: flex;
+ align-items: center;
+ flex-direction: row-reverse;
+ flex-wrap: nowrap;
+ padding: 1em;
+ flex: 1 1 auto;
+ align-self: stretch;
+}
+body.chat #chat-config #chat-config-options .menu-entry.parent{
+ border-radius: 1em 1em 0 1em;
+ margin-top: 1em;
+}
+body.chat #chat-config #chat-config-options .menu-entry.child {
+ /*padding-left: 2.5em;*/
+ margin-left: 2em;
+}
+body.chat #chat-config #chat-config-options .menu-entry:nth-of-type(even){
+ background-color: rgba(175,175,175,0.15);
+}
+body.chat #chat-config #chat-config-options .menu-entry:nth-of-type(odd){
+ background-color: rgba(175,175,175,0.35);
+}
+body.chat #chat-config #chat-config-options .menu-entry:first-child {
+ /* Config list header */
+ border-radius: 0 0 1em 1em;
+}
+body.chat #chat-config #chat-config-options .menu-entry:first-child .label-wrapper {
+ align-items: start;
+}
+body.chat #chat-config #chat-config-options .menu-entry > .toggle-wrapper {
+ /* Holder for a checkbox, if any */
+ min-width: 1.5rem;
+ margin-right: 1rem;
+}
+body.chat #chat-config #chat-config-options .menu-entry .label-wrapper {
+ /* Wrapper for a LABEL and a .hint element. */
+ display: flex;
+ flex-direction: column;
+ align-self: baseline;
+ flex: 1 1 auto;
+}
+body.chat #chat-config #chat-config-options .menu-entry label {
+ /* Config option label. */
+ font-weight: bold;
+ white-space: initial;
+}
+body.chat #chat-config #chat-config-options .menu-entry label[for] {
+ cursor: pointer;
+}
+body.chat #chat-config #chat-config-options .menu-entry .hint {
+ /* Config menu hint text */
+ font-size: 85%;
+ font-weight: normal;
+ white-space: pre-wrap;
+ display: inline-block;
+ opacity: 0.85;
+}
+body.chat #chat-config #chat-config-options .menu-entry select {
+}
+body.chat #chat-preview #chat-preview-content,
+body.chat #chat-search #chat-search-content {
+ overflow: auto;
+ flex: 1 1 auto;
+ padding: 0.5em;
+ border: 1px dotted;
+}
+
+body.chat #chat-preview #chat-preview-content > * {
+ margin: 0;
+ padding: 0;
+}
+body.chat .chat-view .button-bar {
+ flex: 0 1 auto;
+ display: flex;
+ flex-direction: column;
+}
+body.chat .chat-view .button-bar button {
+ padding: 0.5em;
+ flex: 1 1 auto;
+ margin: 0.25em 0;
+}
+
+body.chat #chat-search .button-bar {
+ flex: 0 1 auto;
+ display: flex;
+ flex-direction: row;
+}
+
+body.chat #chat-user-list-wrapper {
+ /* Safari can't do fieldsets right, so we emulate one. */
+ border-radius: 0.5em;
+ margin: 1em 0 0.2em 0;
+ padding: 0 0.5em;
+ border-style: inset;
+ border-width: 0 1px 1px 1px/*else collides with the LEGEND*/;
+}
+body.chat #chat-user-list-wrapper.collapsed {
+ padding: 0;
+}
+body.chat #chat-user-list-wrapper > .legend {
+ font-weight: initial;
+ padding: 0 0.5em 0 0.5em;
+ position: relative;
+ top: -1.75ex/* place it like a fieldset legend */;
+ cursor: pointer;
+}
+body.chat #chat-user-list-wrapper > .legend > * {
+ vertical-align: middle;
+}
+body.chat #chat-user-list-wrapper > .legend > *:nth-child(2){
+ /* Title label */
+ opacity: 0.6;
+ font-size: 0.8em;
+}
+body.chat #chat-user-list-wrapper.collapsed > .legend > *:nth-child(2)::after {
+ content: " (tap to toggle)";
+}
+body.chat #chat-user-list-wrapper .help-buttonlet {
+ margin: 0;
+}
+body.chat #chat-user-list-wrapper.collapsed #chat-user-list {
+ position: absolute !important;
+ opacity: 0 !important;
+ pointer-events: none !important;
+ display: none !important;
+}
+body.chat #chat-user-list {
+ margin-top: -1.25ex;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ align-items: center;
+}
+body.chat #chat-user-list .chat-user {
+ margin: 0.2em;
+ padding: 0.1em 0.5em 0.2em 0.5em;
+ border-radius: 0.5em;
+ cursor: pointer;
+ text-align: center;
+ white-space: pre;
+}
+body.chat #chat-user-list .timestamp {
+ font-size: 85%;
+ font-family: monospace;
+}
+body.chat #chat-user-list:not(.timestamps) .timestamp {
+ display: none;
+}
+body.chat #chat-user-list .chat-user.selected {
+ font-weight: bold;
+ text-decoration: underline;
+}
+
+body.chat .searchForm {
+ margin-top: 1em;
+}
+body.chat .spacer-widget button {
+ margin-left: 1ex;
+ margin-right: 1ex;
+ display: block;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+body.chat .anim-rotate-360 {
+ animation: rotate-360 750ms linear;
+}
+@keyframes rotate-360 {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
+body.chat .anim-flip-h {
+ animation: flip-h 750ms linear;
+}
+@keyframes flip-h{
+ from { transform: rotateY(0deg); }
+ to { transform: rotateY(360deg); }
+}
+body.chat .anim-flip-v {
+ animation: flip-v 750ms linear;
+}
+@keyframes flip-v{
+ from { transform: rotateX(0deg); }
+ to { transform: rotateX(360deg); }
+}
+body.chat .anim-fade-in {
+ animation: fade-in 750ms linear;
+}
+body.chat .anim-fade-in-fast {
+ animation: fade-in 350ms linear;
+}
+@keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+body.chat .anim-fade-out-fast {
+ animation: fade-out 250ms linear;
+}
+@keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+