diff --git a/.editorconfig b/.editorconfig index 2322ac0d2..7f32cfe8a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,5 +3,5 @@ root = true [*.scss] indent_size = 2 -[{**/login.scss,**/tangerine/**/*.scss,**/gts/**/*.scss}] +[{**/login.scss,**/tangerine/**/*.scss,**/gts/**/*.scss,app/css/**/*.css}] indent_size = 4 \ No newline at end of file diff --git a/app/css/core/Manrope[wght].woff2 b/app/css/core/Manrope[wght].woff2 new file mode 100644 index 000000000..4d677aac3 Binary files /dev/null and b/app/css/core/Manrope[wght].woff2 differ diff --git a/app/css/core/_core.css b/app/css/core/_core.css index 0314fa8f8..f95c2d0d3 100644 --- a/app/css/core/_core.css +++ b/app/css/core/_core.css @@ -1,3 +1,101 @@ -body { - border: 20px solid pink; +@import "colors"; +@import "columns"; +@import "scrollbars"; +@import "sizes"; + +@import "multiple-columns"; + +@import "components/drawer"; +@import "components/search"; +@import "components/column"; +@import "components/notification-filter-bar"; +@import "components/status/status"; + +@import "modules/feed"; +@import "modules/status"; + +@font-face { + font-family: "Manrope"; + src: url("Manrope[wght].woff2") format("woff2-variations"); +} + +* { + box-sizing: border-box; + + &::before, + &::after { + box-sizing: inherit; + } +} + +body { + margin: 0; + font-family: "Manrope", ui-rounded, sans-serif; + color: var(--color-fg); + line-height: 1.5; + text-rendering: optimizelegibility; + background: var(--color-bg); +} + +.ui { + width: 100%; + height: 100%; +} + +button { + display: block; + padding: 6px; + border: 1px solid transparent; + color: var(--color-content-fg); + font: inherit; + line-height: inherit; + border-radius: 6px; + background-color: var(--color-content-secondary-bg); + + &:is(:active, :focus, :hover) { + color: var(--color-accent); + background-color: var(--color-accent-bg); + } + + &:focus-visible { + outline: solid 2px var(--color-accent-focus); + outline-offset: 2px; + } +} + +button:has(svg) { + display: flex; + align-items: center; +} + +img { + max-width: 100px; +} + +svg.gts-icon { + display: block; + width: var(--size-icon); + height: var(--size-icon); +} + +.compose-form__buttons { + display: flex; + gap: 5px; +} + +.emojione { + --size: min(1em, 20px); + + width: var(--size); + height: var(--size); +} + +.ui__header, +.search__popout, +.drawer__inner__mastodon { + display: none; +} + +.upload-area { + position: fixed; } diff --git a/app/css/core/colors.css b/app/css/core/colors.css new file mode 100644 index 000000000..66b77f917 --- /dev/null +++ b/app/css/core/colors.css @@ -0,0 +1,39 @@ +/* 🎨 Colors */ +:root { + color-scheme: light dark; + + --color-bg: #f2eff5; + --gradient-bg: linear-gradient(90deg, var(--color-bg), var(--color-bg)); + --color-fg: #2a2d37; + --color-fg-muted: #888494; + --color-secondary-bg: #e8e4f2; + --color-secondary-separator: #dfdbed; + + --color-content-bg: #ffffff; + --color-content-fg: #444a5a; + --color-content-fg-bold: #000000; + --color-content-fg-muted: color-mix( + in srgb, + var(--color-content-fg), + var(--color-content-bg) 40% + ); + --color-content-secondary-bg: #f5f4f9; + --color-content-secondary-separator: rgba(223, 219, 237, 0.4); + --color-content-bg-focus: #fffcfa; + + --color-accent: #5758ff; + --color-accent-focus: #563acc; + --color-accent-lines: rgba(99, 100, 255, 0.12); + --color-accent-bg: #e5ddf6; + --color-accent-fg: #ffffff; + + --color-lines: #e1dde4; + --color-lines-translucent: rgba(0, 0, 0, 0.15); + + --color-confirm: #79bd9a; + --color-confirm-bg: rgba(121, 189, 154, 0.3); + --color-confirm-fg: #4e8a6b; + + --color-reject: #df405a; + --color-reject-bg: rgba(223, 64, 90, 0.3); +} diff --git a/app/css/core/columns.css b/app/css/core/columns.css new file mode 100644 index 000000000..f7f6bf839 --- /dev/null +++ b/app/css/core/columns.css @@ -0,0 +1,24 @@ +.columns-area { + display: flex; + padding: var(--size-layout-gap); + column-gap: var(--size-layout-gap); +} + +.column { + display: flex; + flex-direction: column; + flex-shrink: 0; + overflow: hidden; + border: 1px solid var(--color-lines); + border-radius: var(--size-layout-radius); + background: var(--color-content-bg); + + .layout-multiple-columns & { + width: 400px; + } +} + +.column > .scrollable { + max-height: 100%; + overflow-y: scroll; +} diff --git a/app/css/core/components/column.css b/app/css/core/components/column.css new file mode 100644 index 000000000..470370a29 --- /dev/null +++ b/app/css/core/components/column.css @@ -0,0 +1 @@ +@import "components/column/column-header"; diff --git a/app/css/core/components/column/column-header.css b/app/css/core/components/column/column-header.css new file mode 100644 index 000000000..ce93a1a3e --- /dev/null +++ b/app/css/core/components/column/column-header.css @@ -0,0 +1,32 @@ +.column-header { + display: flex; + margin: 0; + font-size: max(16px, 1rem); + font-weight: bold; + backdrop-filter: blur(20px); +} + +.column-header > button { + display: flex; + align-items: center; + flex-grow: 1; + gap: 15px; + padding-inline-start: 15px; + color: var(--color-content-fg); + background: var(--color-content-bg); + + &:hover { + color: inherit; + background-color: transparent; + } +} + +.column-header__buttons { + display: flex; + gap: var(--size-ui-gap); + padding: 5px; + + > button { + background-color: transparent; + } +} diff --git a/app/css/core/components/drawer.css b/app/css/core/components/drawer.css new file mode 100644 index 000000000..534115235 --- /dev/null +++ b/app/css/core/components/drawer.css @@ -0,0 +1,33 @@ +.drawer { + display: flex; + flex-direction: column; + row-gap: var(--size-layout-gap); + min-width: 300px; + max-width: 400px; +} + +.drawer__header { + display: flex; + column-gap: var(--size-ui-gap); + padding: 5px; + border: 1px solid var(--color-lines); + border-radius: var(--size-layout-radius); + background: var(--color-content-bg); +} + +.drawer__header a { + --size-icon: 24px; + + display: flex; + align-items: center; + flex-grow: 1; + justify-content: center; + padding: 8px; + border-radius: var(--size-ui-radius); + color: inherit; + transition: all 0.3s; + + &:is(:active, :focus, :hover) { + background-color: var(--color-accent-bg); + } +} diff --git a/app/css/core/components/notification-filter-bar.css b/app/css/core/components/notification-filter-bar.css new file mode 100644 index 000000000..ac57e55a6 --- /dev/null +++ b/app/css/core/components/notification-filter-bar.css @@ -0,0 +1,66 @@ +.notification__filter-bar { + display: flex; +} + +.notification__filter-bar { + display: flex; + gap: 8px; + margin-inline: -1px; + padding: 6px; + border: 1px solid var(--color-accent-lines); + background: var(--color-accent-bg); + + a, + button { + display: flex; + align-items: center; + justify-content: center; + flex-grow: 1; + padding: 8px 6px; + min-width: 32px; + border: 0; + border-radius: var(--size-ui-radius); + color: var(--color-content-fg); + line-height: 20px; + text-decoration: none; + background: transparent; + transition: all 0.3s; + + &:focus-visible, + &:hover { + background: var(--color-accent-lines); + } + } + + a.active, + button.active { + color: var(--color-content-fg); + background: var(--color-content-bg); + + /* &:focus-visible, + &:hover { + background: var(--color-notifications-bg--hover); + } */ + } + + a:not(:first-child), + button:not(:first-child) { + position: relative; + + &::before { + position: absolute; + top: 6px; + right: calc(100% + 3px); + width: 2px; + height: 24px; + background: var(--color-accent-lines); + content: ""; + } + } + + svg.gts-icon { + --size: 20px; + + display: block; + } +} diff --git a/app/css/core/components/search.css b/app/css/core/components/search.css new file mode 100644 index 000000000..848a9c6c5 --- /dev/null +++ b/app/css/core/components/search.css @@ -0,0 +1,50 @@ +/* 🔍 Search */ +.search { + position: relative; + display: flex; +} + +.search > input { + display: block; + padding: 12px 40px; + width: 100%; + border: 1px solid var(--color-accent-lines); + border-radius: var(--size-layout-radius); + color: var(--color-content-fg); + font: inherit; + font-weight: 500; + line-height: 20px; + background: var(--color-accent-bg); + transition: 0.2s; + transition-property: border-color, background-color, outline; + + &::placeholder { + font-weight: 500; + color: var(--color-accent); + } + + &:focus::placeholder { + color: var(--color-content-fg); + opacity: 0.4; + } +} + +.search > .gts-icon { + --size-icon: 20px; + + position: absolute; + top: 13px; + left: 13px; +} + +.search > button { + position: absolute; + top: 7px; + right: 7px; + padding: 6px; + background: transparent; + + &:not(.active) { + display: none; + } +} diff --git a/app/css/core/components/status/_status.css b/app/css/core/components/status/_status.css new file mode 100644 index 000000000..34b4a1cbf --- /dev/null +++ b/app/css/core/components/status/_status.css @@ -0,0 +1,10 @@ +/* 🚥 Status */ +@import "components/status/account"; +@import "components/status/action-bar"; +@import "components/status/avatar"; +@import "components/status/container"; +@import "components/status/content"; +@import "components/status/display-name"; +@import "components/status/icons"; +@import "components/status/info"; +@import "components/status/prepend"; diff --git a/app/css/core/components/status/account.css b/app/css/core/components/status/account.css new file mode 100644 index 000000000..05de83b63 --- /dev/null +++ b/app/css/core/components/status/account.css @@ -0,0 +1,8 @@ +/* 🚥 Status: Account */ +.status__info__account { + display: grid; + grid-template-columns: auto 1fr; + gap: 10px; + overflow: hidden; + text-overflow: clip; +} diff --git a/app/css/core/components/status/action-bar.css b/app/css/core/components/status/action-bar.css new file mode 100644 index 000000000..f2afcae08 --- /dev/null +++ b/app/css/core/components/status/action-bar.css @@ -0,0 +1,16 @@ +/* 🚥 Status: Action bar */ +.status__action-bar { + display: flex; + align-items: center; + gap: 5px; + + button { + color: var(--color-accent); + background-color: transparent; + } +} + +.status__relative-time { + margin-left: auto; + color: var(--color-content-fg); +} diff --git a/app/css/core/components/status/avatar.css b/app/css/core/components/status/avatar.css new file mode 100644 index 000000000..97d71cc00 --- /dev/null +++ b/app/css/core/components/status/avatar.css @@ -0,0 +1,38 @@ +/* 🚥 Status: Avatar */ +.status__avatar { +} + +.status { + .account__avatar { + border-radius: var(--size-ui-radius); + } + + .account__avatar-overlay { + position: relative; + padding-block-end: 10px; + padding-inline-end: 10px; + } + + .account__avatar-overlay-base, + .account__avatar-overlay-overlay { + display: block; + width: var(--size-avatar); + height: var(--size-avatar); + border-radius: var(--size-ui-radius); + background-position: center; + background-size: cover; + background-repeat: no-repeat; + } + + .account__avatar-overlay-base { + --size-avatar: 36px; + } + + .account__avatar-overlay-overlay { + --size-avatar: 24px; + + position: absolute; + bottom: 0; + right: 0; + } +} diff --git a/app/css/core/components/status/container.css b/app/css/core/components/status/container.css new file mode 100644 index 000000000..5c6fc5ab9 --- /dev/null +++ b/app/css/core/components/status/container.css @@ -0,0 +1,13 @@ +.status { + --color-status-bg: var(--color-content-bg); + + display: flex; + flex-direction: column; + row-gap: var(--size-layout-gap); + padding: 15px; + text-wrap: pretty; + + a { + word-break: break-word; + } +} diff --git a/app/css/core/components/status/content.css b/app/css/core/components/status/content.css new file mode 100644 index 000000000..810d1efd3 --- /dev/null +++ b/app/css/core/components/status/content.css @@ -0,0 +1,37 @@ +/* 🚥 Status: Content */ +.status__content__text { + > :first-child { + margin-block-start: 0; + } + + > :last-child { + margin-block-end: 0; + } +} + +.status__content__text a { + color: var(--color-accent); + text-decoration-line: underline; + text-decoration-color: var(--color-accent-bg); + text-decoration-thickness: 2px; + text-underline-offset: 2px; + + &:hover { + text-decoration-color: var(--color-accent); + } +} + +.status__content__text a.mention { + text-decoration: none; + + span { + text-decoration-line: underline; + text-decoration-color: var(--color-accent-bg); + text-decoration-thickness: 2px; + text-underline-offset: 2px; + } + + &:is(:active, :focus, :hover) span { + text-decoration-color: var(--color-accent); + } +} diff --git a/app/css/core/components/status/display-name.css b/app/css/core/components/status/display-name.css new file mode 100644 index 000000000..879034655 --- /dev/null +++ b/app/css/core/components/status/display-name.css @@ -0,0 +1,35 @@ +/* 🚥 Status: Display name */ +.status__display-name { + align-self: start; + justify-self: start; + color: var(--color-content-fg); + font-size: 15px; + line-height: 1.2; + text-decoration: none; + overflow: hidden; + + .display-name { + display: block; + max-width: 100%; + overflow: hidden; + font-weight: 700; + text-overflow: clip; + } + + .display-name__html { + font-weight: 700; + } + + .display-name__account { + color: var(--color-secondary-fg); + font-weight: 400; + word-break: normal; + } + + &:hover .display-name__html { + text-decoration-line: underline; + text-decoration-color: currentColor; + text-decoration-thickness: 2px; + text-underline-offset: 2px; + } +} diff --git a/app/css/core/components/status/icons.css b/app/css/core/components/status/icons.css new file mode 100644 index 000000000..e9a9b19a0 --- /dev/null +++ b/app/css/core/components/status/icons.css @@ -0,0 +1,46 @@ +/* 🚥 Status: Icons */ +.status__info__icons { + --size-icon: 18px; + + position: relative; + display: flex; + gap: 5px; + align-items: start; + color: var(--color-content-fg); + + .text-icon { + font-size: 12px; + line-height: 20px; + } + + &::before { + position: absolute; + top: 0; + right: calc(100% + 5px); + width: 20px; + height: 100%; + content: ""; + background: linear-gradient(90deg, transparent, var(--color-status-bg)); + transition: all 0.2s; + } +} + +.status__info__icons button.icon-button { + display: block; + margin: -3px; + padding: 2px; + color: inherit; + background-color: transparent; + + svg.gts-icon { + transition: transform ease-in-out 0.2s; + } + + &.active svg.gts-icon { + transform: rotate(-180deg); + } + + &:hover { + color: var(--color-accent-hover); + } +} diff --git a/app/css/core/components/status/info.css b/app/css/core/components/status/info.css new file mode 100644 index 000000000..52a13843e --- /dev/null +++ b/app/css/core/components/status/info.css @@ -0,0 +1,10 @@ +/* 🚥 Status: Info */ +.status__info { + display: grid; + gap: 5px; + grid-template-columns: 1fr auto; + + .notification__message { + grid-column: 1/-1; + } +} diff --git a/app/css/core/components/status/prepend.css b/app/css/core/components/status/prepend.css new file mode 100644 index 000000000..894397260 --- /dev/null +++ b/app/css/core/components/status/prepend.css @@ -0,0 +1,43 @@ +/* 🚥 Status: Prepend */ +.status__prepend { + display: inline-flex; + align-items: center; + align-self: start; + gap: 5px; + padding: 5px 10px; + border: 1px solid var(--color-accent-lines); + border-radius: 50px; + color: var(--color-content-fg); + font-size: 13px; + font-weight: 500; + background-color: var(--color-content-secondary-bg); + + &:focus-within { + outline: 2px solid var(--color-accent-focus); + outline-offset: 3px; + } +} + +.status__prepend-icon { + --size: 18px; + + display: block; + width: var(--size); + height: var(--size); +} + +.status__prepend-display-name { + color: inherit; + text-decoration: underline; + text-decoration-color: var(--color-accent-muted-fg); + + &:hover { + color: inherit; + text-decoration-thickness: 2px; + } + + &:focus-visible { + color: var(--color-accent-focus); + outline-color: transparent; + } +} diff --git a/app/css/core/modules/feed.css b/app/css/core/modules/feed.css new file mode 100644 index 000000000..591464f55 --- /dev/null +++ b/app/css/core/modules/feed.css @@ -0,0 +1,8 @@ +[role="feed"].item-list { +} + +[role="feed"].item-list > article { + &:not(:last-child) { + border-bottom: 1px solid var(--color-lines); + } +} diff --git a/app/css/core/modules/status.css b/app/css/core/modules/status.css new file mode 100644 index 000000000..e69de29bb diff --git a/app/css/core/multiple-columns.css b/app/css/core/multiple-columns.css new file mode 100644 index 000000000..a5e05c89e --- /dev/null +++ b/app/css/core/multiple-columns.css @@ -0,0 +1,17 @@ +body.layout-multiple-columns { + position: absolute; + width: 100%; + height: 100%; + padding-bottom: env(safe-area-inset-bottom); + padding-left: env(safe-area-inset-left); + padding-right: env(safe-area-inset-right); + + :is(.app-holder, .app-holder > div, .columns-area) { + height: 100%; + } + + .ui { + display: flex; + flex: 0 0 auto; + } +} diff --git a/app/css/core/scrollbars.css b/app/css/core/scrollbars.css new file mode 100644 index 000000000..b6ebf1ae5 --- /dev/null +++ b/app/css/core/scrollbars.css @@ -0,0 +1,28 @@ +/* 🖱️ Scrollbars */ +:root:has(.app-body) *::-webkit-scrollbar-track { + background-color: var(--color-bg); + padding: 2px; +} +:root:has(.app-body) *::-webkit-scrollbar-thumb { + background-color: var(--color-accent); + border-radius: 8px; + opacity: 0.4; + box-shadow: none; +} +:root:has(.app-body) *::-webkit-scrollbar-track:hover { + background-color: var(--color-bg); +} +:root:has(.app-body) *::-webkit-scrollbar-thumb:hover { + background-color: var(--color-accent); + opacity: 0.7; +} +@media screen and (max-width: 1175px) { + :root:has(.app-body) *::-webkit-scrollbar { + display: none; + } +} +:root, +* { + scrollbar-color: var(--color-accent) var(--color-bg); + scrollbar-width: thin; +} diff --git a/app/css/core/sizes.css b/app/css/core/sizes.css new file mode 100644 index 000000000..a3d1b0f5d --- /dev/null +++ b/app/css/core/sizes.css @@ -0,0 +1,9 @@ +/* 📏 Sizes */ +:root { + --size-layout-gap: 10px; + --size-layout-radius: 8px; + --size-ui-gap: 5px; + --size-ui-radius: 6px; + + --size-icon: max(1em, 20px); +} diff --git a/public/index.html b/public/index.html index d935cf7c8..2eb599214 100644 --- a/public/index.html +++ b/public/index.html @@ -19,10 +19,10 @@ - + - +